From 8543d2d61fbafde6222e9b95f9604b41570db477 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Wed, 20 Jul 2022 16:26:08 +0800 Subject: Switch to `qrcode` lib --- src/renderer.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'src/renderer.rs') diff --git a/src/renderer.rs b/src/renderer.rs index 7ec48b0..48b74b6 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -3,6 +3,7 @@ use chrono::{DateTime, Utc}; use chrono_humanize::Humanize; use clap::{crate_name, crate_version}; use maud::{html, Markup, PreEscaped, DOCTYPE}; +use qrcode::QrCode; use std::time::SystemTime; use strum::IntoEnumIterator; @@ -224,6 +225,45 @@ pub fn raw(entries: Vec, is_root: bool) -> Markup { } } +/// Renders the QR code page +pub fn qr_code_page(qr: &QrCode) -> Markup { + use qrcode::render::svg; + + html! { + (DOCTYPE) + html { + body { + // make QR code expand and fill page + style { + (PreEscaped("\ + html {\ + width: 100vw;\ + height: 100vh;\ + }\ + body {\ + width: 100%;\ + height: 100%;\ + margin: 0;\ + display: grid;\ + align-items: center;\ + justify-items: center;\ + }\ + svg {\ + width: 80%;\ + height: 80%;\ + }\ + ")) + } + (PreEscaped(qr.render() + .quiet_zone(false) + .dark_color(svg::Color("#000000")) + .light_color(svg::Color("#ffffff")) + .build())) + } + } + } +} + // Partial: version footer fn version_footer() -> Markup { html! { -- cgit v1.2.3 From c2ece55040d4f1f03e189636895645435d762322 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Wed, 20 Jul 2022 20:09:55 +0800 Subject: Fix tests --- src/renderer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/renderer.rs') diff --git a/src/renderer.rs b/src/renderer.rs index 48b74b6..95aeb5f 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -232,7 +232,7 @@ pub fn qr_code_page(qr: &QrCode) -> Markup { html! { (DOCTYPE) html { - body { + body.qr_code_page { // make QR code expand and fill page style { (PreEscaped("\ -- cgit v1.2.3 From a99d8bdcadf4f822bb86a2710e5d73783ac7097a Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Tue, 26 Jul 2022 12:27:14 +0800 Subject: Move QR code page style to `style.scss` --- src/renderer.rs | 47 +++++++++++++++++------------------------------ 1 file changed, 17 insertions(+), 30 deletions(-) (limited to 'src/renderer.rs') diff --git a/src/renderer.rs b/src/renderer.rs index 95aeb5f..0154ce0 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -18,7 +18,7 @@ pub fn page( readme: Option<(String, String)>, is_root: bool, query_params: QueryParameters, - breadcrumbs: Vec, + breadcrumbs: &[Breadcrumb], encoded_dir: &str, conf: &MiniserveConfig, current_user: Option<&CurrentUser>, @@ -34,11 +34,7 @@ pub fn page( let upload_action = build_upload_action(&upload_route, encoded_dir, sort_method, sort_order); let mkdir_action = build_mkdir_action(&upload_route, encoded_dir); - let title_path = breadcrumbs - .iter() - .map(|el| el.name.clone()) - .collect::>() - .join("/"); + let title_path = breadcrumbs_to_path_string(breadcrumbs); html! { (DOCTYPE) @@ -226,34 +222,16 @@ pub fn raw(entries: Vec, is_root: bool) -> Markup { } /// Renders the QR code page -pub fn qr_code_page(qr: &QrCode) -> Markup { +pub fn qr_code_page(breadcrumbs: &[Breadcrumb], qr: &QrCode, conf: &MiniserveConfig) -> Markup { use qrcode::render::svg; + let title = breadcrumbs_to_path_string(breadcrumbs); + html! { (DOCTYPE) - html { - body.qr_code_page { - // make QR code expand and fill page - style { - (PreEscaped("\ - html {\ - width: 100vw;\ - height: 100vh;\ - }\ - body {\ - width: 100%;\ - height: 100%;\ - margin: 0;\ - display: grid;\ - align-items: center;\ - justify-items: center;\ - }\ - svg {\ - width: 80%;\ - height: 80%;\ - }\ - ")) - } + html.qr_code_page { + (page_header(&title, false, &conf.favicon_route, &conf.css_route)) + body { (PreEscaped(qr.render() .quiet_zone(false) .dark_color(svg::Color("#000000")) @@ -264,6 +242,15 @@ pub fn qr_code_page(qr: &QrCode) -> Markup { } } +/// Build a path string from a list of breadcrumbs. +fn breadcrumbs_to_path_string(breadcrumbs: &[Breadcrumb]) -> String { + breadcrumbs + .iter() + .map(|el| el.name.clone()) + .collect::>() + .join("/") +} + // Partial: version footer fn version_footer() -> Markup { html! { -- cgit v1.2.3 From 9f7d5a8aeaf252fb51d88b965b3a324e8e815f37 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Thu, 1 Sep 2022 19:37:39 +0800 Subject: Fix drop-down QR code --- src/renderer.rs | 95 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 57 insertions(+), 38 deletions(-) (limited to 'src/renderer.rs') diff --git a/src/renderer.rs b/src/renderer.rs index 0154ce0..614672f 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -2,12 +2,15 @@ use actix_web::http::StatusCode; use chrono::{DateTime, Utc}; use chrono_humanize::Humanize; use clap::{crate_name, crate_version}; +use lazy_static::lazy_static; use maud::{html, Markup, PreEscaped, DOCTYPE}; -use qrcode::QrCode; +use qrcode::{types::QrError, QrCode}; +use regex::Regex; use std::time::SystemTime; use strum::IntoEnumIterator; use crate::auth::CurrentUser; +use crate::consts; use crate::listing::{Breadcrumb, Entry, QueryParameters, SortingMethod, SortingOrder}; use crate::{archive::ArchiveMethod, MiniserveConfig}; @@ -16,6 +19,7 @@ use crate::{archive::ArchiveMethod, MiniserveConfig}; pub fn page( entries: Vec, readme: Option<(String, String)>, + abs_url: impl AsRef, is_root: bool, query_params: QueryParameters, breadcrumbs: &[Breadcrumb], @@ -86,7 +90,10 @@ pub fn page( } } } - (color_scheme_selector(conf.show_qrcode, conf.hide_theme_selector)) + nav { + (qr_spoiler(conf.show_qrcode, abs_url)) + (color_scheme_selector(conf.hide_theme_selector)) + } div.container { span #top { } h1.title dir="ltr" { @@ -221,25 +228,30 @@ pub fn raw(entries: Vec, is_root: bool) -> Markup { } } -/// Renders the QR code page -pub fn qr_code_page(breadcrumbs: &[Breadcrumb], qr: &QrCode, conf: &MiniserveConfig) -> Markup { +/// Renders the QR code SVG +fn qr_code_svg(url: impl AsRef, no_width_height_attr: bool) -> Result { use qrcode::render::svg; - - let title = breadcrumbs_to_path_string(breadcrumbs); - - html! { - (DOCTYPE) - html.qr_code_page { - (page_header(&title, false, &conf.favicon_route, &conf.css_route)) - body { - (PreEscaped(qr.render() - .quiet_zone(false) - .dark_color(svg::Color("#000000")) - .light_color(svg::Color("#ffffff")) - .build())) - } + let qr = QrCode::with_error_correction_level(url.as_ref(), consts::QR_EC_LEVEL)?; + let mut svg = qr + .render() + .quiet_zone(false) + .dark_color(svg::Color("#000000")) + .light_color(svg::Color("#ffffff")) + .build(); + + if no_width_height_attr { + // HACK: qrcode crate hard-codes height and width into SVG's attributes. + // This behaviour may be undesirable because we want it to fit its HTML container. + // The proper way to remove them is to use a XML parser, but regex is good enough for a + // simple case like this. + lazy_static! { + static ref RE: Regex = + Regex::new(r#"(?P.+?>)"#).unwrap(); } + svg = RE.replace(&svg, "$front$aft").to_string(); } + + Ok(svg) } /// Build a path string from a list of breadcrumbs. @@ -317,30 +329,37 @@ const THEME_PICKER_CHOICES: &[(&str, &str)] = &[ pub const THEME_SLUGS: &[&str] = &["squirrel", "archlinux", "zenburn", "monokai"]; -/// Partial: color scheme selector -fn color_scheme_selector(show_qrcode: bool, hide_theme_selector: bool) -> Markup { +/// Partial: qr code spoiler +fn qr_spoiler(show_qrcode: bool, content: impl AsRef) -> Markup { html! { - nav { - @if show_qrcode { - div { - p onmouseover="document.querySelector('#qrcode').src = `?qrcode=${encodeURIComponent(window.location.href)}`" { - "QR code" - } - div.qrcode { - img #qrcode alt="QR code" title="QR code of this page"; + @if show_qrcode { + div { + p { + "QR code" + } + div.qrcode #qrcode { + @match qr_code_svg(content, true) { + Ok(svg) => (PreEscaped(svg)), + Err(err) => (format!("QR generation error: {}", err)), } } } - @if !hide_theme_selector { - div { - p { - "Change theme..." - } - ul.theme { - @for color_scheme in THEME_PICKER_CHOICES { - li.(format!("theme_{}", color_scheme.1)) { - (color_scheme_link(color_scheme)) - } + } + } +} + +/// Partial: color scheme selector +fn color_scheme_selector(hide_theme_selector: bool) -> Markup { + html! { + @if !hide_theme_selector { + div { + p { + "Change theme..." + } + ul.theme { + @for color_scheme in THEME_PICKER_CHOICES { + li.(format!("theme_{}", color_scheme.1)) { + (color_scheme_link(color_scheme)) } } } -- cgit v1.2.3 From aa2dda7885a83354d1519eef62397b90189a9802 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Thu, 1 Sep 2022 20:20:27 +0800 Subject: Switch to `fast_qr` crate --- src/renderer.rs | 36 ++++++++++-------------------------- 1 file changed, 10 insertions(+), 26 deletions(-) (limited to 'src/renderer.rs') diff --git a/src/renderer.rs b/src/renderer.rs index 614672f..77b9eed 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -2,10 +2,10 @@ use actix_web::http::StatusCode; use chrono::{DateTime, Utc}; use chrono_humanize::Humanize; use clap::{crate_name, crate_version}; -use lazy_static::lazy_static; +use fast_qr::convert::svg::SvgBuilder; +use fast_qr::qr::QRCodeError; +use fast_qr::QRBuilder; use maud::{html, Markup, PreEscaped, DOCTYPE}; -use qrcode::{types::QrError, QrCode}; -use regex::Regex; use std::time::SystemTime; use strum::IntoEnumIterator; @@ -229,27 +229,11 @@ pub fn raw(entries: Vec, is_root: bool) -> Markup { } /// Renders the QR code SVG -fn qr_code_svg(url: impl AsRef, no_width_height_attr: bool) -> Result { - use qrcode::render::svg; - let qr = QrCode::with_error_correction_level(url.as_ref(), consts::QR_EC_LEVEL)?; - let mut svg = qr - .render() - .quiet_zone(false) - .dark_color(svg::Color("#000000")) - .light_color(svg::Color("#ffffff")) - .build(); - - if no_width_height_attr { - // HACK: qrcode crate hard-codes height and width into SVG's attributes. - // This behaviour may be undesirable because we want it to fit its HTML container. - // The proper way to remove them is to use a XML parser, but regex is good enough for a - // simple case like this. - lazy_static! { - static ref RE: Regex = - Regex::new(r#"(?P.+?>)"#).unwrap(); - } - svg = RE.replace(&svg, "$front$aft").to_string(); - } +fn qr_code_svg(url: impl AsRef, margin: usize) -> Result { + let qr = QRBuilder::new(url.as_ref().into()) + .ecl(consts::QR_EC_LEVEL) + .build()?; + let svg = SvgBuilder::new().margin(margin).build_qr(qr); Ok(svg) } @@ -338,9 +322,9 @@ fn qr_spoiler(show_qrcode: bool, content: impl AsRef) -> Markup { "QR code" } div.qrcode #qrcode { - @match qr_code_svg(content, true) { + @match qr_code_svg(content, 1) { Ok(svg) => (PreEscaped(svg)), - Err(err) => (format!("QR generation error: {}", err)), + Err(err) => (format!("QR generation error: {:?}", err)), } } } -- cgit v1.2.3 From 044f30c550888429cf8a9d39ef1a282ff3385e09 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Thu, 1 Sep 2022 21:10:30 +0800 Subject: Move QR margin size into `consts` --- src/renderer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/renderer.rs') diff --git a/src/renderer.rs b/src/renderer.rs index 77b9eed..562f215 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -322,7 +322,7 @@ fn qr_spoiler(show_qrcode: bool, content: impl AsRef) -> Markup { "QR code" } div.qrcode #qrcode { - @match qr_code_svg(content, 1) { + @match qr_code_svg(content, consts::SVG_QR_MARGIN) { Ok(svg) => (PreEscaped(svg)), Err(err) => (format!("QR generation error: {:?}", err)), } -- cgit v1.2.3 From 2d63d3d7a25483293789546a347f6235ef0aea67 Mon Sep 17 00:00:00 2001 From: cyqsimon <28627918+cyqsimon@users.noreply.github.com> Date: Thu, 15 Sep 2022 19:54:50 +0800 Subject: Add tooltip on QR code --- src/renderer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/renderer.rs') diff --git a/src/renderer.rs b/src/renderer.rs index 562f215..ebb9f6f 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -321,7 +321,7 @@ fn qr_spoiler(show_qrcode: bool, content: impl AsRef) -> Markup { p { "QR code" } - div.qrcode #qrcode { + div.qrcode #qrcode title=(PreEscaped(content.as_ref())) { @match qr_code_svg(content, consts::SVG_QR_MARGIN) { Ok(svg) => (PreEscaped(svg)), Err(err) => (format!("QR generation error: {:?}", err)), -- cgit v1.2.3