Merge pull request 'Make it possible to open menu on iOS mobile devices' (#897) from menu into main
Reviewed-on: https://git.joinplu.me/Plume/Plume/pulls/897
This commit is contained in:
commit
a7e45bee11
10
.cargo/config.toml
Normal file
10
.cargo/config.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[target.wasm32-unknown-unknown]
|
||||||
|
# required for clippy
|
||||||
|
rustflags = [
|
||||||
|
"--cfg", "web_sys_unstable_apis",
|
||||||
|
]
|
||||||
|
|
||||||
|
[target.x86_64-unknown-linux-gnu]
|
||||||
|
rustflags = [
|
||||||
|
"--cfg", "web_sys_unstable_apis",
|
||||||
|
]
|
@ -10,7 +10,7 @@ executors:
|
|||||||
type: boolean
|
type: boolean
|
||||||
default: false
|
default: false
|
||||||
docker:
|
docker:
|
||||||
- image: plumeorg/plume-buildenv:v0.3.0
|
- image: plumeorg/plume-buildenv:v0.4.0
|
||||||
- image: <<#parameters.postgres>>circleci/postgres:9.6-alpine<</parameters.postgres>><<^parameters.postgres>>alpine:latest<</parameters.postgres>>
|
- image: <<#parameters.postgres>>circleci/postgres:9.6-alpine<</parameters.postgres>><<^parameters.postgres>>alpine:latest<</parameters.postgres>>
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
@ -168,7 +168,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- restore_env:
|
- restore_env:
|
||||||
cache: <<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
|
cache: <<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
|
||||||
- run: cargo web deploy -p plume-front
|
- run: wasm-pack build --target web --release plume-front
|
||||||
- run_with_coverage:
|
- run_with_coverage:
|
||||||
cmd: |
|
cmd: |
|
||||||
cmd="cargo install --debug --no-default-features --features="${FEATURES}",test --force --path . -j"
|
cmd="cargo install --debug --no-default-features --features="${FEATURES}",test --force --path . -j"
|
||||||
@ -203,7 +203,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- restore_env:
|
- restore_env:
|
||||||
cache: release-<<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
|
cache: release-<<#parameters.postgres>>postgres<</ parameters.postgres>><<^parameters.postgres>>sqlite<</parameters.postgres>>
|
||||||
- run: cargo web deploy -p plume-front --release
|
- run: wasm-pack build --target web --release plume-front
|
||||||
- build:
|
- build:
|
||||||
package: plume
|
package: plume
|
||||||
release: true
|
release: true
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM debian:buster-20201117
|
FROM debian:buster-20210208
|
||||||
ENV PATH="/root/.cargo/bin:${PATH}"
|
ENV PATH="/root/.cargo/bin:${PATH}"
|
||||||
|
|
||||||
#install native/circleci/build dependancies
|
#install native/circleci/build dependancies
|
||||||
@ -16,7 +16,7 @@ RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2021-0
|
|||||||
rustup component add rust-std --target wasm32-unknown-unknown
|
rustup component add rust-std --target wasm32-unknown-unknown
|
||||||
|
|
||||||
#compile some deps
|
#compile some deps
|
||||||
RUN cargo install cargo-web &&\
|
RUN cargo install wasm-pack &&\
|
||||||
cargo install grcov &&\
|
cargo install grcov &&\
|
||||||
strip /root/.cargo/bin/* &&\
|
strip /root/.cargo/bin/* &&\
|
||||||
rm -fr ~/.cargo/registry
|
rm -fr ~/.cargo/registry
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Percent-encode URI for remote_interact (#866, #857)
|
- Percent-encode URI for remote_interact (#866, #857)
|
||||||
- Menu animation not opening on iOS (#876)
|
- Menu animation not opening on iOS (#876, #897)
|
||||||
|
|
||||||
## [[0.6.0]] - 2020-12-29
|
## [[0.6.0]] - 2020-12-29
|
||||||
|
|
||||||
|
230
Cargo.lock
generated
230
Cargo.lock
generated
@ -9,7 +9,7 @@ dependencies = [
|
|||||||
"activitystreams-derive",
|
"activitystreams-derive",
|
||||||
"activitystreams-traits",
|
"activitystreams-traits",
|
||||||
"activitystreams-types",
|
"activitystreams-types",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
@ -32,7 +32,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "670ef03168e704b0cae242e7a5d8b40506772b339687e01a3496fc4afe2e8542"
|
checksum = "670ef03168e704b0cae242e7a5d8b40506772b339687e01a3496fc4afe2e8542"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"failure",
|
"failure",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ dependencies = [
|
|||||||
"activitystreams-traits",
|
"activitystreams-traits",
|
||||||
"chrono",
|
"chrono",
|
||||||
"mime 0.3.16",
|
"mime 0.3.16",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
@ -209,7 +209,7 @@ checksum = "8d3a45e77e34375a7923b1e8febb049bb011f064714a8e17a1a616fef01da13d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -296,12 +296,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base-x"
|
|
||||||
version = "0.2.8"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.9.3"
|
version = "0.9.3"
|
||||||
@ -353,7 +347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -526,7 +520,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits 0.2.14",
|
"num-traits 0.2.14",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"time",
|
"time",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
@ -573,13 +567,23 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
"nom 5.1.2",
|
"nom 5.1.2",
|
||||||
"rust-ini",
|
"rust-ini",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde-hjson",
|
"serde-hjson",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"toml 0.5.8",
|
"toml 0.5.8",
|
||||||
"yaml-rust",
|
"yaml-rust",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console_error_panic_hook"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-random"
|
name = "const-random"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
@ -654,7 +658,7 @@ dependencies = [
|
|||||||
"idna 0.1.5",
|
"idna 0.1.5",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"publicsuffix",
|
"publicsuffix",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"time",
|
"time",
|
||||||
"try_from",
|
"try_from",
|
||||||
@ -966,7 +970,7 @@ checksum = "45f5098f628d02a7a0f68ddba586fb61e80edec3bdc1be3b921f4ceec60858d3"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -988,12 +992,6 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "discard"
|
|
||||||
version = "1.0.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dotenv"
|
name = "dotenv"
|
||||||
version = "0.14.1"
|
version = "0.14.1"
|
||||||
@ -1161,7 +1159,7 @@ checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -1370,7 +1368,7 @@ dependencies = [
|
|||||||
"proc-macro-hack 0.5.19",
|
"proc-macro-hack 0.5.19",
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1929,9 +1927,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.46"
|
version = "0.3.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf3d7383929f7c9c7c2d0fa596f325832df98c3704f2c60553080f7127a58175"
|
checksum = "5cfb73131c35423a367daf8cbd24100af0d077668c8c2943f0e7dd775fef0f65"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
@ -2012,7 +2010,7 @@ dependencies = [
|
|||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"nom 4.2.3",
|
"nom 4.2.3",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
@ -2079,7 +2077,7 @@ dependencies = [
|
|||||||
"lindera-dictionary",
|
"lindera-dictionary",
|
||||||
"lindera-ipadic",
|
"lindera-ipadic",
|
||||||
"lindera-ipadic-builder",
|
"lindera-ipadic-builder",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2092,7 +2090,7 @@ dependencies = [
|
|||||||
"bincode",
|
"bincode",
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
"encoding",
|
"encoding",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"yada",
|
"yada",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2225,7 +2223,7 @@ dependencies = [
|
|||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"phf",
|
"phf",
|
||||||
"phf_codegen",
|
"phf_codegen",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"string_cache",
|
"string_cache",
|
||||||
@ -2312,7 +2310,7 @@ dependencies = [
|
|||||||
"migrations_internals",
|
"migrations_internals",
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2860,7 +2858,7 @@ checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2871,7 +2869,7 @@ checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2908,7 +2906,7 @@ dependencies = [
|
|||||||
"chrono",
|
"chrono",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"line-wrap",
|
"line-wrap",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"xml-rs",
|
"xml-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2945,7 +2943,7 @@ dependencies = [
|
|||||||
"rsass",
|
"rsass",
|
||||||
"ructe",
|
"ructe",
|
||||||
"scheduled-thread-pool",
|
"scheduled-thread-pool",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shrinkwraprs 0.2.3",
|
"shrinkwraprs 0.2.3",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -2959,7 +2957,7 @@ dependencies = [
|
|||||||
name = "plume-api"
|
name = "plume-api"
|
||||||
version = "0.6.1-dev"
|
version = "0.6.1-dev"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -2992,7 +2990,7 @@ dependencies = [
|
|||||||
"regex-syntax 0.6.21",
|
"regex-syntax 0.6.21",
|
||||||
"reqwest 0.9.24",
|
"reqwest 0.9.24",
|
||||||
"rocket",
|
"rocket",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shrinkwraprs 0.3.0",
|
"shrinkwraprs 0.3.0",
|
||||||
@ -3005,14 +3003,17 @@ dependencies = [
|
|||||||
name = "plume-front"
|
name = "plume-front"
|
||||||
version = "0.6.1-dev"
|
version = "0.6.1-dev"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"console_error_panic_hook",
|
||||||
"gettext",
|
"gettext",
|
||||||
"gettext-macros",
|
"gettext-macros",
|
||||||
"gettext-utils",
|
"gettext-utils",
|
||||||
|
"js-sys",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"stdweb",
|
"wasm-bindgen",
|
||||||
"stdweb-internal-runtime",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3054,7 +3055,7 @@ dependencies = [
|
|||||||
"rocket",
|
"rocket",
|
||||||
"rocket_i18n",
|
"rocket_i18n",
|
||||||
"scheduled-thread-pool",
|
"scheduled-thread-pool",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"shrinkwraprs 0.2.3",
|
"shrinkwraprs 0.2.3",
|
||||||
@ -3530,7 +3531,7 @@ dependencies = [
|
|||||||
"mime 0.3.16",
|
"mime 0.3.16",
|
||||||
"mime_guess 2.0.3",
|
"mime_guess 2.0.3",
|
||||||
"native-tls",
|
"native-tls",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded 0.5.5",
|
"serde_urlencoded 0.5.5",
|
||||||
"socks",
|
"socks",
|
||||||
@ -3569,7 +3570,7 @@ dependencies = [
|
|||||||
"native-tls",
|
"native-tls",
|
||||||
"percent-encoding 2.1.0",
|
"percent-encoding 2.1.0",
|
||||||
"pin-project-lite 0.2.0",
|
"pin-project-lite 0.2.0",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_urlencoded 0.7.0",
|
"serde_urlencoded 0.7.0",
|
||||||
"tokio 0.2.24",
|
"tokio 0.2.24",
|
||||||
"tokio-tls",
|
"tokio-tls",
|
||||||
@ -3669,7 +3670,7 @@ dependencies = [
|
|||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"notify",
|
"notify",
|
||||||
"rocket",
|
"rocket",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3681,7 +3682,7 @@ dependencies = [
|
|||||||
"data-encoding",
|
"data-encoding",
|
||||||
"ring",
|
"ring",
|
||||||
"rocket",
|
"rocket",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3769,7 +3770,7 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
|
checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3880,9 +3881,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.118"
|
version = "1.0.123"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
|
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
@ -3902,13 +3903,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.118"
|
version = "1.0.123"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
|
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3919,7 +3920,7 @@ checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3939,7 +3940,7 @@ checksum = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"dtoa",
|
"dtoa",
|
||||||
"itoa",
|
"itoa",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"url 1.7.2",
|
"url 1.7.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3952,15 +3953,9 @@ dependencies = [
|
|||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sha1"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@ -3992,7 +3987,7 @@ dependencies = [
|
|||||||
"itertools 0.8.2",
|
"itertools 0.8.2",
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4005,7 +4000,7 @@ dependencies = [
|
|||||||
"itertools 0.8.2",
|
"itertools 0.8.2",
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4119,57 +4114,6 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stdweb"
|
|
||||||
version = "0.4.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a68c0ce28cf7400ed022e18da3c4591e14e1df02c70e93573cc59921b3923aeb"
|
|
||||||
dependencies = [
|
|
||||||
"discard",
|
|
||||||
"rustc_version",
|
|
||||||
"serde 1.0.118",
|
|
||||||
"serde_json",
|
|
||||||
"stdweb-derive",
|
|
||||||
"stdweb-internal-macros",
|
|
||||||
"stdweb-internal-runtime",
|
|
||||||
"wasm-bindgen",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stdweb-derive"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0e21ebd9179de08f2300a65454268a17ea3de204627458588c84319c4def3930"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2 0.4.30",
|
|
||||||
"quote 0.6.13",
|
|
||||||
"serde 1.0.118",
|
|
||||||
"serde_derive",
|
|
||||||
"syn 0.15.44",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stdweb-internal-macros"
|
|
||||||
version = "0.2.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e68f7d08b76979a43e93fe043b66d2626e35d41d68b0b85519202c6dd8ac59fa"
|
|
||||||
dependencies = [
|
|
||||||
"base-x",
|
|
||||||
"proc-macro2 0.4.30",
|
|
||||||
"quote 0.6.13",
|
|
||||||
"serde 1.0.118",
|
|
||||||
"serde_derive",
|
|
||||||
"serde_json",
|
|
||||||
"sha1",
|
|
||||||
"syn 0.15.44",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "stdweb-internal-runtime"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d52317523542cc0af5b7e31017ad0f7d1e78da50455e38d5657cd17754f617da"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "string"
|
name = "string"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -4189,7 +4133,7 @@ dependencies = [
|
|||||||
"new_debug_unreachable",
|
"new_debug_unreachable",
|
||||||
"phf_shared",
|
"phf_shared",
|
||||||
"precomputed-hash",
|
"precomputed-hash",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"string_cache_codegen",
|
"string_cache_codegen",
|
||||||
"string_cache_shared",
|
"string_cache_shared",
|
||||||
]
|
]
|
||||||
@ -4288,9 +4232,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.56"
|
version = "1.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72"
|
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
@ -4314,7 +4258,7 @@ checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
"unicode-xid 0.2.1",
|
"unicode-xid 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4333,7 +4277,7 @@ dependencies = [
|
|||||||
"onig",
|
"onig",
|
||||||
"plist",
|
"plist",
|
||||||
"regex-syntax 0.6.21",
|
"regex-syntax 0.6.21",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
@ -4373,7 +4317,7 @@ dependencies = [
|
|||||||
"rayon",
|
"rayon",
|
||||||
"regex",
|
"regex",
|
||||||
"rust-stemmers",
|
"rust-stemmers",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"smallvec 1.5.1",
|
"smallvec 1.5.1",
|
||||||
"snap",
|
"snap",
|
||||||
@ -4478,7 +4422,7 @@ checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4645,7 +4589,7 @@ checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4793,7 +4737,7 @@ version = "0.4.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
checksum = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4802,7 +4746,7 @@ version = "0.5.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4832,7 +4776,7 @@ checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -4871,7 +4815,7 @@ version = "0.1.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
|
checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -4886,7 +4830,7 @@ dependencies = [
|
|||||||
"lazy_static",
|
"lazy_static",
|
||||||
"matchers",
|
"matchers",
|
||||||
"regex",
|
"regex",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec 1.5.1",
|
"smallvec 1.5.1",
|
||||||
@ -5072,7 +5016,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
|
checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5084,7 +5028,7 @@ dependencies = [
|
|||||||
"idna 0.1.5",
|
"idna 0.1.5",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"regex",
|
"regex",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"url 1.7.2",
|
"url 1.7.2",
|
||||||
@ -5181,28 +5125,28 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3cd364751395ca0f68cafb17666eee36b63077fb5ecd972bbcd74c90c4bf736e"
|
checksum = "55c0f7123de74f0dab9b7d00fd614e7b19349cd1e2f5252bbe9b1754b59433be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1114f89ab1f4106e5b55e688b828c0ab0ea593a1ea7c094b141b14cbaaec2d62"
|
checksum = "7bc45447f0d4573f3d65720f636bbcc3dd6ce920ed704670118650bcd47764c7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -5220,9 +5164,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a6ac8995ead1f084a8dea1e65f194d0973800c7f571f6edd70adf06ecf77084"
|
checksum = "3b8853882eef39593ad4174dd26fc9865a64e84026d223f63bb2c42affcbba2c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@ -5230,28 +5174,28 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5a48c72f299d80557c7c62e37e7225369ecc0c963964059509fbafe917c7549"
|
checksum = "4133b5e7f2a531fa413b3a1695e925038a05a71cf67e87dafa295cb645a01385"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.24",
|
"proc-macro2 1.0.24",
|
||||||
"quote 1.0.8",
|
"quote 1.0.8",
|
||||||
"syn 1.0.56",
|
"syn 1.0.60",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.69"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7e7811dd7f9398f14cc76efd356f98f03aa30419dea46aa810d71e819fc97158"
|
checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.46"
|
version = "0.3.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "222b1ef9334f92a21d3fb53dc3fd80f30836959a90f9274a626d7e06315ba3c3"
|
checksum = "c40dc691fc48003eba817c38da7113c15698142da971298003cac3ef175680b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@ -5264,7 +5208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ec24b1b0700d4b466d280228ed0f62274eedeaa80206820f071fdc8ed787b664"
|
checksum = "ec24b1b0700d4b466d280228ed0f62274eedeaa80206820f071fdc8ed787b664"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"reqwest 0.9.24",
|
"reqwest 0.9.24",
|
||||||
"serde 1.0.118",
|
"serde 1.0.123",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ RUN chmod a+x ./wasm-deps.sh && sleep 1 && ./wasm-deps.sh
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY Cargo.toml Cargo.lock rust-toolchain ./
|
COPY Cargo.toml Cargo.lock rust-toolchain ./
|
||||||
RUN cargo install cargo-web
|
RUN cargo install wasm-pack
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ RUN chmod a+x ./wasm-deps.sh && sleep 1 && ./wasm-deps.sh
|
|||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY Cargo.toml Cargo.lock rust-toolchain ./
|
COPY Cargo.toml Cargo.lock rust-toolchain ./
|
||||||
RUN cargo install diesel_cli --no-default-features --features postgres --version '=1.3.0'
|
RUN cargo install diesel_cli --no-default-features --features postgres --version '=1.3.0'
|
||||||
RUN cargo install cargo-web
|
RUN cargo install wasm-pack
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ body > header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body > header:focus-within #content, #content.show {
|
body > header:focus-within #content, .show + #content {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -216,9 +216,7 @@ body > header {
|
|||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, 0);
|
|
||||||
transform: translateZ(0);
|
transform: translateZ(0);
|
||||||
-webkit-transform: none !important;
|
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
@ -231,7 +229,6 @@ body > header {
|
|||||||
.mobile-label {
|
.mobile-label {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translate(-50%, 80%);
|
transform: translate(-50%, 80%);
|
||||||
-webkit-transform: translate(-50%, 80%);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -262,7 +259,7 @@ body > header {
|
|||||||
transform-origin: left;
|
transform-origin: left;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body > header {
|
body > header {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -280,7 +277,7 @@ body > header {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body > header:focus-within #content, #content.show {
|
body > header:focus-within #content, .show + #content {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
16
build.rs
16
build.rs
@ -48,18 +48,12 @@ fn main() {
|
|||||||
create_dir_all(&Path::new("static").join("media")).expect("Couldn't init media directory");
|
create_dir_all(&Path::new("static").join("media")).expect("Couldn't init media directory");
|
||||||
|
|
||||||
let cache_id = &compute_static_hash()[..8];
|
let cache_id = &compute_static_hash()[..8];
|
||||||
println!("cargo:rerun-if-changed=target/deploy/plume-front.wasm");
|
println!("cargo:rerun-if-changed=plume-front/pkg/plume_front_bg.wasm");
|
||||||
copy("target/deploy/plume-front.wasm", "static/plume-front.wasm")
|
copy(
|
||||||
.and_then(|_| read_to_string("target/deploy/plume-front.js"))
|
"plume-front/pkg/plume_front_bg.wasm",
|
||||||
.and_then(|js| {
|
"static/plume_front_bg.wasm",
|
||||||
write(
|
|
||||||
"static/plume-front.js",
|
|
||||||
js.replace(
|
|
||||||
"\"plume-front.wasm\"",
|
|
||||||
&format!("\"/static/cached/{}/plume-front.wasm\"", cache_id),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
})
|
.and_then(|_| copy("plume-front/pkg/plume_front.js", "static/plume_front.js"))
|
||||||
.ok();
|
.ok();
|
||||||
|
|
||||||
println!("cargo:rustc-env=CACHE_ID={}", cache_id)
|
println!("cargo:rustc-env=CACHE_ID={}", cache_id)
|
||||||
|
@ -4,12 +4,49 @@ version = "0.6.1-dev"
|
|||||||
authors = ["Plume contributors"]
|
authors = ["Plume contributors"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
stdweb = "=0.4.18"
|
|
||||||
stdweb-internal-runtime = "=0.1.4"
|
|
||||||
gettext = { git = "https://github.com/Plume-org/gettext/", rev = "294c54d74c699fbc66502b480a37cc66c1daa7f3" }
|
gettext = { git = "https://github.com/Plume-org/gettext/", rev = "294c54d74c699fbc66502b480a37cc66c1daa7f3" }
|
||||||
gettext-macros = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
|
gettext-macros = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
|
||||||
gettext-utils = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
|
gettext-utils = { git = "https://github.com/Plume-org/gettext-macros/", rev = "a7c605f7edd6bfbfbfe7778026bfefd88d82db10" }
|
||||||
lazy_static = "1.3"
|
lazy_static = "1.3"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
wasm-bindgen = "0.2.70"
|
||||||
|
js-sys = "0.3.47"
|
||||||
|
serde_derive = "1.0.123"
|
||||||
|
console_error_panic_hook = "0.1.6"
|
||||||
|
|
||||||
|
[dependencies.web-sys]
|
||||||
|
version = "0.3.47"
|
||||||
|
features = [
|
||||||
|
'console',
|
||||||
|
'ClipboardEvent',
|
||||||
|
'CssStyleDeclaration',
|
||||||
|
'DataTransfer',
|
||||||
|
'Document',
|
||||||
|
'DomStringMap',
|
||||||
|
'DomTokenList',
|
||||||
|
'Element',
|
||||||
|
'EventTarget',
|
||||||
|
'FocusEvent',
|
||||||
|
'History',
|
||||||
|
'HtmlAnchorElement',
|
||||||
|
'HtmlDocument',
|
||||||
|
'HtmlFormElement',
|
||||||
|
'HtmlInputElement',
|
||||||
|
'HtmlSelectElement',
|
||||||
|
'HtmlTextAreaElement',
|
||||||
|
'KeyboardEvent',
|
||||||
|
'Storage',
|
||||||
|
'Location',
|
||||||
|
'MouseEvent',
|
||||||
|
'Navigator',
|
||||||
|
'Node',
|
||||||
|
'NodeList',
|
||||||
|
'Text',
|
||||||
|
'TouchEvent',
|
||||||
|
'Window'
|
||||||
|
]
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
use crate::CATALOG;
|
use crate::{document, CATALOG};
|
||||||
use serde::{Deserialize, Serialize};
|
use js_sys::{encode_uri_component, Date, RegExp};
|
||||||
use std::sync::Mutex;
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use stdweb::{
|
use std::{convert::TryInto, sync::Mutex};
|
||||||
unstable::{TryFrom, TryInto},
|
use wasm_bindgen::{prelude::*, JsCast, JsValue};
|
||||||
web::{event::*, html_element::*, *},
|
use web_sys::{
|
||||||
|
console, window, ClipboardEvent, Element, Event, FocusEvent, HtmlAnchorElement, HtmlDocument,
|
||||||
|
HtmlElement, HtmlFormElement, HtmlInputElement, HtmlSelectElement, HtmlTextAreaElement,
|
||||||
|
KeyboardEvent, MouseEvent, Node,
|
||||||
};
|
};
|
||||||
|
|
||||||
macro_rules! mv {
|
macro_rules! mv {
|
||||||
@ -17,30 +20,29 @@ macro_rules! mv {
|
|||||||
|
|
||||||
fn get_elt_value(id: &'static str) -> String {
|
fn get_elt_value(id: &'static str) -> String {
|
||||||
let elt = document().get_element_by_id(id).unwrap();
|
let elt = document().get_element_by_id(id).unwrap();
|
||||||
let inp: Result<InputElement, _> = elt.clone().try_into();
|
let inp: Option<&HtmlInputElement> = elt.dyn_ref();
|
||||||
let textarea: Result<TextAreaElement, _> = elt.clone().try_into();
|
let textarea: Option<&HtmlTextAreaElement> = elt.dyn_ref();
|
||||||
let select: Result<SelectElement, _> = elt.try_into();
|
let select: Option<&HtmlSelectElement> = elt.dyn_ref();
|
||||||
inp.map(|i| i.raw_value()).unwrap_or_else(|_| {
|
inp.map(|i| i.value()).unwrap_or_else(|| {
|
||||||
textarea
|
textarea
|
||||||
.map(|t| t.value())
|
.map(|t| t.value())
|
||||||
.unwrap_or_else(|_| select.unwrap().raw_value())
|
.unwrap_or_else(|| select.unwrap().value())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_value<S: AsRef<str>>(id: &'static str, val: S) {
|
fn set_value<S: AsRef<str>>(id: &'static str, val: S) {
|
||||||
let elt = document().get_element_by_id(id).unwrap();
|
let elt = document().get_element_by_id(id).unwrap();
|
||||||
let inp: Result<InputElement, _> = elt.clone().try_into();
|
let inp: Option<&HtmlInputElement> = elt.dyn_ref();
|
||||||
let textarea: Result<TextAreaElement, _> = elt.clone().try_into();
|
let textarea: Option<&HtmlTextAreaElement> = elt.dyn_ref();
|
||||||
let select: Result<SelectElement, _> = elt.try_into();
|
let select: Option<&HtmlSelectElement> = elt.dyn_ref();
|
||||||
inp.map(|i| i.set_raw_value(val.as_ref()))
|
inp.map(|i| i.set_value(val.as_ref())).unwrap_or_else(|| {
|
||||||
.unwrap_or_else(|_| {
|
|
||||||
textarea
|
textarea
|
||||||
.map(|t| t.set_value(val.as_ref()))
|
.map(|t| t.set_value(val.as_ref()))
|
||||||
.unwrap_or_else(|_| select.unwrap().set_raw_value(val.as_ref()))
|
.unwrap_or_else(|| select.unwrap().set_value(val.as_ref()))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn no_return(evt: KeyDownEvent) {
|
fn no_return(evt: KeyboardEvent) {
|
||||||
if evt.key() == "Enter" {
|
if evt.key() == "Enter" {
|
||||||
evt.prevent_default();
|
evt.prevent_default();
|
||||||
}
|
}
|
||||||
@ -50,7 +52,6 @@ fn no_return(evt: KeyDownEvent) {
|
|||||||
pub enum EditorError {
|
pub enum EditorError {
|
||||||
NoneError,
|
NoneError,
|
||||||
DOMError,
|
DOMError,
|
||||||
TypeError,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<std::option::NoneError> for EditorError {
|
impl From<std::option::NoneError> for EditorError {
|
||||||
@ -58,22 +59,7 @@ impl From<std::option::NoneError> for EditorError {
|
|||||||
EditorError::NoneError
|
EditorError::NoneError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<stdweb::web::error::InvalidCharacterError> for EditorError {
|
const AUTOSAVE_DEBOUNCE_TIME: i32 = 5000;
|
||||||
fn from(_: stdweb::web::error::InvalidCharacterError) -> Self {
|
|
||||||
EditorError::DOMError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<stdweb::private::TODO> for EditorError {
|
|
||||||
fn from(_: stdweb::private::TODO) -> Self {
|
|
||||||
EditorError::DOMError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<stdweb::private::ConversionError> for EditorError {
|
|
||||||
fn from(_: stdweb::private::ConversionError) -> Self {
|
|
||||||
EditorError::TypeError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const AUTOSAVE_DEBOUNCE_TIME: u32 = 5000;
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
struct AutosaveInformation {
|
struct AutosaveInformation {
|
||||||
contents: String,
|
contents: String,
|
||||||
@ -84,10 +70,16 @@ struct AutosaveInformation {
|
|||||||
tags: String,
|
tags: String,
|
||||||
title: String,
|
title: String,
|
||||||
}
|
}
|
||||||
js_serializable!(AutosaveInformation);
|
|
||||||
fn is_basic_editor() -> bool {
|
fn is_basic_editor() -> bool {
|
||||||
if let Some(basic_editor) = window().local_storage().get("basic-editor") {
|
if let Some(basic_editor) = window()
|
||||||
basic_editor == "true"
|
.unwrap()
|
||||||
|
.local_storage()
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.get("basic-editor")
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
&basic_editor == "true"
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
@ -96,65 +88,58 @@ fn get_title() -> String {
|
|||||||
if is_basic_editor() {
|
if is_basic_editor() {
|
||||||
get_elt_value("title")
|
get_elt_value("title")
|
||||||
} else {
|
} else {
|
||||||
let title_field = HtmlElement::try_from(
|
|
||||||
document()
|
document()
|
||||||
.query_selector("#plume-editor > h1")
|
.query_selector("#plume-editor > h1")
|
||||||
.ok()
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap(),
|
.unwrap()
|
||||||
)
|
.dyn_ref::<HtmlElement>()
|
||||||
.ok()
|
.unwrap()
|
||||||
.unwrap();
|
.inner_text()
|
||||||
title_field.inner_text()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_autosave_id() -> String {
|
fn get_autosave_id() -> String {
|
||||||
format!(
|
format!(
|
||||||
"editor_contents={}",
|
"editor_contents={}",
|
||||||
window().location().unwrap().pathname().unwrap()
|
window().unwrap().location().pathname().unwrap()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn get_editor_contents() -> String {
|
fn get_editor_contents() -> String {
|
||||||
if is_basic_editor() {
|
if is_basic_editor() {
|
||||||
get_elt_value("editor-content")
|
get_elt_value("editor-content")
|
||||||
} else {
|
} else {
|
||||||
let editor =
|
let editor = document().query_selector("article").unwrap().unwrap();
|
||||||
HtmlElement::try_from(document().query_selector("article").ok().unwrap().unwrap())
|
let child_nodes = editor.child_nodes();
|
||||||
.ok()
|
let mut md = String::new();
|
||||||
.unwrap();
|
for i in 0..child_nodes.length() {
|
||||||
editor.child_nodes().iter().fold(String::new(), |md, ch| {
|
let ch = child_nodes.get(i).unwrap();
|
||||||
let to_append = match ch.node_type() {
|
let to_append = match ch.node_type() {
|
||||||
NodeType::Element => {
|
Node::ELEMENT_NODE => {
|
||||||
if js! { return @{&ch}.tagName; } == "DIV" {
|
let elt = ch.dyn_ref::<Element>().unwrap();
|
||||||
(js! { return @{&ch}.innerHTML; })
|
if elt.tag_name() == "DIV" {
|
||||||
.try_into()
|
elt.inner_html()
|
||||||
.unwrap_or_default()
|
|
||||||
} else {
|
} else {
|
||||||
(js! { return @{&ch}.outerHTML; })
|
elt.outer_html()
|
||||||
.try_into()
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeType::Text => ch.node_value().unwrap_or_default(),
|
Node::TEXT_NODE => ch.node_value().unwrap_or_default(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
format!("{}\n\n{}", md, to_append)
|
md = format!("{}\n\n{}", md, to_append);
|
||||||
})
|
}
|
||||||
|
md
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn get_subtitle() -> String {
|
fn get_subtitle() -> String {
|
||||||
if is_basic_editor() {
|
if is_basic_editor() {
|
||||||
get_elt_value("subtitle")
|
get_elt_value("subtitle")
|
||||||
} else {
|
} else {
|
||||||
let subtitle_element = HtmlElement::try_from(
|
|
||||||
document()
|
document()
|
||||||
.query_selector("#plume-editor > h2")
|
.query_selector("#plume-editor > h2")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap(),
|
.unwrap()
|
||||||
)
|
.dyn_ref::<HtmlElement>()
|
||||||
.ok()
|
.unwrap()
|
||||||
.unwrap();
|
.inner_text()
|
||||||
subtitle_element.inner_text()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn autosave() {
|
fn autosave() {
|
||||||
@ -169,27 +154,31 @@ fn autosave() {
|
|||||||
};
|
};
|
||||||
let id = get_autosave_id();
|
let id = get_autosave_id();
|
||||||
match window()
|
match window()
|
||||||
|
.unwrap()
|
||||||
.local_storage()
|
.local_storage()
|
||||||
.insert(&id, &serde_json::to_string(&info).unwrap())
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.set(&id, &serde_json::to_string(&info).unwrap())
|
||||||
{
|
{
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
_ => console!(log, "Autosave failed D:"),
|
_ => console::log_1(&"Autosave failed D:".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//This is only necessary until we go to stdweb 4.20 at least
|
|
||||||
fn confirm(message: &str) -> bool {
|
|
||||||
let result: bool = js! {return confirm(@{message});} == true;
|
|
||||||
result
|
|
||||||
}
|
|
||||||
fn load_autosave() {
|
fn load_autosave() {
|
||||||
if let Some(autosave_str) = window().local_storage().get(&get_autosave_id()) {
|
if let Ok(Some(autosave_str)) = window()
|
||||||
|
.unwrap()
|
||||||
|
.local_storage()
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.get(&get_autosave_id())
|
||||||
|
{
|
||||||
let autosave_info: AutosaveInformation = serde_json::from_str(&autosave_str).ok().unwrap();
|
let autosave_info: AutosaveInformation = serde_json::from_str(&autosave_str).ok().unwrap();
|
||||||
let message = i18n!(
|
let message = i18n!(
|
||||||
CATALOG,
|
CATALOG,
|
||||||
"Do you want to load the local autosave last edited at {}?";
|
"Do you want to load the local autosave last edited at {}?";
|
||||||
Date::from_time(autosave_info.last_saved).to_date_string()
|
Date::new(&JsValue::from_f64(autosave_info.last_saved)).to_date_string().as_string().unwrap()
|
||||||
);
|
);
|
||||||
if confirm(&message) {
|
if let Ok(true) = window().unwrap().confirm_with_message(&message) {
|
||||||
set_value("editor-content", &autosave_info.contents);
|
set_value("editor-content", &autosave_info.contents);
|
||||||
set_value("title", &autosave_info.title);
|
set_value("title", &autosave_info.title);
|
||||||
set_value("subtitle", &autosave_info.subtitle);
|
set_value("subtitle", &autosave_info.subtitle);
|
||||||
@ -202,18 +191,33 @@ fn load_autosave() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn clear_autosave() {
|
fn clear_autosave() {
|
||||||
window().local_storage().remove(&get_autosave_id());
|
window()
|
||||||
console!(log, &format!("Saved to {}", &get_autosave_id()));
|
.unwrap()
|
||||||
|
.local_storage()
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.remove_item(&get_autosave_id())
|
||||||
|
.unwrap();
|
||||||
|
console::log_1(&&format!("Saved to {}", &get_autosave_id()).into());
|
||||||
}
|
}
|
||||||
|
type TimeoutHandle = i32;
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref AUTOSAVE_TIMEOUT: Mutex<Option<TimeoutHandle>> = Mutex::new(None);
|
static ref AUTOSAVE_TIMEOUT: Mutex<Option<TimeoutHandle>> = Mutex::new(None);
|
||||||
}
|
}
|
||||||
fn autosave_debounce() {
|
fn autosave_debounce() {
|
||||||
|
let window = window().unwrap();
|
||||||
let timeout = &mut AUTOSAVE_TIMEOUT.lock().unwrap();
|
let timeout = &mut AUTOSAVE_TIMEOUT.lock().unwrap();
|
||||||
if let Some(timeout) = timeout.take() {
|
if let Some(timeout) = timeout.take() {
|
||||||
timeout.clear();
|
window.clear_timeout_with_handle(timeout);
|
||||||
}
|
}
|
||||||
**timeout = Some(window().set_clearable_timeout(autosave, AUTOSAVE_DEBOUNCE_TIME));
|
let callback = Closure::once(autosave);
|
||||||
|
**timeout = window
|
||||||
|
.set_timeout_with_callback_and_timeout_and_arguments_0(
|
||||||
|
callback.as_ref().unchecked_ref(),
|
||||||
|
AUTOSAVE_DEBOUNCE_TIME,
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
callback.forget();
|
||||||
}
|
}
|
||||||
fn init_widget(
|
fn init_widget(
|
||||||
parent: &Element,
|
parent: &Element,
|
||||||
@ -222,19 +226,33 @@ fn init_widget(
|
|||||||
content: String,
|
content: String,
|
||||||
disable_return: bool,
|
disable_return: bool,
|
||||||
) -> Result<HtmlElement, EditorError> {
|
) -> Result<HtmlElement, EditorError> {
|
||||||
let widget = placeholder(make_editable(tag).try_into()?, &placeholder_text);
|
let widget = placeholder(
|
||||||
|
make_editable(tag).dyn_into::<HtmlElement>().unwrap(),
|
||||||
|
&placeholder_text,
|
||||||
|
);
|
||||||
if !content.is_empty() {
|
if !content.is_empty() {
|
||||||
widget.dataset().insert("edited", "true")?;
|
widget
|
||||||
|
.dataset()
|
||||||
|
.set("edited", "true")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
}
|
}
|
||||||
widget.append_child(&document().create_text_node(&content));
|
widget
|
||||||
|
.append_child(&document().create_text_node(&content))
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
if disable_return {
|
if disable_return {
|
||||||
widget.add_event_listener(no_return);
|
let callback = Closure::wrap(Box::new(no_return) as Box<dyn FnMut(KeyboardEvent)>);
|
||||||
|
widget
|
||||||
|
.add_event_listener_with_callback("keydown", callback.as_ref().unchecked_ref())
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
callback.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.append_child(&widget);
|
parent
|
||||||
|
.append_child(&widget)
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
// We need to do that to make sure the placeholder is correctly rendered
|
// We need to do that to make sure the placeholder is correctly rendered
|
||||||
widget.focus();
|
widget.focus().map_err(|_| EditorError::DOMError)?;
|
||||||
widget.blur();
|
widget.blur().map_err(|_| EditorError::DOMError)?;
|
||||||
|
|
||||||
filter_paste(&widget);
|
filter_paste(&widget);
|
||||||
|
|
||||||
@ -243,48 +261,88 @@ fn init_widget(
|
|||||||
|
|
||||||
fn filter_paste(elt: &HtmlElement) {
|
fn filter_paste(elt: &HtmlElement) {
|
||||||
// Only insert text when pasting something
|
// Only insert text when pasting something
|
||||||
js! {
|
let insert_text = Closure::wrap(Box::new(|evt: ClipboardEvent| {
|
||||||
@{&elt}.addEventListener("paste", function (evt) {
|
evt.prevent_default();
|
||||||
evt.preventDefault();
|
if let Some(data) = evt.clipboard_data() {
|
||||||
document.execCommand("insertText", false, evt.clipboardData.getData("text"));
|
if let Ok(data) = data.get_data("text") {
|
||||||
});
|
document()
|
||||||
};
|
.dyn_ref::<HtmlDocument>()
|
||||||
|
.unwrap()
|
||||||
|
.exec_command_with_show_ui_and_value("insertText", false, &data)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) as Box<dyn FnMut(ClipboardEvent)>);
|
||||||
|
elt.add_event_listener_with_callback("paste", insert_text.as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
insert_text.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() -> Result<(), EditorError> {
|
pub fn init() -> Result<(), EditorError> {
|
||||||
if let Some(ed) = document().get_element_by_id("plume-fallback-editor") {
|
if let Some(ed) = document().get_element_by_id("plume-fallback-editor") {
|
||||||
load_autosave();
|
load_autosave();
|
||||||
ed.add_event_listener(|_: SubmitEvent| clear_autosave());
|
let callback = Closure::wrap(Box::new(|_| clear_autosave()) as Box<dyn FnMut(Event)>);
|
||||||
|
ed.add_event_listener_with_callback("submit", callback.as_ref().unchecked_ref())
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
callback.forget();
|
||||||
}
|
}
|
||||||
// Check if the user wants to use the basic editor
|
// Check if the user wants to use the basic editor
|
||||||
if window()
|
if window()
|
||||||
|
.unwrap()
|
||||||
.local_storage()
|
.local_storage()
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
.get("basic-editor")
|
.get("basic-editor")
|
||||||
.map(|x| x == "true")
|
.map(|x| x.is_some() && x.unwrap() == "true")
|
||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
{
|
{
|
||||||
if let Some(editor) = document().get_element_by_id("plume-fallback-editor") {
|
if let Some(editor) = document().get_element_by_id("plume-fallback-editor") {
|
||||||
if let Ok(Some(title_label)) = document().query_selector("label[for=title]") {
|
if let Ok(Some(title_label)) = document().query_selector("label[for=title]") {
|
||||||
let editor_button = document().create_element("a")?;
|
let editor_button = document()
|
||||||
js! { @{&editor_button}.href = "#"; }
|
.create_element("a")
|
||||||
editor_button.add_event_listener(|_: ClickEvent| {
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
if window()
|
editor_button
|
||||||
|
.dyn_ref::<HtmlAnchorElement>()
|
||||||
|
.unwrap()
|
||||||
|
.set_href("#");
|
||||||
|
let disable_basic_editor = Closure::wrap(Box::new(|_| {
|
||||||
|
let window = window().unwrap();
|
||||||
|
if window
|
||||||
.local_storage()
|
.local_storage()
|
||||||
.insert("basic-editor", "false")
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.set("basic-editor", "false")
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
console!(log, "Failed to write into local storage");
|
console::log_1(&"Failed to write into local storage".into());
|
||||||
}
|
}
|
||||||
window().history().go(0).ok(); // refresh
|
window.history().unwrap().go_with_delta(0).ok(); // refresh
|
||||||
});
|
})
|
||||||
editor_button.append_child(
|
as Box<dyn FnMut(MouseEvent)>);
|
||||||
|
editor_button
|
||||||
|
.add_event_listener_with_callback(
|
||||||
|
"click",
|
||||||
|
disable_basic_editor.as_ref().unchecked_ref(),
|
||||||
|
)
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
disable_basic_editor.forget();
|
||||||
|
editor_button
|
||||||
|
.append_child(
|
||||||
&document().create_text_node(&i18n!(CATALOG, "Open the rich text editor")),
|
&document().create_text_node(&i18n!(CATALOG, "Open the rich text editor")),
|
||||||
|
)
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
editor
|
||||||
|
.insert_before(&editor_button, Some(&title_label))
|
||||||
|
.ok();
|
||||||
|
let callback = Closure::wrap(
|
||||||
|
Box::new(|_| autosave_debounce()) as Box<dyn FnMut(KeyboardEvent)>
|
||||||
);
|
);
|
||||||
editor.insert_before(&editor_button, &title_label).ok();
|
|
||||||
document()
|
document()
|
||||||
.get_element_by_id("editor-content")
|
.get_element_by_id("editor-content")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.add_event_listener(|_: KeyDownEvent| autosave_debounce());
|
.add_event_listener_with_callback("keydown", callback.as_ref().unchecked_ref())
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
callback.forget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,14 +355,30 @@ pub fn init() -> Result<(), EditorError> {
|
|||||||
fn init_editor() -> Result<(), EditorError> {
|
fn init_editor() -> Result<(), EditorError> {
|
||||||
if let Some(ed) = document().get_element_by_id("plume-editor") {
|
if let Some(ed) = document().get_element_by_id("plume-editor") {
|
||||||
// Show the editor
|
// Show the editor
|
||||||
js! { @{&ed}.style.display = "block"; };
|
ed.dyn_ref::<HtmlElement>()
|
||||||
|
.unwrap()
|
||||||
|
.style()
|
||||||
|
.set_property("display", "block")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
// And hide the HTML-only fallback
|
// And hide the HTML-only fallback
|
||||||
let old_ed = document().get_element_by_id("plume-fallback-editor")?;
|
let old_ed = document().get_element_by_id("plume-fallback-editor");
|
||||||
|
if old_ed.is_none() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let old_ed = old_ed.unwrap();
|
||||||
let old_title = document().get_element_by_id("plume-editor-title")?;
|
let old_title = document().get_element_by_id("plume-editor-title")?;
|
||||||
js! {
|
old_ed
|
||||||
@{&old_ed}.style.display = "none";
|
.dyn_ref::<HtmlElement>()
|
||||||
@{&old_title}.style.display = "none";
|
.unwrap()
|
||||||
};
|
.style()
|
||||||
|
.set_property("display", "none")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
old_title
|
||||||
|
.dyn_ref::<HtmlElement>()
|
||||||
|
.unwrap()
|
||||||
|
.style()
|
||||||
|
.set_property("display", "none")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
|
||||||
// Get content from the old editor (when editing an article for instance)
|
// Get content from the old editor (when editing an article for instance)
|
||||||
let title_val = get_elt_value("title");
|
let title_val = get_elt_value("title");
|
||||||
@ -326,24 +400,29 @@ fn init_editor() -> Result<(), EditorError> {
|
|||||||
content_val.clone(),
|
content_val.clone(),
|
||||||
false,
|
false,
|
||||||
)?;
|
)?;
|
||||||
js! { @{&content}.innerHTML = @{content_val}; };
|
content.set_inner_html(&content_val);
|
||||||
|
|
||||||
// character counter
|
// character counter
|
||||||
content.add_event_listener(mv!(content => move |_: KeyDownEvent| {
|
let character_counter = Closure::wrap(Box::new(mv!(content => move |_| {
|
||||||
window().set_timeout(mv!(content => move || {
|
let update_char_count = Closure::wrap(Box::new(mv!(content => move || {
|
||||||
if let Some(e) = document().get_element_by_id("char-count") {
|
if let Some(e) = document().get_element_by_id("char-count") {
|
||||||
let count = chars_left("#plume-fallback-editor", &content).unwrap_or_default();
|
let count = chars_left("#plume-fallback-editor", &content).unwrap_or_default();
|
||||||
let text = i18n!(CATALOG, "Around {} characters left"; count);
|
let text = i18n!(CATALOG, "Around {} characters left"; count);
|
||||||
HtmlElement::try_from(e).map(|e| {
|
e.dyn_ref::<HtmlElement>().map(|e| {
|
||||||
js!{@{e}.innerText = @{text}};
|
e.set_inner_text(&text);
|
||||||
}).ok();
|
}).unwrap();
|
||||||
};
|
};
|
||||||
}), 0);
|
})) as Box<dyn FnMut()>);
|
||||||
|
window().unwrap().set_timeout_with_callback_and_timeout_and_arguments(update_char_count.as_ref().unchecked_ref(), 0, &js_sys::Array::new()).unwrap();
|
||||||
|
update_char_count.forget();
|
||||||
autosave_debounce();
|
autosave_debounce();
|
||||||
}));
|
})) as Box<dyn FnMut(KeyboardEvent)>);
|
||||||
|
content
|
||||||
|
.add_event_listener_with_callback("keydown", character_counter.as_ref().unchecked_ref())
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
character_counter.forget();
|
||||||
|
|
||||||
document().get_element_by_id("publish")?.add_event_listener(
|
let show_popup = Closure::wrap(Box::new(mv!(title, subtitle, content, old_ed => move |_| {
|
||||||
mv!(title, subtitle, content, old_ed => move |_: ClickEvent| {
|
|
||||||
let popup = document().get_element_by_id("publish-popup").or_else(||
|
let popup = document().get_element_by_id("publish-popup").or_else(||
|
||||||
init_popup(&title, &subtitle, &content, &old_ed).ok()
|
init_popup(&title, &subtitle, &content, &old_ed).ok()
|
||||||
).unwrap();
|
).unwrap();
|
||||||
@ -351,10 +430,14 @@ fn init_editor() -> Result<(), EditorError> {
|
|||||||
init_popup_bg().ok()
|
init_popup_bg().ok()
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
popup.class_list().add("show").unwrap();
|
popup.class_list().add_1("show").unwrap();
|
||||||
bg.class_list().add("show").unwrap();
|
bg.class_list().add_1("show").unwrap();
|
||||||
}),
|
})) as Box<dyn FnMut(MouseEvent)>);
|
||||||
);
|
document()
|
||||||
|
.get_element_by_id("publish")?
|
||||||
|
.add_event_listener_with_callback("click", show_popup.as_ref().unchecked_ref())
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
show_popup.forget();
|
||||||
|
|
||||||
show_errors();
|
show_errors();
|
||||||
setup_close_button();
|
setup_close_button();
|
||||||
@ -364,32 +447,47 @@ fn init_editor() -> Result<(), EditorError> {
|
|||||||
|
|
||||||
fn setup_close_button() {
|
fn setup_close_button() {
|
||||||
if let Some(button) = document().get_element_by_id("close-editor") {
|
if let Some(button) = document().get_element_by_id("close-editor") {
|
||||||
button.add_event_listener(|_: ClickEvent| {
|
let close_editor = Closure::wrap(Box::new(|_| {
|
||||||
window()
|
window()
|
||||||
|
.unwrap()
|
||||||
.local_storage()
|
.local_storage()
|
||||||
.insert("basic-editor", "true")
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.set("basic-editor", "true")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
window().history().go(0).unwrap(); // Refresh the page
|
window()
|
||||||
});
|
.unwrap()
|
||||||
|
.history()
|
||||||
|
.unwrap()
|
||||||
|
.go_with_delta(0)
|
||||||
|
.unwrap(); // Refresh the page
|
||||||
|
}) as Box<dyn FnMut(MouseEvent)>);
|
||||||
|
button
|
||||||
|
.add_event_listener_with_callback("click", close_editor.as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
close_editor.forget();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_errors() {
|
fn show_errors() {
|
||||||
if let Ok(Some(header)) = document().query_selector("header") {
|
let document = document();
|
||||||
let list = document().create_element("header").unwrap();
|
if let Ok(Some(header)) = document.query_selector("header") {
|
||||||
list.class_list().add("messages").unwrap();
|
let list = document.create_element("header").unwrap();
|
||||||
for error in document().query_selector_all("p.error").unwrap() {
|
list.class_list().add_1("messages").unwrap();
|
||||||
|
let errors = document.query_selector_all("p.error").unwrap();
|
||||||
|
for i in 0..errors.length() {
|
||||||
|
let error = errors.get(i).unwrap();
|
||||||
error
|
error
|
||||||
.parent_element()
|
.parent_element()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.remove_child(&error)
|
.remove_child(&error)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
list.append_child(&error);
|
let _ = list.append_child(&error);
|
||||||
}
|
}
|
||||||
header
|
header
|
||||||
.parent_element()
|
.parent_element()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.insert_before(&list, &header.next_sibling().unwrap())
|
.insert_before(&list, header.next_sibling().as_ref())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -400,9 +498,17 @@ fn init_popup(
|
|||||||
content: &HtmlElement,
|
content: &HtmlElement,
|
||||||
old_ed: &Element,
|
old_ed: &Element,
|
||||||
) -> Result<Element, EditorError> {
|
) -> Result<Element, EditorError> {
|
||||||
let popup = document().create_element("div")?;
|
let document = document();
|
||||||
popup.class_list().add("popup")?;
|
let popup = document
|
||||||
popup.set_attribute("id", "publish-popup")?;
|
.create_element("div")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
popup
|
||||||
|
.class_list()
|
||||||
|
.add_1("popup")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
popup
|
||||||
|
.set_attribute("id", "publish-popup")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
|
||||||
let tags = get_elt_value("tags")
|
let tags = get_elt_value("tags")
|
||||||
.split(',')
|
.split(',')
|
||||||
@ -410,109 +516,154 @@ fn init_popup(
|
|||||||
.map(str::to_string)
|
.map(str::to_string)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let license = get_elt_value("license");
|
let license = get_elt_value("license");
|
||||||
make_input(&i18n!(CATALOG, "Tags"), "popup-tags", &popup).set_raw_value(&tags.join(", "));
|
make_input(&i18n!(CATALOG, "Tags"), "popup-tags", &popup).set_value(&tags.join(", "));
|
||||||
make_input(&i18n!(CATALOG, "License"), "popup-license", &popup).set_raw_value(&license);
|
make_input(&i18n!(CATALOG, "License"), "popup-license", &popup).set_value(&license);
|
||||||
|
|
||||||
let cover_label = document().create_element("label")?;
|
let cover_label = document
|
||||||
cover_label.append_child(&document().create_text_node(&i18n!(CATALOG, "Cover")));
|
.create_element("label")
|
||||||
cover_label.set_attribute("for", "cover")?;
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
let cover = document().get_element_by_id("cover")?;
|
cover_label
|
||||||
|
.append_child(&document.create_text_node(&i18n!(CATALOG, "Cover")))
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
cover_label
|
||||||
|
.set_attribute("for", "cover")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
let cover = document.get_element_by_id("cover")?;
|
||||||
cover.parent_element()?.remove_child(&cover).ok();
|
cover.parent_element()?.remove_child(&cover).ok();
|
||||||
popup.append_child(&cover_label);
|
popup
|
||||||
popup.append_child(&cover);
|
.append_child(&cover_label)
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
popup
|
||||||
|
.append_child(&cover)
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
|
||||||
if let Some(draft_checkbox) = document().get_element_by_id("draft") {
|
if let Some(draft_checkbox) = document.get_element_by_id("draft") {
|
||||||
let draft_label = document().create_element("label")?;
|
let draft_checkbox = draft_checkbox.dyn_ref::<HtmlInputElement>().unwrap();
|
||||||
draft_label.set_attribute("for", "popup-draft")?;
|
let draft_label = document
|
||||||
|
.create_element("label")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
draft_label
|
||||||
|
.set_attribute("for", "popup-draft")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
|
||||||
let draft = document().create_element("input").unwrap();
|
let draft = document.create_element("input").unwrap();
|
||||||
js! {
|
draft.set_id("popup-draft");
|
||||||
@{&draft}.id = "popup-draft";
|
let draft = draft.dyn_ref::<HtmlInputElement>().unwrap();
|
||||||
@{&draft}.name = "popup-draft";
|
draft.set_name("popup-draft");
|
||||||
@{&draft}.type = "checkbox";
|
draft.set_type("checkbox");
|
||||||
@{&draft}.checked = @{&draft_checkbox}.checked;
|
draft.set_checked(draft_checkbox.checked());
|
||||||
};
|
|
||||||
|
|
||||||
draft_label.append_child(&draft);
|
draft_label
|
||||||
draft_label.append_child(&document().create_text_node(&i18n!(CATALOG, "This is a draft")));
|
.append_child(&draft)
|
||||||
popup.append_child(&draft_label);
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
draft_label
|
||||||
|
.append_child(&document.create_text_node(&i18n!(CATALOG, "This is a draft")))
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
popup
|
||||||
|
.append_child(&draft_label)
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let button = document().create_element("input")?;
|
let button = document
|
||||||
js! {
|
.create_element("input")
|
||||||
@{&button}.type = "submit";
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
@{&button}.value = @{i18n!(CATALOG, "Publish")};
|
button
|
||||||
};
|
.append_child(&document.create_text_node(&i18n!(CATALOG, "Publish")))
|
||||||
button.append_child(&document().create_text_node(&i18n!(CATALOG, "Publish")));
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
button.add_event_listener(
|
let button = button.dyn_ref::<HtmlInputElement>().unwrap();
|
||||||
mv!(title, subtitle, content, old_ed => move |_: ClickEvent| {
|
button.set_type("submit");
|
||||||
title.focus(); // Remove the placeholder before publishing
|
button.set_value(&i18n!(CATALOG, "Publish"));
|
||||||
|
let callback = Closure::wrap(Box::new(mv!(title, subtitle, content, old_ed => move |_| {
|
||||||
|
let document = self::document();
|
||||||
|
title.focus().unwrap(); // Remove the placeholder before publishing
|
||||||
set_value("title", title.inner_text());
|
set_value("title", title.inner_text());
|
||||||
subtitle.focus();
|
subtitle.focus().unwrap();
|
||||||
set_value("subtitle", subtitle.inner_text());
|
set_value("subtitle", subtitle.inner_text());
|
||||||
content.focus();
|
content.focus().unwrap();
|
||||||
set_value("editor-content", content.child_nodes().iter().fold(String::new(), |md, ch| {
|
let mut md = String::new();
|
||||||
|
let child_nodes = content.child_nodes();
|
||||||
|
for i in 0..child_nodes.length() {
|
||||||
|
let ch = child_nodes.get(i).unwrap();
|
||||||
let to_append = match ch.node_type() {
|
let to_append = match ch.node_type() {
|
||||||
NodeType::Element => {
|
Node::ELEMENT_NODE => {
|
||||||
if js!{ return @{&ch}.tagName; } == "DIV" {
|
let ch = ch.dyn_ref::<Element>().unwrap();
|
||||||
(js!{ return @{&ch}.innerHTML; }).try_into().unwrap_or_default()
|
if ch.tag_name() == "DIV" {
|
||||||
|
ch.inner_html()
|
||||||
} else {
|
} else {
|
||||||
(js!{ return @{&ch}.outerHTML; }).try_into().unwrap_or_default()
|
ch.outer_html()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
NodeType::Text => ch.node_value().unwrap_or_default(),
|
Node::TEXT_NODE => ch.node_value().unwrap_or_default(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
format!("{}\n\n{}", md, to_append)
|
md = format!("{}\n\n{}", md, to_append);
|
||||||
}));
|
|
||||||
set_value("tags", get_elt_value("popup-tags"));
|
|
||||||
if let Some(draft) = document().get_element_by_id("popup-draft") {
|
|
||||||
js!{
|
|
||||||
document.getElementById("draft").checked = @{draft}.checked;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
let cover = document().get_element_by_id("cover").unwrap();
|
set_value("editor-content", md);
|
||||||
|
set_value("tags", get_elt_value("popup-tags"));
|
||||||
|
if let Some(draft) = document.get_element_by_id("popup-draft") {
|
||||||
|
if let Some(draft_checkbox) = document.get_element_by_id("draft") {
|
||||||
|
let draft_checkbox = draft_checkbox.dyn_ref::<HtmlInputElement>().unwrap();
|
||||||
|
let draft = draft.dyn_ref::<HtmlInputElement>().unwrap();
|
||||||
|
draft_checkbox.set_checked(draft.checked());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let cover = document.get_element_by_id("cover").unwrap();
|
||||||
cover.parent_element().unwrap().remove_child(&cover).ok();
|
cover.parent_element().unwrap().remove_child(&cover).ok();
|
||||||
old_ed.append_child(&cover);
|
old_ed.append_child(&cover).unwrap();
|
||||||
set_value("license", get_elt_value("popup-license"));
|
set_value("license", get_elt_value("popup-license"));
|
||||||
clear_autosave();
|
clear_autosave();
|
||||||
js! {
|
let old_ed = old_ed.dyn_ref::<HtmlFormElement>().unwrap();
|
||||||
@{&old_ed}.submit();
|
old_ed.submit().unwrap();
|
||||||
};
|
})) as Box<dyn FnMut(MouseEvent)>);
|
||||||
}),
|
button
|
||||||
);
|
.add_event_listener_with_callback("click", callback.as_ref().unchecked_ref())
|
||||||
popup.append_child(&button);
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
callback.forget();
|
||||||
|
popup
|
||||||
|
.append_child(&button)
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
|
||||||
document().body()?.append_child(&popup);
|
document
|
||||||
|
.body()?
|
||||||
|
.append_child(&popup)
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
Ok(popup)
|
Ok(popup)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_popup_bg() -> Result<Element, EditorError> {
|
fn init_popup_bg() -> Result<Element, EditorError> {
|
||||||
let bg = document().create_element("div")?;
|
let bg = document()
|
||||||
bg.class_list().add("popup-bg")?;
|
.create_element("div")
|
||||||
bg.set_attribute("id", "popup-bg")?;
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
bg.class_list()
|
||||||
|
.add_1("popup-bg")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
bg.set_attribute("id", "popup-bg")
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
|
||||||
document().body()?.append_child(&bg);
|
document()
|
||||||
bg.add_event_listener(|_: ClickEvent| close_popup());
|
.body()?
|
||||||
|
.append_child(&bg)
|
||||||
|
.map_err(|_| EditorError::DOMError)?;
|
||||||
|
let callback = Closure::wrap(Box::new(|_| close_popup()) as Box<dyn FnMut(MouseEvent)>);
|
||||||
|
bg.add_event_listener_with_callback("click", callback.as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
callback.forget();
|
||||||
Ok(bg)
|
Ok(bg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chars_left(selector: &str, content: &HtmlElement) -> Option<i32> {
|
fn chars_left(selector: &str, content: &HtmlElement) -> Option<i32> {
|
||||||
match document().query_selector(selector) {
|
match document().query_selector(selector) {
|
||||||
Ok(Some(form)) => HtmlElement::try_from(form).ok().and_then(|form| {
|
Ok(Some(form)) => form.dyn_ref::<HtmlElement>().and_then(|form| {
|
||||||
if let Some(len) = form
|
if let Some(len) = form
|
||||||
.get_attribute("content-size")
|
.get_attribute("content-size")
|
||||||
.and_then(|s| s.parse::<i32>().ok())
|
.and_then(|s| s.parse::<i32>().ok())
|
||||||
{
|
{
|
||||||
(js! {
|
(encode_uri_component(&content.inner_html())
|
||||||
let x = encodeURIComponent(@{content}.innerHTML)
|
.replace("%20", "+")
|
||||||
.replace(/%20/g, "+")
|
.replace("%0A", "%0D0A")
|
||||||
.replace(/%0A/g, "%0D%0A")
|
.replace_by_pattern(&RegExp::new("[!'*()]", "g"), "XXX")
|
||||||
.replace(new RegExp("[!'*()]", "g"), "XXX") // replace exceptions of encodeURIComponent with placeholder
|
.length()
|
||||||
.length + 2;
|
+ 2_u32)
|
||||||
console.log(x);
|
|
||||||
return x;
|
|
||||||
})
|
|
||||||
.try_into()
|
.try_into()
|
||||||
.map(|c: i32| len - c)
|
.map(|c: i32| len - c)
|
||||||
.ok()
|
.ok()
|
||||||
@ -525,26 +676,26 @@ fn chars_left(selector: &str, content: &HtmlElement) -> Option<i32> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn close_popup() {
|
fn close_popup() {
|
||||||
let hide = |x: Element| x.class_list().remove("show");
|
let hide = |x: Element| x.class_list().remove_1("show");
|
||||||
document().get_element_by_id("publish-popup").map(hide);
|
document().get_element_by_id("publish-popup").map(hide);
|
||||||
document().get_element_by_id("popup-bg").map(hide);
|
document().get_element_by_id("popup-bg").map(hide);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_input(label_text: &str, name: &'static str, form: &Element) -> InputElement {
|
fn make_input(label_text: &str, name: &'static str, form: &Element) -> HtmlInputElement {
|
||||||
let label = document().create_element("label").unwrap();
|
let document = document();
|
||||||
label.append_child(&document().create_text_node(label_text));
|
let label = document.create_element("label").unwrap();
|
||||||
|
label
|
||||||
|
.append_child(&document.create_text_node(label_text))
|
||||||
|
.unwrap();
|
||||||
label.set_attribute("for", name).unwrap();
|
label.set_attribute("for", name).unwrap();
|
||||||
|
|
||||||
let inp: InputElement = document()
|
let inp = document.create_element("input").unwrap();
|
||||||
.create_element("input")
|
let inp = inp.dyn_into::<HtmlInputElement>().unwrap();
|
||||||
.unwrap()
|
|
||||||
.try_into()
|
|
||||||
.unwrap();
|
|
||||||
inp.set_attribute("name", name).unwrap();
|
inp.set_attribute("name", name).unwrap();
|
||||||
inp.set_attribute("id", name).unwrap();
|
inp.set_attribute("id", name).unwrap();
|
||||||
|
|
||||||
form.append_child(&label);
|
form.append_child(&label).unwrap();
|
||||||
form.append_child(&inp);
|
form.append_child(&inp).unwrap();
|
||||||
inp
|
inp
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -558,36 +709,46 @@ fn make_editable(tag: &'static str) -> Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn placeholder(elt: HtmlElement, text: &str) -> HtmlElement {
|
fn placeholder(elt: HtmlElement, text: &str) -> HtmlElement {
|
||||||
elt.dataset().insert("placeholder", text).unwrap();
|
elt.dataset().set("placeholder", text).unwrap();
|
||||||
elt.dataset().insert("edited", "false").unwrap();
|
elt.dataset().set("edited", "false").unwrap();
|
||||||
|
|
||||||
elt.add_event_listener(mv!(elt => move |_: FocusEvent| {
|
let callback = Closure::wrap(Box::new(mv!(elt => move |_: FocusEvent| {
|
||||||
if elt.dataset().get("edited").unwrap().as_str() != "true" {
|
if elt.dataset().get("edited").unwrap().as_str() != "true" {
|
||||||
clear_children(&elt);
|
clear_children(&elt);
|
||||||
}
|
}
|
||||||
}));
|
})) as Box<dyn FnMut(FocusEvent)>);
|
||||||
elt.add_event_listener(mv!(elt => move |_: BlurEvent| {
|
elt.add_event_listener_with_callback("focus", callback.as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
callback.forget();
|
||||||
|
let callback = Closure::wrap(Box::new(mv!(elt => move |_: Event| {
|
||||||
if elt.dataset().get("edited").unwrap().as_str() != "true" {
|
if elt.dataset().get("edited").unwrap().as_str() != "true" {
|
||||||
clear_children(&elt);
|
clear_children(&elt);
|
||||||
|
|
||||||
let ph = document().create_element("span").expect("Couldn't create placeholder");
|
let ph = document().create_element("span").expect("Couldn't create placeholder");
|
||||||
ph.class_list().add("placeholder").expect("Couldn't add class");
|
ph.class_list().add_1("placeholder").expect("Couldn't add class");
|
||||||
ph.append_child(&document().create_text_node(&elt.dataset().get("placeholder").unwrap_or_default()));
|
ph.append_child(&document().create_text_node(&elt.dataset().get("placeholder").unwrap_or_default())).unwrap();
|
||||||
elt.append_child(&ph);
|
elt.append_child(&ph).unwrap();
|
||||||
}
|
}
|
||||||
}));
|
})) as Box<dyn FnMut(Event)>);
|
||||||
elt.add_event_listener(mv!(elt => move |_: KeyUpEvent| {
|
elt.add_event_listener_with_callback("blur", callback.as_ref().unchecked_ref())
|
||||||
elt.dataset().insert("edited", if elt.inner_text().trim_matches('\n').is_empty() {
|
.unwrap();
|
||||||
|
callback.forget();
|
||||||
|
let callback = Closure::wrap(Box::new(mv!(elt => move |_: KeyboardEvent| {
|
||||||
|
elt.dataset().set("edited", if elt.inner_text().trim_matches('\n').is_empty() {
|
||||||
"false"
|
"false"
|
||||||
} else {
|
} else {
|
||||||
"true"
|
"true"
|
||||||
}).expect("Couldn't update edition state");
|
}).expect("Couldn't update edition state");
|
||||||
}));
|
})) as Box<dyn FnMut(KeyboardEvent)>);
|
||||||
|
elt.add_event_listener_with_callback("keyup", callback.as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
callback.forget();
|
||||||
elt
|
elt
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_children(elt: &HtmlElement) {
|
fn clear_children(elt: &HtmlElement) {
|
||||||
for child in elt.child_nodes() {
|
let child_nodes = elt.child_nodes();
|
||||||
elt.remove_child(&child).unwrap();
|
for _ in 0..child_nodes.length() {
|
||||||
|
elt.remove_child(&child_nodes.get(0).unwrap()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
163
plume-front/src/lib.rs
Executable file
163
plume-front/src/lib.rs
Executable file
@ -0,0 +1,163 @@
|
|||||||
|
#![recursion_limit = "128"]
|
||||||
|
#![feature(decl_macro, proc_macro_hygiene, try_trait)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate gettext_macros;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
|
use wasm_bindgen::{prelude::*, JsCast};
|
||||||
|
use web_sys::{console, window, Document, Element, Event, HtmlInputElement, TouchEvent};
|
||||||
|
|
||||||
|
init_i18n!(
|
||||||
|
"plume-front",
|
||||||
|
af,
|
||||||
|
ar,
|
||||||
|
bg,
|
||||||
|
ca,
|
||||||
|
cs,
|
||||||
|
cy,
|
||||||
|
da,
|
||||||
|
de,
|
||||||
|
el,
|
||||||
|
en,
|
||||||
|
eo,
|
||||||
|
es,
|
||||||
|
fa,
|
||||||
|
fi,
|
||||||
|
fr,
|
||||||
|
gl,
|
||||||
|
he,
|
||||||
|
hi,
|
||||||
|
hr,
|
||||||
|
hu,
|
||||||
|
it,
|
||||||
|
ja,
|
||||||
|
ko,
|
||||||
|
nb,
|
||||||
|
nl,
|
||||||
|
no,
|
||||||
|
pl,
|
||||||
|
pt,
|
||||||
|
ro,
|
||||||
|
ru,
|
||||||
|
sat,
|
||||||
|
si,
|
||||||
|
sk,
|
||||||
|
sl,
|
||||||
|
sr,
|
||||||
|
sv,
|
||||||
|
tr,
|
||||||
|
uk,
|
||||||
|
vi,
|
||||||
|
zh
|
||||||
|
);
|
||||||
|
|
||||||
|
mod editor;
|
||||||
|
|
||||||
|
compile_i18n!();
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref CATALOG: gettext::Catalog = {
|
||||||
|
let catalogs = include_i18n!();
|
||||||
|
let lang = window().unwrap().navigator().language().unwrap();
|
||||||
|
let lang = lang.splitn(2, '-').next().unwrap_or("en");
|
||||||
|
|
||||||
|
let english_position = catalogs
|
||||||
|
.iter()
|
||||||
|
.position(|(language_code, _)| *language_code == "en")
|
||||||
|
.unwrap();
|
||||||
|
catalogs
|
||||||
|
.iter()
|
||||||
|
.find(|(l, _)| l == &lang)
|
||||||
|
.unwrap_or(&catalogs[english_position])
|
||||||
|
.clone()
|
||||||
|
.1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(start)]
|
||||||
|
pub fn main() -> Result<(), JsValue> {
|
||||||
|
extern crate console_error_panic_hook;
|
||||||
|
use std::panic;
|
||||||
|
panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||||
|
|
||||||
|
menu();
|
||||||
|
search();
|
||||||
|
editor::init()
|
||||||
|
.map_err(|e| console::error_1(&&format!("Editor error: {:?}", e).into()))
|
||||||
|
.ok();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Toggle menu on mobile devices
|
||||||
|
///
|
||||||
|
/// It should normally be working fine even without this code
|
||||||
|
/// But :focus-within is not yet supported by Webkit/Blink
|
||||||
|
fn menu() {
|
||||||
|
let document = document();
|
||||||
|
if let Ok(Some(button)) = document.query_selector("#menu a") {
|
||||||
|
if let Some(menu) = document.get_element_by_id("content") {
|
||||||
|
let show_menu = Closure::wrap(Box::new(|_: TouchEvent| {
|
||||||
|
self::document()
|
||||||
|
.get_element_by_id("menu")
|
||||||
|
.map(|menu| {
|
||||||
|
menu.set_attribute("aria-expanded", "true")
|
||||||
|
.map(|_| menu.class_list().add_1("show"))
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
}) as Box<dyn FnMut(TouchEvent)>);
|
||||||
|
button
|
||||||
|
.add_event_listener_with_callback("touchend", show_menu.as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
show_menu.forget();
|
||||||
|
|
||||||
|
let close_menu = Closure::wrap(Box::new(|_: TouchEvent| {
|
||||||
|
self::document()
|
||||||
|
.get_element_by_id("menu")
|
||||||
|
.map(|menu| {
|
||||||
|
menu.set_attribute("aria-expanded", "false")
|
||||||
|
.map(|_| menu.class_list().remove_1("show"))
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
.unwrap()
|
||||||
|
}) as Box<dyn FnMut(TouchEvent)>);
|
||||||
|
menu.add_event_listener_with_callback("touchend", close_menu.as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
close_menu.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clear the URL of the search page before submitting request
|
||||||
|
fn search() {
|
||||||
|
if let Some(form) = document().get_element_by_id("form") {
|
||||||
|
let normalize_query = Closure::wrap(Box::new(|_: Event| {
|
||||||
|
document()
|
||||||
|
.query_selector_all("#form input")
|
||||||
|
.map(|inputs| {
|
||||||
|
for i in 0..inputs.length() {
|
||||||
|
let input = inputs.get(i).unwrap();
|
||||||
|
let input = input.dyn_ref::<HtmlInputElement>().unwrap();
|
||||||
|
if input.name().is_empty() {
|
||||||
|
input.set_name(&input.dyn_ref::<Element>().unwrap().id());
|
||||||
|
}
|
||||||
|
if !input.name().is_empty() && input.value().is_empty() {
|
||||||
|
input.set_name("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}) as Box<dyn FnMut(Event)>);
|
||||||
|
form.add_event_listener_with_callback("submit", normalize_query.as_ref().unchecked_ref())
|
||||||
|
.unwrap();
|
||||||
|
normalize_query.forget();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn document() -> Document {
|
||||||
|
window().unwrap().document().unwrap()
|
||||||
|
}
|
@ -1,129 +0,0 @@
|
|||||||
#![recursion_limit = "128"]
|
|
||||||
#![feature(decl_macro, proc_macro_hygiene, try_trait)]
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate gettext_macros;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate stdweb;
|
|
||||||
use stdweb::web::{event::*, *};
|
|
||||||
|
|
||||||
init_i18n!(
|
|
||||||
"plume-front",
|
|
||||||
af,
|
|
||||||
ar,
|
|
||||||
bg,
|
|
||||||
ca,
|
|
||||||
cs,
|
|
||||||
cy,
|
|
||||||
da,
|
|
||||||
de,
|
|
||||||
el,
|
|
||||||
en,
|
|
||||||
eo,
|
|
||||||
es,
|
|
||||||
fa,
|
|
||||||
fi,
|
|
||||||
fr,
|
|
||||||
gl,
|
|
||||||
he,
|
|
||||||
hi,
|
|
||||||
hr,
|
|
||||||
hu,
|
|
||||||
it,
|
|
||||||
ja,
|
|
||||||
ko,
|
|
||||||
nb,
|
|
||||||
nl,
|
|
||||||
no,
|
|
||||||
pl,
|
|
||||||
pt,
|
|
||||||
ro,
|
|
||||||
ru,
|
|
||||||
sat,
|
|
||||||
si,
|
|
||||||
sk,
|
|
||||||
sl,
|
|
||||||
sr,
|
|
||||||
sv,
|
|
||||||
tr,
|
|
||||||
uk,
|
|
||||||
vi,
|
|
||||||
zh
|
|
||||||
);
|
|
||||||
|
|
||||||
mod editor;
|
|
||||||
|
|
||||||
compile_i18n!();
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref CATALOG: gettext::Catalog = {
|
|
||||||
let catalogs = include_i18n!();
|
|
||||||
let lang = js! { return navigator.language }.into_string().unwrap();
|
|
||||||
let lang = lang.splitn(2, '-').next().unwrap_or("en");
|
|
||||||
|
|
||||||
let english_position = catalogs
|
|
||||||
.iter()
|
|
||||||
.position(|(language_code, _)| *language_code == "en")
|
|
||||||
.unwrap();
|
|
||||||
catalogs
|
|
||||||
.iter()
|
|
||||||
.find(|(l, _)| l == &lang)
|
|
||||||
.unwrap_or(&catalogs[english_position])
|
|
||||||
.clone()
|
|
||||||
.1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
menu();
|
|
||||||
search();
|
|
||||||
editor::init()
|
|
||||||
.map_err(|e| console!(error, format!("Editor error: {:?}", e)))
|
|
||||||
.ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Toggle menu on mobile devices
|
|
||||||
///
|
|
||||||
/// It should normally be working fine even without this code
|
|
||||||
/// But :focus-within is not yet supported by Webkit/Blink
|
|
||||||
fn menu() {
|
|
||||||
if let Some(button) = document().get_element_by_id("menu") {
|
|
||||||
if let Some(menu) = document().get_element_by_id("content") {
|
|
||||||
button.add_event_listener(|_: TouchEnd| {
|
|
||||||
document()
|
|
||||||
.get_element_by_id("menu")
|
|
||||||
.map(|menu| menu.class_list().add("show"));
|
|
||||||
});
|
|
||||||
menu.add_event_listener(|_: TouchEnd| {
|
|
||||||
document()
|
|
||||||
.get_element_by_id("menu")
|
|
||||||
.map(|menu| menu.class_list().remove("show"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear the URL of the search page before submitting request
|
|
||||||
fn search() {
|
|
||||||
if let Some(form) = document().get_element_by_id("form") {
|
|
||||||
form.add_event_listener(|_: SubmitEvent| {
|
|
||||||
document()
|
|
||||||
.query_selector_all("#form input")
|
|
||||||
.map(|inputs| {
|
|
||||||
for input in inputs {
|
|
||||||
js! {
|
|
||||||
if (@{&input}.name === "") {
|
|
||||||
@{&input}.name = @{&input}.id
|
|
||||||
}
|
|
||||||
if (@{&input}.name && !@{&input}.value) {
|
|
||||||
@{&input}.name = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.ok();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,4 +3,4 @@ mkdir bin
|
|||||||
cp target/release/{plume,plm} bin
|
cp target/release/{plume,plm} bin
|
||||||
strip -s bin/*
|
strip -s bin/*
|
||||||
tar -cvzf plume.tar.gz bin/ static/
|
tar -cvzf plume.tar.gz bin/ static/
|
||||||
tar -cvzf wasm.tar.gz static/plume-front.{js,wasm}
|
tar -cvzf wasm.tar.gz static/plume_front{.js,_bg.wasm}
|
||||||
|
4
script/plume-front.sh
Normal file → Executable file
4
script/plume-front.sh
Normal file → Executable file
@ -21,7 +21,7 @@ EOF
|
|||||||
if [ $ARCH == "aarch64" -o $ARCH == "armv71" ] ; then
|
if [ $ARCH == "aarch64" -o $ARCH == "armv71" ] ; then
|
||||||
export PATH=/opt/local/llvm/bin:${PATH}
|
export PATH=/opt/local/llvm/bin:${PATH}
|
||||||
cd /app
|
cd /app
|
||||||
RUSTFLAGS="-C linker=lld" cargo web deploy -p plume-front
|
RUSTFLAGS="-C linker=lld" wasm-pack build --target web --release plume-front
|
||||||
else
|
else
|
||||||
cargo web deploy -p plume-front
|
wasm-pack build --target web --release plume-front
|
||||||
fi
|
fi
|
||||||
|
@ -9,7 +9,7 @@ pkg="$4"
|
|||||||
build () {
|
build () {
|
||||||
features="$1"
|
features="$1"
|
||||||
cargo clean
|
cargo clean
|
||||||
cargo web deploy -p plume-front --release
|
wasm-pack build --target web --release plume-front
|
||||||
cargo build --release --no-default-features --features="${features}" --package=plume-cli
|
cargo build --release --no-default-features --features="${features}" --package=plume-cli
|
||||||
cargo build --release --no-default-features --features="${features}"
|
cargo build --release --no-default-features --features="${features}"
|
||||||
./script/generate_artifact.sh
|
./script/generate_artifact.sh
|
||||||
|
@ -38,17 +38,17 @@ parts:
|
|||||||
snapcraftctl set-version $(git describe --tags)
|
snapcraftctl set-version $(git describe --tags)
|
||||||
export PATH=$PATH:$HOME/.cargo/bin
|
export PATH=$PATH:$HOME/.cargo/bin
|
||||||
rustup install stable
|
rustup install stable
|
||||||
cargo +stable install --force cargo-web
|
cargo +stable install --force wasm-pack
|
||||||
|
|
||||||
# Only Tier 1 Rust platforms get rust-lld
|
# Only Tier 1 Rust platforms get rust-lld
|
||||||
# On the others (arm64, armhf, powerpc64, s390x) fall back to using
|
# On the others (arm64, armhf, powerpc64, s390x) fall back to using
|
||||||
# the system LLD we've installed earlier.
|
# the system LLD we've installed earlier.
|
||||||
case ${SNAPCRAFT_ARCH_TRIPLET} in \
|
case ${SNAPCRAFT_ARCH_TRIPLET} in \
|
||||||
aarch64-linux-gnu|arm-linux-gnueabihf|powerpc64-linux-gnu|s390x-linux-gnu) \
|
aarch64-linux-gnu|arm-linux-gnueabihf|powerpc64-linux-gnu|s390x-linux-gnu) \
|
||||||
RUSTFLAGS="-C linker=lld-8" cargo web deploy -p plume-front --release \
|
RUSTFLAGS="-C linker=lld" wasm-pack build --target web --release plume-front \
|
||||||
;; \
|
;; \
|
||||||
*) \
|
*) \
|
||||||
cargo web deploy -p plume-front --release \
|
wasm-pack build --target web --release plume-front \
|
||||||
;; \
|
;; \
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
@ -21,9 +21,9 @@
|
|||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
<nav id="menu">
|
<nav id="menu">
|
||||||
<a href="#" aria-label="@i18n!(ctx.1, "Menu")" title="@i18n!(ctx.1, "Menu")"><i class="icon icon-menu"></i></a>
|
<a href="#" aria-label="@i18n!(ctx.1, "Menu")" title="@i18n!(ctx.1, "Menu")" role="button" aria-haspopup="true" aria-controls="content" aria-epanded="false"><i class="icon icon-menu"></i></a>
|
||||||
</nav>
|
</nav>
|
||||||
<div id="content">
|
<div id="content" role="menu" aria-labelled-by="menu">
|
||||||
<nav>
|
<nav>
|
||||||
<a href="@uri!(instance::index)" class="title">
|
<a href="@uri!(instance::index)" class="title">
|
||||||
<img src="@uri!(plume_static_files: file = CONFIG.logo.main.as_str(), build_id = CACHE_NAME)">
|
<img src="@uri!(plume_static_files: file = CONFIG.logo.main.as_str(), build_id = CACHE_NAME)">
|
||||||
@ -96,6 +96,9 @@
|
|||||||
<a href="https://matrix.to/#/#plume-blog:matrix.org">@i18n!(ctx.1, "Matrix room")</a>
|
<a href="https://matrix.to/#/#plume-blog:matrix.org">@i18n!(ctx.1, "Matrix room")</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<script src="@uri!(plume_static_files: file = "plume-front.js", build_id = CACHE_NAME)"></script>
|
<script type="module">
|
||||||
|
import init from '@uri!(plume_static_files: file = "plume_front.js", build_id = CACHE_NAME)';
|
||||||
|
(async () => await init())();
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<small class="p-nickname">@user.fqn</small>
|
<small class="p-nickname">@user.fqn</small>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p>
|
<p class="grow">
|
||||||
@if user.is_admin() {
|
@if user.is_admin() {
|
||||||
<span class="badge">@i18n!(ctx.1, "Admin")</span>
|
<span class="badge">@i18n!(ctx.1, "Admin")</span>
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user