Compare commits
5 Commits
0df7b7909f
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35e34c27f7
|
||
|
|
6be48da010
|
||
|
|
c1b38f27ed
|
||
|
|
f1fe0e9827
|
||
|
|
7738a8fa78
|
@@ -2,7 +2,7 @@
|
|||||||
name = "squad-quote-store"
|
name = "squad-quote-store"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Reed Krantz <programming@krantz.one>"]
|
authors = ["Reed Krantz <programming@krantz.one>"]
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|||||||
23
flake.lock
generated
23
flake.lock
generated
@@ -69,7 +69,8 @@
|
|||||||
"crane": "crane",
|
"crane": "crane",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"rust-overlay": "rust-overlay"
|
"rust-overlay": "rust-overlay",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rust-overlay": {
|
"rust-overlay": {
|
||||||
@@ -91,6 +92,26 @@
|
|||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1770228511,
|
||||||
|
"narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "337a4fe074be1042a35086f15481d763b8ddc0e7",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
78
flake.nix
78
flake.nix
@@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||||
|
|
||||||
|
treefmt-nix = {
|
||||||
|
url = "github:numtide/treefmt-nix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
crane.url = "github:ipetkov/crane";
|
crane.url = "github:ipetkov/crane";
|
||||||
|
|
||||||
rust-overlay = {
|
rust-overlay = {
|
||||||
@@ -17,15 +22,30 @@
|
|||||||
outputs = {
|
outputs = {
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
flake-parts,
|
flake-parts,
|
||||||
|
treefmt-nix,
|
||||||
crane,
|
crane,
|
||||||
rust-overlay,
|
rust-overlay,
|
||||||
...
|
...
|
||||||
} @ inputs:
|
} @ inputs:
|
||||||
flake-parts.lib.mkFlake {inherit inputs;} {
|
flake-parts.lib.mkFlake {inherit inputs;} {
|
||||||
|
imports = [
|
||||||
|
treefmt-nix.flakeModule
|
||||||
|
];
|
||||||
|
|
||||||
systems = ["aarch64-linux" "x86_64-linux" "aarch64-darwin" "x86_64-darwin"];
|
systems = ["aarch64-linux" "x86_64-linux" "aarch64-darwin" "x86_64-darwin"];
|
||||||
|
|
||||||
perSystem = {system, ...}: let
|
perSystem = {system, ...}: let
|
||||||
src = ./.;
|
src = craneLib.cleanCargoSource ./.;
|
||||||
|
|
||||||
|
# runtime dependencies
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
# openssl
|
||||||
|
];
|
||||||
|
|
||||||
|
# build dependencies
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
# pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
pkgs = import nixpkgs {
|
pkgs = import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
@@ -42,42 +62,14 @@
|
|||||||
# Build *just* the cargo dependencies, so we can reuse
|
# Build *just* the cargo dependencies, so we can reuse
|
||||||
# all of that work (e.g. via cachix) when running in CI
|
# all of that work (e.g. via cachix) when running in CI
|
||||||
cargoArtifacts = craneLib.buildDepsOnly {
|
cargoArtifacts = craneLib.buildDepsOnly {
|
||||||
inherit src;
|
inherit src buildInputs nativeBuildInputs;
|
||||||
};
|
};
|
||||||
in rec {
|
in rec {
|
||||||
# Formatter for nix files, available through 'nix fmt'
|
|
||||||
formatter = pkgs.alejandra;
|
|
||||||
|
|
||||||
# Your custom packages
|
|
||||||
# Accessible through 'nix build', 'nix shell', 'nix run', etc
|
|
||||||
packages = {
|
|
||||||
default = craneLib.buildPackage {
|
|
||||||
inherit src cargoArtifacts;
|
|
||||||
|
|
||||||
# runtime dependencies
|
|
||||||
# buildInputs = [];
|
|
||||||
|
|
||||||
# build dependencies
|
|
||||||
# nativeBuildInputs = [pkgs.pkg-config];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
checks = {
|
|
||||||
clippy = craneLib.cargoClippy {
|
|
||||||
inherit src cargoArtifacts;
|
|
||||||
cargoClippyExtraArgs = "-- --deny warnings";
|
|
||||||
};
|
|
||||||
|
|
||||||
fmt = craneLib.cargoFmt {
|
|
||||||
inherit src cargoArtifacts;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# Dev Shell that lets you enter an environment with all the necessary utilites
|
# Dev Shell that lets you enter an environment with all the necessary utilites
|
||||||
# Available through 'nix develop'
|
# Available through 'nix develop'
|
||||||
# Also can be activated automatically if direnv is installed on the system with 'direnv allow'
|
# Also can be activated automatically if direnv is installed on the system with 'direnv allow'
|
||||||
devShells.default = craneLib.devShell {
|
devShells.default = craneLib.devShell {
|
||||||
inherit cargoArtifacts checks;
|
inherit checks;
|
||||||
|
|
||||||
# extra tooling dependencies
|
# extra tooling dependencies
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
@@ -87,6 +79,30 @@
|
|||||||
|
|
||||||
inputsFrom = [packages.default];
|
inputsFrom = [packages.default];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Formatter for nix files, available through 'nix fmt'
|
||||||
|
treefmt = {
|
||||||
|
programs.alejandra.enable = true;
|
||||||
|
programs.rustfmt = {
|
||||||
|
enable = true;
|
||||||
|
edition = (builtins.fromTOML (builtins.readFile "${src}/Cargo.toml")).package.edition;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Your custom packages
|
||||||
|
# Accessible through 'nix build', 'nix shell', 'nix run', etc
|
||||||
|
packages = {
|
||||||
|
default = craneLib.buildPackage {
|
||||||
|
inherit src buildInputs nativeBuildInputs cargoArtifacts;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
checks = {
|
||||||
|
clippy = craneLib.cargoClippy {
|
||||||
|
inherit src buildInputs nativeBuildInputs cargoArtifacts;
|
||||||
|
cargoClippyExtraArgs = "-- --deny warnings";
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
use dioxus_primitives::{
|
use dioxus_primitives::{
|
||||||
|
ContentAlign,
|
||||||
date_picker::{self, DatePickerInputProps, DatePickerProps, DateRangePickerProps},
|
date_picker::{self, DatePickerInputProps, DatePickerProps, DateRangePickerProps},
|
||||||
popover::{PopoverContentProps, PopoverTriggerProps},
|
popover::{PopoverContentProps, PopoverTriggerProps},
|
||||||
ContentAlign,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::super::calendar::*;
|
use super::super::calendar::*;
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
use crate::components::{
|
use crate::components::{
|
||||||
date_picker::{DatePicker, DatePickerInput},
|
|
||||||
Input,
|
Input,
|
||||||
|
date_picker::{DatePicker, DatePickerInput},
|
||||||
|
textarea::Textarea,
|
||||||
};
|
};
|
||||||
use dioxus::prelude::*;
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
use time::{macros::offset, OffsetDateTime};
|
use time::{OffsetDateTime, macros::offset};
|
||||||
|
|
||||||
#[component]
|
#[component]
|
||||||
pub fn EditQuote() -> Element {
|
pub fn EditQuote() -> Element {
|
||||||
@@ -17,9 +18,10 @@ pub fn EditQuote() -> Element {
|
|||||||
.date(),
|
.date(),
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
let mut context = use_signal(String::new);
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
Input {
|
Textarea {
|
||||||
oninput: move |e: FormEvent| quote.set(e.value()),
|
oninput: move |e: FormEvent| quote.set(e.value()),
|
||||||
placeholder: "Enter the quote",
|
placeholder: "Enter the quote",
|
||||||
value: quote,
|
value: quote,
|
||||||
@@ -34,5 +36,10 @@ pub fn EditQuote() -> Element {
|
|||||||
on_value_change: move |v| date.set(v),
|
on_value_change: move |v| date.set(v),
|
||||||
DatePickerInput {}
|
DatePickerInput {}
|
||||||
}
|
}
|
||||||
|
Textarea {
|
||||||
|
oninput: move |e: FormEvent| context.set(e.value()),
|
||||||
|
placeholder: "Any additional context",
|
||||||
|
value: context,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,3 +17,4 @@ pub use edit_quote::EditQuote;
|
|||||||
pub mod calendar;
|
pub mod calendar;
|
||||||
pub mod date_picker;
|
pub mod date_picker;
|
||||||
pub mod popover;
|
pub mod popover;
|
||||||
|
pub mod textarea;
|
||||||
|
|||||||
78
src/components/textarea/component.rs
Normal file
78
src/components/textarea/component.rs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
use dioxus::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Default)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum TextareaVariant {
|
||||||
|
#[default]
|
||||||
|
Default,
|
||||||
|
Fade,
|
||||||
|
Outline,
|
||||||
|
Ghost,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextareaVariant {
|
||||||
|
pub fn class(&self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
TextareaVariant::Default => "default",
|
||||||
|
TextareaVariant::Fade => "fade",
|
||||||
|
TextareaVariant::Outline => "outline",
|
||||||
|
TextareaVariant::Ghost => "ghost",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn Textarea(
|
||||||
|
oninput: Option<EventHandler<FormEvent>>,
|
||||||
|
onchange: Option<EventHandler<FormEvent>>,
|
||||||
|
oninvalid: Option<EventHandler<FormEvent>>,
|
||||||
|
onselect: Option<EventHandler<SelectionEvent>>,
|
||||||
|
onselectionchange: Option<EventHandler<SelectionEvent>>,
|
||||||
|
onfocus: Option<EventHandler<FocusEvent>>,
|
||||||
|
onblur: Option<EventHandler<FocusEvent>>,
|
||||||
|
onfocusin: Option<EventHandler<FocusEvent>>,
|
||||||
|
onfocusout: Option<EventHandler<FocusEvent>>,
|
||||||
|
onkeydown: Option<EventHandler<KeyboardEvent>>,
|
||||||
|
onkeypress: Option<EventHandler<KeyboardEvent>>,
|
||||||
|
onkeyup: Option<EventHandler<KeyboardEvent>>,
|
||||||
|
oncompositionstart: Option<EventHandler<CompositionEvent>>,
|
||||||
|
oncompositionupdate: Option<EventHandler<CompositionEvent>>,
|
||||||
|
oncompositionend: Option<EventHandler<CompositionEvent>>,
|
||||||
|
oncopy: Option<EventHandler<ClipboardEvent>>,
|
||||||
|
oncut: Option<EventHandler<ClipboardEvent>>,
|
||||||
|
onpaste: Option<EventHandler<ClipboardEvent>>,
|
||||||
|
#[props(default)] variant: TextareaVariant,
|
||||||
|
#[props(extends=GlobalAttributes)]
|
||||||
|
#[props(extends=textarea)]
|
||||||
|
attributes: Vec<Attribute>,
|
||||||
|
children: Element,
|
||||||
|
) -> Element {
|
||||||
|
rsx! {
|
||||||
|
document::Link { rel: "stylesheet", href: asset!("./style.css") }
|
||||||
|
textarea {
|
||||||
|
class: "textarea",
|
||||||
|
"data-slot": "textarea",
|
||||||
|
"data-style": variant.class(),
|
||||||
|
oninput: move |e| _ = oninput.map(|callback| callback(e)),
|
||||||
|
onchange: move |e| _ = onchange.map(|callback| callback(e)),
|
||||||
|
oninvalid: move |e| _ = oninvalid.map(|callback| callback(e)),
|
||||||
|
onselect: move |e| _ = onselect.map(|callback| callback(e)),
|
||||||
|
onselectionchange: move |e| _ = onselectionchange.map(|callback| callback(e)),
|
||||||
|
onfocus: move |e| _ = onfocus.map(|callback| callback(e)),
|
||||||
|
onblur: move |e| _ = onblur.map(|callback| callback(e)),
|
||||||
|
onfocusin: move |e| _ = onfocusin.map(|callback| callback(e)),
|
||||||
|
onfocusout: move |e| _ = onfocusout.map(|callback| callback(e)),
|
||||||
|
onkeydown: move |e| _ = onkeydown.map(|callback| callback(e)),
|
||||||
|
onkeypress: move |e| _ = onkeypress.map(|callback| callback(e)),
|
||||||
|
onkeyup: move |e| _ = onkeyup.map(|callback| callback(e)),
|
||||||
|
oncompositionstart: move |e| _ = oncompositionstart.map(|callback| callback(e)),
|
||||||
|
oncompositionupdate: move |e| _ = oncompositionupdate.map(|callback| callback(e)),
|
||||||
|
oncompositionend: move |e| _ = oncompositionend.map(|callback| callback(e)),
|
||||||
|
oncopy: move |e| _ = oncopy.map(|callback| callback(e)),
|
||||||
|
oncut: move |e| _ = oncut.map(|callback| callback(e)),
|
||||||
|
onpaste: move |e| _ = onpaste.map(|callback| callback(e)),
|
||||||
|
..attributes,
|
||||||
|
{children}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/components/textarea/mod.rs
Normal file
2
src/components/textarea/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
mod component;
|
||||||
|
pub use component::*;
|
||||||
84
src/components/textarea/style.css
Normal file
84
src/components/textarea/style.css
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/* Base */
|
||||||
|
.textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 4rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
margin: 0;
|
||||||
|
appearance: none;
|
||||||
|
background: none;
|
||||||
|
color: var(--secondary-color-4);
|
||||||
|
font-family: inherit;
|
||||||
|
line-height: 1.5;
|
||||||
|
outline: none;
|
||||||
|
resize: vertical;
|
||||||
|
transition: background-color 100ms ease-out, border-color 100ms ease-out, box-shadow 100ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea:disabled {
|
||||||
|
color: var(--secondary-color-5);
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea::placeholder {
|
||||||
|
color: var(--secondary-color-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default Variant */
|
||||||
|
.textarea[data-style="default"] {
|
||||||
|
background: var(--light, var(--primary-color)) var(--dark, var(--primary-color-3));
|
||||||
|
box-shadow: inset 0 0 0 1px var(--light, var(--primary-color-6)) var(--dark, var(--primary-color-7));
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea[data-style="default"]:hover:not(:disabled),
|
||||||
|
.textarea[data-style="default"]:focus {
|
||||||
|
background: var(--light, var(--primary-color-4)) var(--dark, var(--primary-color-5));
|
||||||
|
color: var(--secondary-color-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fade Variant */
|
||||||
|
.textarea[data-style="fade"] {
|
||||||
|
background: var(--light, var(--primary-color)) var(--dark, var(--primary-color-3));
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea[data-style="fade"]:hover:not(:disabled),
|
||||||
|
.textarea[data-style="fade"]:focus {
|
||||||
|
background: var(--light, var(--primary-color-4)) var(--dark, var(--primary-color-5));
|
||||||
|
color: var(--secondary-color-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Outline Variant */
|
||||||
|
.textarea[data-style="outline"] {
|
||||||
|
border: 1px solid var(--primary-color-6);
|
||||||
|
background-color: var(--light, var(--primary-color))
|
||||||
|
var(--dark, var(--primary-color-3));
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea[data-style="outline"]:hover:not(:disabled, :focus) {
|
||||||
|
border-color: var(--primary-color-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea[data-style="outline"]:focus {
|
||||||
|
border-color: var(--focused-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea[data-style="outline"]:invalid,
|
||||||
|
.textarea[data-style="outline"][aria-invalid="true"] {
|
||||||
|
border-color: var(--primary-error-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ghost Variant */
|
||||||
|
.textarea[data-style="ghost"] {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea[data-style="ghost"]:hover:not(:disabled) {
|
||||||
|
background-color: var(--primary-color-5);
|
||||||
|
color: var(--secondary-color-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.textarea[data-style="ghost"]:focus {
|
||||||
|
border-color: var(--focused-border-color);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user