-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy pathmain.rs
More file actions
124 lines (113 loc) · 4.17 KB
/
main.rs
File metadata and controls
124 lines (113 loc) · 4.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
extern crate base64;
use std::collections::HashMap;
use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use gloo::file::callbacks::FileReader;
use web_sys::{DragEvent, Event, HtmlInputElement};
use yew::html::TargetCast;
use yew::{Callback, Component, Context, Html, html};
pub struct FileDetails {
name: String,
file_type: String,
data: Vec<u8>,
}
pub enum Msg {
Loaded(FileDetails),
Files(Option<web_sys::FileList>),
}
pub struct App {
readers: HashMap<String, FileReader>,
files: Vec<FileDetails>,
}
impl Component for App {
type Message = Msg;
type Properties = ();
fn create(_ctx: &Context<Self>) -> Self {
Self {
readers: HashMap::default(),
files: Vec::default(),
}
}
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
match msg {
Msg::Loaded(file) => {
self.readers.remove(&file.name);
self.files.push(file);
true
}
Msg::Files(files) => {
for file in gloo::file::FileList::from(files.expect("files")).iter() {
let link = ctx.link().clone();
let name = file.name().clone();
let file_type = file.raw_mime_type();
let task = {
gloo::file::callbacks::read_as_bytes(file, move |res| {
link.send_message(Msg::Loaded(FileDetails {
data: res.expect("failed to read file"),
file_type,
name,
}))
})
};
self.readers.insert(file.name(), task);
}
true
}
}
}
fn view(&self, ctx: &Context<Self>) -> Html {
let noop_drag = Callback::from(|e: DragEvent| {
e.prevent_default();
});
html! {
<div id="wrapper">
<p id="title">{ "Upload Your Files To The Cloud" }</p>
<label for="file-upload">
<div
id="drop-container"
ondrop={ctx.link().callback(|event: DragEvent| {
event.prevent_default();
Msg::Files(event.data_transfer().unwrap().files())
})}
ondragover={&noop_drag}
ondragenter={&noop_drag}
>
<i class="fa fa-cloud-upload"></i>
<p>{"Drop your images here or click to select"}</p>
</div>
</label>
<input
id="file-upload"
type="file"
accept="image/*,video/*"
multiple={true}
onchange={ctx.link().callback(move |e: Event| {
let input: HtmlInputElement = e.target_unchecked_into();
Msg::Files(input.files())
})}
/>
<div id="preview-area">
for file in &self.files {
let file_type = file.file_type.to_string();
let src = format!("data:{};base64,{}", file_type, STANDARD.encode(&file.data));
<div class="preview-tile">
<p class="preview-name">{ &file.name }</p>
<div class="preview-media">
if file.file_type.contains("image") {
<img src={src} />
} else if file.file_type.contains("video") {
<video controls={true}>
<source src={src} type={ file_type }/>
</video>
}
</div>
</div>
}
</div>
</div>
}
}
}
fn main() {
yew::Renderer::<App>::new().render();
}