Commit 5b9ef0e36746ad99245c953001fe9a2d4c7c0233

Authored by Georg Hopp
1 parent b3ee7df8

Get preview and file info from file selector

1 1 .markdown {
2   - float: left;
3   - padding: 1em;
4   - border-radius: .5em;
5   - border: 1px solid #ddd;
6   - background: #f7f7f7;
  2 + float: left;
  3 + padding: 1em;
  4 + border-radius: .5em;
  5 + border: 1px solid #ddd;
  6 + background: #f7f7f7;
7 7 }
8 8
9 9 .markdown p {
10   - text-align: justify;
11   - text-indent: .5em;
12   - margin-block: .5em;
  10 + text-align: justify;
  11 + text-indent: .5em;
  12 + margin-block: .5em;
13 13 }
14 14
15 15 .markdown > div:first-child {
16   - position: fixed;
  16 + position: fixed;
17 17 width: inherit;
18 18 z-index: 10;
19 19 }
20 20
21 21 .markdown > div:first-child > div {
22 22 position: relative;
23   - left: .5em;
  23 + left: .5em;
24 24 width: inherit;
25 25 }
26 26
27 27 .markdown > div:first-child > pre {
28   - white-space: pre-wrap;
29   - height: 15em;
  28 + white-space: pre-wrap;
  29 + height: 15em;
30 30 width: calc(100% - 10px);
31   - overflow-y: auto;
32   - overflow-x: hidden;
33   - background: #ffffff;
34   - border-radius: .35em;
35   - border: 2px solid #bbb;
36   - margin: 2px 0px;
  31 + overflow-y: auto;
  32 + overflow-x: hidden;
  33 + background: #ffffff;
  34 + border-radius: .35em;
  35 + border: 2px solid #bbb;
  36 + margin: 2px 0px;
37 37 opacity: .95;
38 38 }
39 39
40 40 .markdown > div:first-child > div > div {
41   - display: inline;
  41 + display: inline;
42 42 }
43 43
44 44 .markdown > div:first-child > div ul {
45   - height: 15em;
46   - list-style-type: none;
47   - margin: 2px 0px;
48   - overflow-y: auto;
49   - padding-left: 0px;
50   - position: absolute;
51   - scroll-behavior: auto;
52   - top: 1.8em;
  45 + height: 15em;
  46 + list-style-type: none;
  47 + margin: 2px 0px;
  48 + overflow-y: auto;
  49 + padding-left: 0px;
  50 + position: absolute;
  51 + scroll-behavior: auto;
  52 + top: 1.8em;
53 53 }
54 54
55 55 .markdown blockquote {
56   - border-left: 5px solid #ccc;
57   - margin: .5em 10px;
58   - padding: .5em 10px;
  56 + border-left: 5px solid #ccc;
  57 + margin: .5em 10px;
  58 + padding: .5em 10px;
59 59 }
60 60
61 61 .markdown blockquote p {
62   - text-align: left;
63   - text-indent: 0;
64   - margin-block: 0;
  62 + text-align: left;
  63 + text-indent: 0;
  64 + margin-block: 0;
65 65 }
66 66
67 67 .markdown .footnote-definition > * {
68   - display: inline;
  68 + display: inline;
  69 +}
  70 +
  71 +@keyframes spinner {
  72 + 0% {
  73 + transform: translate3d(-50%, -50%, 0) rotate(0deg);
  74 + }
  75 + 100% {
  76 + transform: translate3d(-50%, -50%, 0) rotate(360deg);
  77 + }
  78 +}
  79 +
  80 +.spin::before {
  81 + animation: 1.5s linear infinite spinner;
  82 + animation-play-state: inherit;
  83 + border: solid 5px #cfd0d1;
  84 + border-bottom-color: #1c87c9;
  85 + border-radius: 50%;
  86 + content: "";
  87 + height: 1.5em;
  88 + width: 1.5em;
  89 + position: absolute;
  90 + top: 10%;
  91 + left: 1.5em;
  92 + transform: translate3d(-50%, -50%, 0);
  93 + will-change: transform;
69 94 }
... ...
... ... @@ -36,20 +36,28 @@ version = "^0.5"
36 36 [dependencies.web-sys]
37 37 version = "^0.3"
38 38 features = [
39   - "Document",
40   - "DomParser",
41   - "Headers",
42   - "HtmlElement",
43   - "HtmlInputElement",
44   - "MouseEvent",
45   - "Node",
46   - "Request",
47   - "RequestInit",
48   - "RequestMode",
49   - "Response",
50   - "SupportedType",
51   - "Window",
52   -]
  39 + "Blob",
  40 + "CanvasRenderingContext2d",
  41 + "Document",
  42 + "DomParser",
  43 + "File",
  44 + "FileList",
  45 + "FileReader",
  46 + "ImageBitmap",
  47 + "Headers",
  48 + "HtmlCanvasElement",
  49 + "HtmlElement",
  50 + "HtmlInputElement",
  51 + "MouseEvent",
  52 + "Node",
  53 + "ReadableStream",
  54 + "Request",
  55 + "RequestInit",
  56 + "RequestMode",
  57 + "Response",
  58 + "SupportedType",
  59 + "Window",
  60 + ]
53 61
54 62 [dev-dependencies]
55 63 wasm-bindgen-test = "0.2"
... ...
1 1 pub(crate) mod markdown;
  2 +pub(crate) mod upload;
... ...
  1 +use mogwai::prelude::*;
  2 +use web_sys::{HtmlInputElement, window, ImageBitmap, HtmlCanvasElement, CanvasRenderingContext2d};
  3 +
  4 +use crate::component::upload::view::upload_preview_view;
  5 +
  6 +async fn upload_preview_logic( mut rx_canvas :broadcast::Receiver<Dom>
  7 + , bitmap :ImageBitmap ) {
  8 + while let Some(dom) = rx_canvas.next().await {
  9 + match dom.inner_read() {
  10 + Either::Left(c) => {
  11 + let canvas = c.to_owned().dyn_into::<HtmlCanvasElement>().unwrap();
  12 + let context = canvas
  13 + . get_context("2d").unwrap().unwrap()
  14 + . dyn_into::<CanvasRenderingContext2d>().unwrap();
  15 + context . draw_image_with_image_bitmap_and_dw_and_dh( &bitmap
  16 + , 0.0, 0.0
  17 + , 100.0, 100.0 )
  18 + . unwrap();
  19 + },
  20 + _ => (),
  21 + }
  22 + }
  23 +}
  24 +
  25 +pub(super) async fn upload_logic( mut rx_logic: broadcast::Receiver<DomEvent>
  26 + , tx_previews: mpmc::Sender<ListPatch<ViewBuilder<Dom>>>
  27 + ) {
  28 + while let Some(msg) = rx_logic.next().await {
  29 + match msg.clone_inner() {
  30 + Either::Left(val) => {
  31 + let event = val.dyn_into::<Event>().unwrap();
  32 + let target = event.target().unwrap();
  33 + let element = target.dyn_into::<HtmlInputElement>().unwrap();
  34 + let filelist = element.files().unwrap();
  35 +
  36 + let mut previews = vec![];
  37 + for index in 0..filelist.length() {
  38 + let (tx_canvas, rx_canvas) = broadcast::bounded(1);
  39 + let file = filelist.item(index).unwrap();
  40 + let bitmap =
  41 + JsFuture::from( window().unwrap()
  42 + . create_image_bitmap_with_blob(&file.clone().into()).unwrap());
  43 + let bitmap = bitmap
  44 + . await.unwrap()
  45 + . dyn_into::<ImageBitmap>().unwrap();
  46 +
  47 + let view = upload_preview_view( tx_canvas
  48 + , file.name()
  49 + , file.size()
  50 + , file.type_()
  51 + , file.last_modified() );
  52 + let logic = upload_preview_logic(rx_canvas, bitmap);
  53 +
  54 + previews.push(Component::from(view).with_logic(logic).into());
  55 + }
  56 + let previews = ListPatch::splice(.., previews.into_iter());
  57 + tx_previews.send(previews).await.unwrap();
  58 + },
  59 + _ => (),
  60 + }
  61 + }
  62 +}
... ...
  1 +mod view;
  2 +mod logic;
  3 +
  4 +use mogwai::prelude::*;
  5 +
  6 +use self::{view::upload_view, logic::upload_logic};
  7 +
  8 +pub(crate) async fn new() -> Component<Dom> {
  9 + let (tx_logic, rx_logic) = broadcast::bounded(1);
  10 + let (tx_previews, rx_previews) = mpmc::bounded(1);
  11 +
  12 + let view = upload_view(tx_logic, rx_previews);
  13 + let logic = upload_logic(rx_logic, tx_previews);
  14 +
  15 + Component::from(view).with_logic(logic)
  16 +}
... ...
  1 +use mogwai::prelude::*;
  2 +
  3 +pub(super) fn upload_preview_view( tx_canvas :broadcast::Sender<Dom>
  4 + , filename :String
  5 + , size :f64
  6 + , mime_type :String
  7 + , mtime :f64 ) -> ViewBuilder<Dom> {
  8 + let post_build = move |dom: &mut Dom| {
  9 + tx_canvas.try_broadcast(dom.clone()).unwrap();
  10 + };
  11 +
  12 + builder! {
  13 + <li style:display="flex">
  14 + <div style:width="100px"
  15 + style:height="100px">
  16 + <canvas post:build=post_build />
  17 + </div>
  18 + <div style:width="fit-content">
  19 + <ul>
  20 + <li>{format!("filename: {}", filename)}</li>
  21 + <li>{format!("size: {}", size)}</li>
  22 + <li>{format!("mime type: {}", mime_type)}</li>
  23 + <li>{format!("modification time: {}", mtime)}</li>
  24 + </ul>
  25 + </div>
  26 + </li>
  27 + }
  28 +}
  29 +
  30 +pub(super) fn upload_view( tx_logic: broadcast::Sender<DomEvent>
  31 + , rx_previews: mpmc::Receiver<ListPatch<ViewBuilder<Dom>>>
  32 + ) -> ViewBuilder<Dom> {
  33 + builder! {
  34 + <div class="upload">
  35 + <div class="spin"></div>
  36 + <div>
  37 + <input type="file"
  38 + multiple="multiple"
  39 + accept="image/*"
  40 + on:change=tx_logic.sink()/>
  41 + </div>
  42 + <ul patch:children=rx_previews>
  43 + </ul>
  44 + </div>
  45 + }
  46 +}
... ...
... ... @@ -6,7 +6,7 @@ mod component;
6 6
7 7 use std::panic;
8 8
9   -use crate::component::markdown;
  9 +use crate::component::*;
10 10 use log::Level;
11 11 use mogwai::prelude::*;
12 12 use wasm_bindgen::prelude::*;
... ... @@ -16,8 +16,14 @@ pub async fn main() -> Result<(), JsValue> {
16 16 panic::set_hook(Box::new(console_error_panic_hook::hook));
17 17 console_log::init_with_level(Level::Trace).unwrap();
18 18
19   - let comp = markdown::new().await;
  19 + let md = markdown::new().await;
  20 + let comp = upload::new().await;
20 21
21   - let page = Component::from(builder! {{comp}});
  22 + let page = Component::from(builder! {
  23 + <div>
  24 + {comp}
  25 + {md}
  26 + </div>
  27 + });
22 28 page.build()?.run()
23 29 }
... ...
Please register or login to post a comment