diff --git a/web/src/app.rs b/web/src/app.rs
index 662ef70..92592c5 100644
--- a/web/src/app.rs
+++ b/web/src/app.rs
@@ -1,11 +1,10 @@
-use crate::pages::{aes::AesPage, des::DesPage, home::Home};
+use crate::pages::{aes::AesPage, des::DesPage, footer::Footer, header::Header, home::Home};
use leptos::prelude::*;
use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context};
use leptos_router::{
StaticSegment,
- components::{A, Route, Router, Routes},
+ components::{Route, Router, Routes},
};
-use std::fmt::Display;
#[must_use]
pub fn shell(options: LeptosOptions) -> impl IntoView {
@@ -26,60 +25,15 @@ pub fn shell(options: LeptosOptions) -> impl IntoView {
}
}
-#[derive(Clone, Copy, PartialEq)]
-enum Theme {
- Light,
- Dark,
-}
-
-impl Theme {
- const fn inverse(self) -> Self {
- match self {
- Self::Light => Self::Dark,
- Self::Dark => Self::Light,
- }
- }
-}
-
-impl Display for Theme {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let s = match self {
- Self::Light => "☀️ Light",
- Self::Dark => "🌙 Dark",
- };
- f.write_str(s)
- }
-}
-
#[component]
// Provides context that manages stylesheets, titles, meta tags, etc.
pub fn App() -> impl IntoView {
provide_meta_context();
- let (theme, set_theme) = signal(Theme::Dark);
-
- let toggle_theme = move |_| {
- set_theme.update(|t| *t = t.inverse());
-
- if let Some(body) = document().body() {
- let class_list = body.class_list();
- match theme.get() {
- Theme::Light => {
- let _ = class_list.remove_1("dark-theme");
- let _ = class_list.add_1("light-theme");
- }
- Theme::Dark => {
- let _ = class_list.remove_1("light-theme");
- let _ = class_list.add_1("dark-theme");
- }
- }
- }
- };
-
view! {
// injects a stylesheet into the document
// id=leptos means cargo-leptos will hot-reload this stylesheet
-
+
// sets the document title
@@ -87,22 +41,7 @@ pub fn App() -> impl IntoView {
// content for this welcome page
-
-
-
- {move || theme.get().to_string()}
-
-
+
@@ -110,6 +49,7 @@ pub fn App() -> impl IntoView {
+
}
diff --git a/web/src/pages/footer.rs b/web/src/pages/footer.rs
new file mode 100644
index 0000000..35a88d2
--- /dev/null
+++ b/web/src/pages/footer.rs
@@ -0,0 +1,23 @@
+use leptos::prelude::*;
+use leptos_router::components::A;
+
+#[component]
+pub fn Footer() -> impl IntoView {
+ view! {
+
+ }
+}
diff --git a/web/src/pages/header.rs b/web/src/pages/header.rs
new file mode 100644
index 0000000..c48a1de
--- /dev/null
+++ b/web/src/pages/header.rs
@@ -0,0 +1,70 @@
+use leptos::prelude::*;
+use leptos_router::components::A;
+use std::fmt::Display;
+
+#[component]
+pub fn Header() -> impl IntoView {
+ let (theme, set_theme) = signal(Theme::Dark);
+
+ let toggle_theme = move |_| {
+ set_theme.update(|t| *t = t.inverse());
+
+ if let Some(body) = document().body() {
+ let class_list = body.class_list();
+ match theme.get() {
+ Theme::Light => {
+ let _ = class_list.remove_1("dark-theme");
+ let _ = class_list.add_1("light-theme");
+ }
+ Theme::Dark => {
+ let _ = class_list.remove_1("light-theme");
+ let _ = class_list.add_1("dark-theme");
+ }
+ }
+ }
+ };
+
+ view! {
+
+
+
+ {move || theme.get().to_string()}
+
+
+ }
+}
+
+#[derive(Clone, Copy, PartialEq)]
+enum Theme {
+ Light,
+ Dark,
+}
+
+impl Theme {
+ const fn inverse(self) -> Self {
+ match self {
+ Self::Light => Self::Dark,
+ Self::Dark => Self::Light,
+ }
+ }
+}
+
+impl Display for Theme {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let s = match self {
+ Self::Light => "☀️ Light",
+ Self::Dark => "🌙 Dark",
+ };
+ f.write_str(s)
+ }
+}
diff --git a/web/src/pages/mod.rs b/web/src/pages/mod.rs
index 06fe82c..19183cc 100644
--- a/web/src/pages/mod.rs
+++ b/web/src/pages/mod.rs
@@ -1,3 +1,5 @@
pub mod aes;
pub mod des;
+pub mod footer;
+pub mod header;
pub mod home;
diff --git a/web/style/main.scss b/web/style/main.scss
index 8c86354..6724256 100644
--- a/web/style/main.scss
+++ b/web/style/main.scss
@@ -27,6 +27,7 @@ $l-hl-low: #f4ede8;
$l-hl-high: #cecacd;
$control-height: 46px;
+$trans-speed: 0.3s ease;
:root,
body.dark-theme {
@@ -66,20 +67,29 @@ body.light-theme {
--focus-ring: #{rgba($l-rose, 0.3)};
}
+html,
+body {
+ height: 100%;
+ margin: 0;
+ padding: 0;
+}
+
body {
font-family: "Inter", "Segoe UI", sans-serif;
background-color: var(--bg-body);
color: var(--text-main);
margin: 0;
transition:
- background-color 0.3s,
- color 0.3s;
+ background-color $trans-speed,
+ color $trans-speed;
}
.app-containter {
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
max-width: 800px;
margin: 0 auto;
- min-height: 100vh;
}
.main-nav {
@@ -89,6 +99,9 @@ body {
display: flex;
justify-content: space-between;
align-items: center;
+ transition:
+ background-color $trans-speed,
+ border-color $trans-speed;
ul {
list-style: none;
@@ -111,6 +124,13 @@ body {
}
}
+main {
+ flex: 1;
+ padding: 2rem;
+ width: 100%;
+ box-sizing: border-box;
+}
+
.theme-toggle {
background: transparent;
border: 1px solid var(--border);
@@ -135,11 +155,13 @@ body {
text-align: center;
font-size: 0.9rem;
color: var(--text-muted);
+ transition:
+ background-color $trans-speed,
+ border-color $trans-speed,
+ color $trans-speed;
}
.footer-content {
- max-width: 800px;
- margin: 0 auto;
padding: 0 1rem;
p {
@@ -167,16 +189,16 @@ body {
}
}
-main {
- padding: 2rem;
-}
-
.cipher-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 2rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
+ transition:
+ background-color $trans-speed,
+ border-color $trans-speed,
+ box-shadow $trans-speed;
}
.card-header {
@@ -400,6 +422,19 @@ main {
}
}
+.form-group input[type="text"],
+.form-group textarea,
+.format-controls,
+.radio-group,
+.result-box,
+.result-toolbar,
+.format-controls select {
+ transition:
+ background-color $trans-speed,
+ border-color $trans-speed,
+ color $trans-speed;
+}
+
.btn-copy {
background: transparent;
border: none;