♻️ Use of the SCSS variables to compute the width of the inner panels
This commit is contained in:
138
build.rs
138
build.rs
@@ -1,4 +1,5 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fmt::Display;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::{self, BufRead};
|
use std::io::{self, BufRead};
|
||||||
@@ -10,14 +11,32 @@ use regex::Regex;
|
|||||||
fn main() {
|
fn main() {
|
||||||
// Tell Cargo to rerun this build script if any SCSS file
|
// Tell Cargo to rerun this build script if any SCSS file
|
||||||
// in the 'src' directory or its subdirectories changes.
|
// in the 'src' directory or its subdirectories changes.
|
||||||
println!("cargo:rerun-if-changed=src/**/*.scss");
|
println!("cargo:rerun-if-changed=src/ui/**/*.scss");
|
||||||
|
|
||||||
let out_dir = env::var("OUT_DIR").unwrap();
|
let out_dir = env::var("OUT_DIR").unwrap();
|
||||||
|
|
||||||
let style_src_path = PathBuf::from("src/ui/_base.scss");
|
let mut tasks = Vec::new();
|
||||||
let style_dst_path = Path::new(&out_dir).join("style_vars.rs");
|
|
||||||
|
|
||||||
export_color_variables(&style_src_path, &style_dst_path)
|
// Global tokens
|
||||||
|
tasks.push(Task::new(
|
||||||
|
PathBuf::from("src/ui/_base.scss"),
|
||||||
|
Path::new(&out_dir).join("style_tokens.rs"),
|
||||||
|
"style".to_string(),
|
||||||
|
));
|
||||||
|
// variables defined by the Panel component
|
||||||
|
tasks.push(Task::new(
|
||||||
|
PathBuf::from("src/ui/components/_panel.scss"),
|
||||||
|
Path::new(&out_dir).join("style_component_panel.rs"),
|
||||||
|
"panel".to_string(),
|
||||||
|
));
|
||||||
|
// Variables set by the Conversations layout
|
||||||
|
tasks.push(Task::new(
|
||||||
|
PathBuf::from("src/ui/layouts/conversations.scss"),
|
||||||
|
Path::new(&out_dir).join("style_layout_conversations.rs"),
|
||||||
|
"conversations".to_string(),
|
||||||
|
));
|
||||||
|
|
||||||
|
export_variables(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
// From https://doc.rust-lang.org/rust-by-example/std_misc/file/read_lines.html
|
// From https://doc.rust-lang.org/rust-by-example/std_misc/file/read_lines.html
|
||||||
@@ -32,14 +51,21 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct CssColorVariable<'a> {
|
struct ColorVariable {
|
||||||
name: &'a str,
|
name: String,
|
||||||
value: &'a str,
|
value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CssColorVariable<'a> {
|
impl ColorVariable {
|
||||||
pub fn to_rust(&self) -> String {
|
pub fn new(name: String, value: String) -> Self {
|
||||||
format!(
|
Self { name, value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ColorVariable {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
"const {name}: &str = \"{value}\";",
|
"const {name}: &str = \"{value}\";",
|
||||||
name = self.name.replace('-', "_").to_uppercase(),
|
name = self.name.replace('-', "_").to_uppercase(),
|
||||||
value = self.value
|
value = self.value
|
||||||
@@ -47,35 +73,83 @@ impl<'a> CssColorVariable<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn export_color_variables(src_path: &PathBuf, dst_path: &PathBuf) {
|
#[derive(Debug)]
|
||||||
let mut dst_file = File::create(dst_path).unwrap();
|
struct FloatVariable {
|
||||||
if let Err(err) = dst_file.write(b"#[allow(dead_code)]\nmod style {") {
|
name: String,
|
||||||
println!("{}", err);
|
value: f64,
|
||||||
return;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let re = Regex::new(r"^\$([^:]+):[[:space:]]*#([^$]+);[[:space:]]*$").unwrap();
|
impl FloatVariable {
|
||||||
|
pub fn new(name: String, value: f64) -> Self {
|
||||||
|
Self { name, value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Ok(lines) = read_lines(src_path) {
|
impl Display for FloatVariable {
|
||||||
for line in lines.map_while(Result::ok) {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Some(groups) = re.captures(&line) else {
|
write!(
|
||||||
continue;
|
f,
|
||||||
};
|
"const {name}: f64 = {value};",
|
||||||
|
name = self.name.replace('-', "_").to_uppercase(),
|
||||||
|
value = self.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let var = CssColorVariable {
|
struct Task {
|
||||||
name: &groups[1],
|
src_path: PathBuf,
|
||||||
value: &groups[2],
|
dst_path: PathBuf,
|
||||||
};
|
module_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
let rust_export = var.to_rust();
|
impl Task {
|
||||||
if let Err(err) = dst_file.write_fmt(format_args!(" pub {}\n", rust_export)) {
|
pub fn new(src_path: PathBuf, dst_path: PathBuf, module_name: String) -> Self {
|
||||||
|
Self {
|
||||||
|
src_path,
|
||||||
|
dst_path,
|
||||||
|
module_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn export_variables(src_path: &PathBuf, dst_path: &PathBuf) {
|
||||||
|
fn export_variables(tasks: Vec<Task>) {
|
||||||
|
let color_re = Regex::new(r"^\$([^:]+):[[:space:]]*#([^$]+);[[:space:]]*$").unwrap();
|
||||||
|
let variable_re = Regex::new(r"^\$([^:]+):[[:space:]]*([^;]+)[[:space:]]*;").unwrap();
|
||||||
|
|
||||||
|
for task in tasks {
|
||||||
|
let mut dst_file = File::create(task.dst_path).unwrap();
|
||||||
|
if let Err(err) = dst_file.write_fmt(format_args!(
|
||||||
|
"#[allow(dead_code)]\nmod {} {{\n",
|
||||||
|
task.module_name
|
||||||
|
)) {
|
||||||
|
println!("{}", err);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut variables = Vec::<Box<dyn Display>>::new();
|
||||||
|
if let Ok(lines) = read_lines(task.src_path) {
|
||||||
|
for line in lines.map_while(Result::ok) {
|
||||||
|
if let Some(groups) = color_re.captures(&line) {
|
||||||
|
let var = ColorVariable::new(groups[1].to_string(), groups[2].to_string());
|
||||||
|
variables.push(Box::new(var));
|
||||||
|
} else if let Some(groups) = variable_re.captures(&line) {
|
||||||
|
if let Ok(value) = groups[2].parse::<f64>() {
|
||||||
|
variables.push(Box::new(FloatVariable::new(groups[1].to_string(), value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for variable in variables {
|
||||||
|
if let Err(err) = dst_file.write_fmt(format_args!(" pub {}\n", variable)) {
|
||||||
println!("{}", err);
|
println!("{}", err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(err) = dst_file.write(b"}\n") {
|
if let Err(err) = dst_file.write(b"}\n") {
|
||||||
println!("{}", err);
|
println!("{}", err);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
@import "../base.scss";
|
@import "../base.scss";
|
||||||
|
|
||||||
$panel-aspect-ratio: 1/1.618;
|
$aspect-ratio: 0.618; // 1/1.618;
|
||||||
|
|
||||||
@mixin panel($padding-v: 2%, $padding-h: 2%) {
|
@mixin panel($padding-v: 2%, $padding-h: 2%) {
|
||||||
padding: $padding-v $padding-h;
|
padding: $padding-v $padding-h;
|
||||||
|
@@ -7,7 +7,7 @@ use dioxus_free_icons::{Icon, IconShape};
|
|||||||
|
|
||||||
turf::style_sheet!("src/ui/components/icons.scss");
|
turf::style_sheet!("src/ui/components/icons.scss");
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/style_vars.rs"));
|
include!(concat!(env!("OUT_DIR"), "/style_tokens.rs"));
|
||||||
|
|
||||||
use style::{COLOR_PRIMARY_100, COLOR_TERNARY_100};
|
use style::{COLOR_PRIMARY_100, COLOR_TERNARY_100};
|
||||||
|
|
||||||
|
@@ -19,7 +19,7 @@ use super::{
|
|||||||
text_input::{PasswordInputState, PasswordTextInput, TextInput, TextInputState},
|
text_input::{PasswordInputState, PasswordTextInput, TextInput, TextInputState},
|
||||||
};
|
};
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/style_vars.rs"));
|
include!(concat!(env!("OUT_DIR"), "/style_tokens.rs"));
|
||||||
|
|
||||||
use style::{
|
use style::{
|
||||||
COLOR_PRIMARY_100, COLOR_PRIMARY_110, COLOR_PRIMARY_120, COLOR_PRIMARY_140, COLOR_PRIMARY_150,
|
COLOR_PRIMARY_100, COLOR_PRIMARY_110, COLOR_PRIMARY_120, COLOR_PRIMARY_140, COLOR_PRIMARY_150,
|
||||||
|
@@ -9,7 +9,7 @@ use crate::infrastructure::services::random_svg_generators::{
|
|||||||
generate_random_svg_avatar, AvatarConfig, AvatarFeeling,
|
generate_random_svg_avatar, AvatarConfig, AvatarFeeling,
|
||||||
};
|
};
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/style_vars.rs"));
|
include!(concat!(env!("OUT_DIR"), "/style_tokens.rs"));
|
||||||
|
|
||||||
use style::{COLOR_CRITICAL_100, COLOR_SUCCESS_100, COLOR_WARNING_100};
|
use style::{COLOR_CRITICAL_100, COLOR_SUCCESS_100, COLOR_WARNING_100};
|
||||||
|
|
||||||
|
@@ -3,15 +3,18 @@ use std::rc::Rc;
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
use futures::join;
|
use futures::join;
|
||||||
|
|
||||||
|
use crate::ui::components::{
|
||||||
|
chat_panel::ChatPanel, conversations::Conversations as ConversationsComponent,
|
||||||
|
wallpaper::Wallpaper,
|
||||||
|
};
|
||||||
|
|
||||||
turf::style_sheet!("src/ui/layouts/conversations.scss");
|
turf::style_sheet!("src/ui/layouts/conversations.scss");
|
||||||
|
|
||||||
use crate::ui::components::chat_panel::ChatPanel;
|
include!(concat!(env!("OUT_DIR"), "/style_component_panel.rs"));
|
||||||
use crate::ui::components::conversations::Conversations as ConversationsComponent;
|
include!(concat!(env!("OUT_DIR"), "/style_layout_conversations.rs"));
|
||||||
use crate::ui::components::wallpaper::Wallpaper;
|
|
||||||
|
|
||||||
// TODO: Get from SCSS
|
use conversations::INNER_PANEL_HEIGHT_RATIO;
|
||||||
const WIDGET_HEIGHT_RATIO: f64 = 0.95;
|
use panel::ASPECT_RATIO;
|
||||||
const ASPECT_RATIO: f64 = 1.0 / 1.618;
|
|
||||||
|
|
||||||
async fn on_carousel_scroll(
|
async fn on_carousel_scroll(
|
||||||
parent_div: &Rc<MountedData>,
|
parent_div: &Rc<MountedData>,
|
||||||
@@ -229,14 +232,13 @@ pub fn Conversations() -> Element {
|
|||||||
if let Ok(size) = data.get_border_box_size() {
|
if let Ok(size) = data.get_border_box_size() {
|
||||||
if let Some(size) = size.first() {
|
if let Some(size) = size.first() {
|
||||||
// Use LayoutBig if the layout can contain 2 panels side by side
|
// Use LayoutBig if the layout can contain 2 panels side by side
|
||||||
let component_width = size.height * WIDGET_HEIGHT_RATIO * ASPECT_RATIO;
|
let component_width = size.height * INNER_PANEL_HEIGHT_RATIO * ASPECT_RATIO;
|
||||||
let breakpoint_width = component_width * 2_f64;
|
let breakpoint_width = component_width * 2_f64;
|
||||||
use_big_layout = size.width > breakpoint_width;
|
use_big_layout = size.width > breakpoint_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
layout.set(rsx! { if use_big_layout { LayoutBig {} } else { LayoutSmall {} }});
|
layout.set(rsx! { if use_big_layout { LayoutBig {} } else { LayoutSmall {} }});
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{layout}
|
{layout}
|
||||||
|
@@ -17,11 +17,13 @@
|
|||||||
scroll-snap-align: start;
|
scroll-snap-align: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$inner-panel-height-ratio: 0.95;
|
||||||
|
|
||||||
.conversations-view {
|
.conversations-view {
|
||||||
$height: 100vh;
|
$height: 100vh;
|
||||||
$width: 100vw;
|
$width: 100vw;
|
||||||
$conversations-panel-height: calc($height * 0.95);
|
$conversations-panel-height: calc($height * $inner-panel-height-ratio);
|
||||||
$conversations-panel-width: calc($conversations-panel-height * $panel-aspect-ratio);
|
$conversations-panel-width: calc($conversations-panel-height * $aspect-ratio);
|
||||||
$gap: 1%;
|
$gap: 1%;
|
||||||
$content-height: 95%;
|
$content-height: 95%;
|
||||||
$ratio: 2;
|
$ratio: 2;
|
||||||
@@ -63,11 +65,11 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
// TODO: Is aspect-ratio the best criteria to defined that inner shall take all the available space ?
|
// TODO: Is aspect-ratio the best criteria to defined that inner shall take all the available space ?
|
||||||
@media (max-aspect-ratio: $panel-aspect-ratio) {
|
@media (max-aspect-ratio: $aspect-ratio) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
@media (min-aspect-ratio: $panel-aspect-ratio) {
|
@media (min-aspect-ratio: $aspect-ratio) {
|
||||||
aspect-ratio: $panel-aspect-ratio;
|
aspect-ratio: $aspect-ratio;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,7 +107,7 @@
|
|||||||
|
|
||||||
&__conversations-panel {
|
&__conversations-panel {
|
||||||
height: $content-height;
|
height: $content-height;
|
||||||
aspect-ratio: $panel-aspect-ratio;
|
aspect-ratio: $aspect-ratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__conversation-panels {
|
&__conversation-panels {
|
||||||
|
@@ -18,14 +18,14 @@
|
|||||||
align-items: safe center;
|
align-items: safe center;
|
||||||
|
|
||||||
&__login-panel {
|
&__login-panel {
|
||||||
@media (max-aspect-ratio: $panel-aspect-ratio) {
|
@media (max-aspect-ratio: $aspect-ratio) {
|
||||||
width: 95%;
|
width: 95%;
|
||||||
}
|
}
|
||||||
@media (min-aspect-ratio: $panel-aspect-ratio) {
|
@media (min-aspect-ratio: $aspect-ratio) {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
aspect-ratio: $panel-aspect-ratio;
|
aspect-ratio: $aspect-ratio;
|
||||||
max-height: $panel-max-height;
|
max-height: $panel-max-height;
|
||||||
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
@@ -36,6 +36,6 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
// Variables inherited by children
|
// Variables inherited by children
|
||||||
--aspect-ratio: #{$panel-aspect-ratio};
|
--aspect-ratio: #{$aspect-ratio};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user