Skip to content

Commit

Permalink
feat: preview file link in upload result
Browse files Browse the repository at this point in the history
  • Loading branch information
msyfls123 committed Apr 24, 2024
1 parent ba45b5e commit 58fd28f
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 23 deletions.
67 changes: 47 additions & 20 deletions client/src/component/uploader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use serde_wasm_bindgen::from_value;
use wasm_bindgen_futures::{spawn_local, JsFuture};
use web_sys::{console, Event, HtmlInputElement};
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
use yew::{ html, prelude::function_component, use_callback, use_context, use_memo, use_state, Callback, Html, Properties};
use yew::{ html, prelude::function_component, use_callback, use_context, use_memo, use_state, Callback, Html, Properties, UseStateHandle};
use js_sys::{Promise, JSON::stringify_with_replacer_and_space};
use serde_json::{Value};
use serde::{Deserialize};
Expand All @@ -15,6 +15,11 @@ pub struct Progress {
total: Value
}

#[derive(Deserialize, PartialEq, Clone)]
pub struct UploadResult {
Location: Value,
}

#[derive(Properties, PartialEq)]
pub struct UploaderProps {
pub on_upload_start: Callback<()>,
Expand All @@ -27,9 +32,11 @@ pub fn uploader(props: &UploaderProps) -> Html {
let app_ctx = use_context::<AppContext>().expect("no ctx found");
let cos_upload = app_ctx.upload_file;
// state
let upload_result = use_state(|| None);
let upload_result: UseStateHandle<Option<JsValue>> = use_state(|| None);
let is_uploading = use_state(|| false);
let filename = use_state(|| None);
let progress = use_state(|| 0f64);
// computed
let percentage = use_memo(progress.clone(), |progress| {
let progress = *progress.clone();
format!("{:.1}%", progress * 100.0f64)
Expand All @@ -38,12 +45,26 @@ pub fn uploader(props: &UploaderProps) -> Html {
let progress = *progress.clone();
format!("--percentage: {:.1};", progress * 100.0f64)
});
let location = use_memo(upload_result.clone(), |res| {
match res.as_ref() {
Some(v) => {
let parsed: UploadResult = from_value(v.to_owned()).unwrap();
"https://".to_string() + parsed.Location.as_str().unwrap_or_default()
},
None => "".to_string()
}
});
// callbacks
let upload_start = use_callback(
(props.on_upload_start.clone(), is_uploading.clone()),
move |_, (on_start, uploading)| {
(props.on_upload_start.clone(), is_uploading.clone(), filename.clone()),
move |e: Event, (on_start, uploading, filename)| {
on_start.emit(());
uploading.set(true);

let target = e.target().unwrap();
let input_el: HtmlInputElement = target.dyn_into().unwrap();
let option_file = input_el.files().unwrap().item(0);
filename.set(option_file.map(|file| file.name()));
}
);
let upload_end = use_callback(
Expand All @@ -57,7 +78,7 @@ pub fn uploader(props: &UploaderProps) -> Html {
let on_upload = use_callback(
(upload_end.clone(), progress.clone()),
move |e: Event, (upload_cb, progress_state)| {
upload_start.emit(());
upload_start.emit(e.clone());

let progress_state = progress_state.clone();
let closure = Closure::wrap(Box::new(move |payload: JsValue| {
Expand Down Expand Up @@ -99,13 +120,17 @@ pub fn uploader(props: &UploaderProps) -> Html {

html! {
<div class="upload-item">


{if let Some(data) = upload_result.as_ref() {
let upload_text = stringify_with_replacer_and_space(&data, &JsValue::NULL, &JsValue::from_f64(4.0)).unwrap();
html! { <div>
{ "Upload success" }
<pre>{upload_text.as_string().unwrap_or_default()}</pre>
{if let Some(_) = upload_result.as_ref() {
// let upload_text = stringify_with_replacer_and_space(&data, &JsValue::NULL, &JsValue::from_f64(4.0)).unwrap();
html! { <div class="file-link">
<i class="icon-success fa-solid fa-check"></i>
<a target="_blank" href={<std::string::String as Clone>::clone(&location)}>
{if let Some(name) = filename.as_ref() {
html!{ <span> {{ name }} </span> }
} else {
html!{ <span> {"[Untitled]"} </span> }
}}
</a>
</div> }
} else if *is_uploading {
html! {
Expand Down Expand Up @@ -136,14 +161,16 @@ pub fn uploader(props: &UploaderProps) -> Html {
}
} else {
html! {
<input type="file" onchange={move |e: Event| {
let target = e.target().unwrap();
let input_el: HtmlInputElement = target.dyn_into().unwrap();
let option_file = input_el.files().unwrap().item(0);
if let Some(file) = option_file {
on_upload.emit(e)
}
}} />
<div class="upload-input">
<input type="file" onchange={move |e: Event| {
let target = e.target().unwrap();
let input_el: HtmlInputElement = target.dyn_into().unwrap();
let option_file = input_el.files().unwrap().item(0);
if let Some(file) = option_file {
on_upload.emit(e)
}
}} />
</div>
}
}}
</div>
Expand Down
1 change: 0 additions & 1 deletion client/src/container/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ impl Component for HomeInner {
<h2>{"Upload"}</h2>
{ list.into_iter().map(|i| html! {
<div key={i.clone()}>
{i.clone()}
<Uploader
on_upload_start={upload_start.clone()}
on_upload_end={upload_end.clone()}
Expand Down
15 changes: 13 additions & 2 deletions client/src/css/index.styl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

:root
--success: #30C157
--blue: #0067e5
nav
a
margin: 20px
Expand Down Expand Up @@ -26,7 +28,7 @@ body
max-width: 290px
word-break: break-all
a
color: #0067e5
color: var(--blue)
text-decoration: none
&:hover
text-decoration: underline
Expand All @@ -37,6 +39,7 @@ body
.upload-item
margin: 10px 0
padding: 10px
max-width: 250px
border-width: thin
border-style: dashed
border-color: var(--grey-2_5, rgba(20,30,41,0.12))
Expand Down Expand Up @@ -82,3 +85,11 @@ body
stroke-dasharray: var(--circle)
stroke-dashoffset: calc(var(--circle) * (100 - var(--percentage)) / 100)
transition: all 0.5s ease-in-out
.file-link
display: flex
align-items: center
a, a:visited, a:active
color: var(--blue)
.icon-success
margin-right: 10px
color: var(--success)
1 change: 1 addition & 0 deletions server/templates/index.html.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bard</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" integrity="sha512-SnH5WK+bZxgPHs44uWIX+LLJAJ9/2PkPKZ5QiAj6Ta86w+fsb2TkcmfRyVX3pBnMFcV7oQPJkl9QevSCWr3W6A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
</head>
<body>
<h1>hello {{ name }}</h1>
Expand Down

0 comments on commit 58fd28f

Please sign in to comment.