Move Images and Tiles into the toolkit
Add a Profile toolkit struct
This commit is contained in:
parent
f6f603324a
commit
c86f4b3ff2
|
@ -43,7 +43,7 @@ img {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: scale-down;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolkit-select {
|
.toolkit-select {
|
||||||
|
@ -339,6 +339,64 @@ img {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toolkit-tiles {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
|
||||||
|
|
||||||
|
.toolkit-tile {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
picture {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolkit-link {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
font-style: none;
|
||||||
|
font-weight: 500;
|
||||||
|
color: $border-light;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
color: $border-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolkit-tile--overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease-in-out;
|
||||||
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
|
text-shadow: 1px 1px 1px $dark;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolkit-title--meta p {
|
||||||
|
margin: 0;
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.toolkit-centered {
|
.toolkit-centered {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 900px;
|
max-width: 900px;
|
||||||
|
|
50
toolkit/src/banner.rs
Normal file
50
toolkit/src/banner.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
use crate::image::Image;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
pub struct Banner {
|
||||||
|
image: Option<Rc<dyn Image>>,
|
||||||
|
dark: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Banner {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Banner {
|
||||||
|
image: None,
|
||||||
|
dark: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn image(mut self, image: impl Image + 'static) -> Self {
|
||||||
|
self.image = Some(Rc::new(image));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dark(mut self, dark: bool) -> Self {
|
||||||
|
self.dark = dark;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn image_opt(&self) -> Option<&dyn Image> {
|
||||||
|
self.image.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn class_string(&self) -> String {
|
||||||
|
let mut classes = vec!["toolkit-banner".to_owned()];
|
||||||
|
|
||||||
|
if self.dark {
|
||||||
|
classes.push("toolkit-dark".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
classes.join(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Banner {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Banner")
|
||||||
|
.field("dark", &self.dark)
|
||||||
|
.field("image", &"Rc<dyn Image>")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
use std::{cell::RefCell, fmt};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum ButtonKind {
|
pub enum ButtonKind {
|
||||||
Primary,
|
Primary,
|
||||||
|
@ -14,19 +12,8 @@ pub enum LinkKind {
|
||||||
NewTab,
|
NewTab,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
pub(crate) inner: RefCell<Inner>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Button {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.debug_struct("Button").field("inner", &"Inner").finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub(crate) struct Inner {
|
|
||||||
pub(crate) label: String,
|
pub(crate) label: String,
|
||||||
pub(crate) kind: ButtonKind,
|
pub(crate) kind: ButtonKind,
|
||||||
pub(crate) classes: Vec<String>,
|
pub(crate) classes: Vec<String>,
|
||||||
|
@ -39,79 +26,71 @@ pub(crate) struct Inner {
|
||||||
impl Button {
|
impl Button {
|
||||||
pub fn primary(label: &str) -> Self {
|
pub fn primary(label: &str) -> Self {
|
||||||
Button {
|
Button {
|
||||||
inner: RefCell::new(Inner {
|
label: label.to_owned(),
|
||||||
label: label.to_owned(),
|
..Default::default()
|
||||||
..Inner::default()
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary_outline(label: &str) -> Self {
|
pub fn primary_outline(label: &str) -> Self {
|
||||||
Button {
|
Button {
|
||||||
inner: RefCell::new(Inner {
|
label: label.to_owned(),
|
||||||
label: label.to_owned(),
|
kind: ButtonKind::PrimaryOutline,
|
||||||
kind: ButtonKind::PrimaryOutline,
|
..Default::default()
|
||||||
..Inner::default()
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outline(label: &str) -> Self {
|
pub fn outline(label: &str) -> Self {
|
||||||
Button {
|
Button {
|
||||||
inner: RefCell::new(Inner {
|
label: label.to_owned(),
|
||||||
label: label.to_owned(),
|
kind: ButtonKind::Outline,
|
||||||
kind: ButtonKind::Outline,
|
..Default::default()
|
||||||
..Inner::default()
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn secondary(label: &str) -> Self {
|
pub fn secondary(label: &str) -> Self {
|
||||||
Button {
|
Button {
|
||||||
inner: RefCell::new(Inner {
|
label: label.to_owned(),
|
||||||
label: label.to_owned(),
|
kind: ButtonKind::Secondary,
|
||||||
kind: ButtonKind::Secondary,
|
..Default::default()
|
||||||
..Inner::default()
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&self, kind: ButtonKind) -> &Self {
|
pub fn kind(mut self, kind: ButtonKind) -> Self {
|
||||||
self.inner.borrow_mut().kind = kind;
|
self.kind = kind;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn classes(&self, classes: &[&str]) -> &Self {
|
pub fn classes(mut self, classes: &[&str]) -> Self {
|
||||||
self.inner.borrow_mut().classes = classes.into_iter().map(|s| s.to_string()).collect();
|
self.classes = classes.into_iter().map(|s| s.to_string()).collect();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn href(&self, href: &str) -> &Self {
|
pub fn href(mut self, href: &str) -> Self {
|
||||||
self.inner.borrow_mut().href = Some(href.to_owned());
|
self.href = Some(href.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_tab(&self) -> &Self {
|
pub fn new_tab(mut self) -> Self {
|
||||||
self.inner.borrow_mut().link_kind = LinkKind::NewTab;
|
self.link_kind = LinkKind::NewTab;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn form(&self, action: &str) -> &Self {
|
pub fn form(mut self, action: &str) -> Self {
|
||||||
self.inner.borrow_mut().action = Some(action.to_owned());
|
self.action = Some(action.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dark(&self, dark: bool) -> &Self {
|
pub fn dark(mut self, dark: bool) -> Self {
|
||||||
self.inner.borrow_mut().dark = dark;
|
self.dark = dark;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn class_string(&self) -> String {
|
pub(crate) fn class_string(&self) -> String {
|
||||||
use ButtonKind::*;
|
use ButtonKind::*;
|
||||||
|
|
||||||
let mut classes = self.inner.borrow().classes.clone();
|
let mut classes = self.classes.clone();
|
||||||
|
|
||||||
let static_classes = match self.inner.borrow().kind {
|
let static_classes = match self.kind {
|
||||||
Primary => "toolkit-button toolkit-button__primary",
|
Primary => "toolkit-button toolkit-button__primary",
|
||||||
PrimaryOutline => "toolkit-button toolkit-button__primary-outline",
|
PrimaryOutline => "toolkit-button toolkit-button__primary-outline",
|
||||||
Outline => "toolkit-button toolkit-button__outline",
|
Outline => "toolkit-button toolkit-button__outline",
|
||||||
|
@ -120,7 +99,7 @@ impl Button {
|
||||||
|
|
||||||
classes.push(static_classes.to_owned());
|
classes.push(static_classes.to_owned());
|
||||||
|
|
||||||
if self.inner.borrow().dark {
|
if self.dark {
|
||||||
classes.push("toolkit-dark".to_owned());
|
classes.push("toolkit-dark".to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,17 +17,17 @@ impl Card {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn centered(&mut self) -> &mut Self {
|
pub fn centered(mut self) -> Self {
|
||||||
self.classes.push("toolkit-centered".to_owned());
|
self.classes.push("toolkit-centered".to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn classes(&mut self, classes: &[&str]) -> &mut Self {
|
pub fn classes(mut self, classes: &[&str]) -> Self {
|
||||||
self.classes = classes.into_iter().map(|s| s.to_string()).collect();
|
self.classes = classes.into_iter().map(|s| s.to_string()).collect();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dark(&mut self, dark: bool) -> &mut Self {
|
pub fn dark(mut self, dark: bool) -> Self {
|
||||||
self.dark = dark;
|
self.dark = dark;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,27 +52,27 @@ impl FileInput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn multiple(&mut self) -> &mut Self {
|
pub fn multiple(mut self) -> Self {
|
||||||
self.multiple = true;
|
self.multiple = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn classes(&mut self, classes: &[&str]) -> &mut Self {
|
pub fn classes(mut self, classes: &[&str]) -> Self {
|
||||||
self.classes = classes.into_iter().map(|s| s.to_string()).collect();
|
self.classes = classes.into_iter().map(|s| s.to_string()).collect();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accept(&mut self, accept: &str) -> &mut Self {
|
pub fn accept(mut self, accept: &str) -> Self {
|
||||||
self.accept = accept.to_string();
|
self.accept = accept.to_string();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn no_group(&mut self) -> &mut Self {
|
pub fn no_group(mut self) -> Self {
|
||||||
self.group = false;
|
self.group = false;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dark(&mut self, dark: bool) -> &mut Self {
|
pub fn dark(mut self, dark: bool) -> Self {
|
||||||
self.dark = dark;
|
self.dark = dark;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
65
toolkit/src/icon.rs
Normal file
65
toolkit/src/icon.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use crate::image::Image;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Icon {
|
||||||
|
pub(crate) href: String,
|
||||||
|
pub(crate) small: bool,
|
||||||
|
pub(crate) dark: bool,
|
||||||
|
image: Option<Rc<dyn Image>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Icon {
|
||||||
|
pub fn new(href: String) -> Self {
|
||||||
|
Icon {
|
||||||
|
href,
|
||||||
|
small: false,
|
||||||
|
dark: false,
|
||||||
|
image: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn image(mut self, image: impl Image + 'static) -> Self {
|
||||||
|
self.image = Some(Rc::new(image));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dark(mut self, dark: bool) -> Self {
|
||||||
|
self.dark = dark;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn small(mut self, small: bool) -> Self {
|
||||||
|
self.small = small;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn image_opt(&self) -> Option<&dyn Image> {
|
||||||
|
self.image.as_deref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn class_string(&self) -> String {
|
||||||
|
let mut classes = vec!["toolkit-icon--link".to_owned()];
|
||||||
|
|
||||||
|
if self.small {
|
||||||
|
classes.push("toolkit-icon--link__small".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.dark {
|
||||||
|
classes.push("toolkit-dark".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
classes.join(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Icon {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Icon")
|
||||||
|
.field("href", &self.href)
|
||||||
|
.field("small", &self.dark)
|
||||||
|
.field("dark", &self.dark)
|
||||||
|
.field("image", &"Rc<dyn Image>")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
86
toolkit/src/image.rs
Normal file
86
toolkit/src/image.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub trait Image {
|
||||||
|
fn src(&self) -> String;
|
||||||
|
|
||||||
|
fn title(&self) -> String;
|
||||||
|
|
||||||
|
fn png_srcset(&self) -> Option<String>;
|
||||||
|
fn jpeg_srcset(&self) -> Option<String>;
|
||||||
|
fn webp_srcset(&self) -> Option<String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Image for &T
|
||||||
|
where
|
||||||
|
T: Image,
|
||||||
|
{
|
||||||
|
fn src(&self) -> String {
|
||||||
|
T::src(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn title(&self) -> String {
|
||||||
|
T::title(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn png_srcset(&self) -> Option<String> {
|
||||||
|
T::png_srcset(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jpeg_srcset(&self) -> Option<String> {
|
||||||
|
T::jpeg_srcset(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn webp_srcset(&self) -> Option<String> {
|
||||||
|
T::webp_srcset(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Image for Rc<T>
|
||||||
|
where
|
||||||
|
T: Image,
|
||||||
|
{
|
||||||
|
fn src(&self) -> String {
|
||||||
|
T::src(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn title(&self) -> String {
|
||||||
|
T::title(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn png_srcset(&self) -> Option<String> {
|
||||||
|
T::png_srcset(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jpeg_srcset(&self) -> Option<String> {
|
||||||
|
T::jpeg_srcset(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn webp_srcset(&self) -> Option<String> {
|
||||||
|
T::webp_srcset(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Image for Box<T>
|
||||||
|
where
|
||||||
|
T: Image,
|
||||||
|
{
|
||||||
|
fn src(&self) -> String {
|
||||||
|
T::src(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn title(&self) -> String {
|
||||||
|
T::title(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn png_srcset(&self) -> Option<String> {
|
||||||
|
T::png_srcset(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn jpeg_srcset(&self) -> Option<String> {
|
||||||
|
T::jpeg_srcset(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn webp_srcset(&self) -> Option<String> {
|
||||||
|
T::webp_srcset(self)
|
||||||
|
}
|
||||||
|
}
|
|
@ -25,32 +25,32 @@ impl Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kind(&mut self, kind: InputKind) -> &mut Self {
|
pub fn kind(mut self, kind: InputKind) -> Self {
|
||||||
self.kind = kind;
|
self.kind = kind;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&mut self, value: &str) -> &mut Self {
|
pub fn value(mut self, value: &str) -> Self {
|
||||||
self.value = Some(value.to_owned());
|
self.value = Some(value.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn placeholder(&mut self, placeholder: &str) -> &mut Self {
|
pub fn placeholder(mut self, placeholder: &str) -> Self {
|
||||||
self.placeholder = Some(placeholder.to_owned());
|
self.placeholder = Some(placeholder.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_opt(&mut self, value: Option<String>) -> &mut Self {
|
pub fn value_opt(mut self, value: Option<String>) -> Self {
|
||||||
self.value = value;
|
self.value = value;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn classes(&mut self, classes: &[&str]) -> &mut Self {
|
pub fn classes(mut self, classes: &[&str]) -> Self {
|
||||||
self.classes = classes.into_iter().map(|s| s.to_string()).collect();
|
self.classes = classes.into_iter().map(|s| s.to_string()).collect();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dark(&mut self, dark: bool) -> &mut Self {
|
pub fn dark(mut self, dark: bool) -> Self {
|
||||||
self.dark = dark;
|
self.dark = dark;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,31 @@
|
||||||
include!(concat!(env!("OUT_DIR"), "/templates.rs"));
|
include!(concat!(env!("OUT_DIR"), "/templates.rs"));
|
||||||
|
|
||||||
|
mod banner;
|
||||||
mod button;
|
mod button;
|
||||||
mod card;
|
mod card;
|
||||||
mod file_input;
|
mod file_input;
|
||||||
|
mod icon;
|
||||||
|
mod image;
|
||||||
mod input;
|
mod input;
|
||||||
mod link;
|
mod link;
|
||||||
|
mod profile;
|
||||||
mod select;
|
mod select;
|
||||||
mod text_input;
|
mod text_input;
|
||||||
|
mod tile;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
|
banner::Banner,
|
||||||
button::{Button, ButtonKind, LinkKind},
|
button::{Button, ButtonKind, LinkKind},
|
||||||
card::Card,
|
card::Card,
|
||||||
file_input::FileInput,
|
file_input::FileInput,
|
||||||
|
icon::Icon,
|
||||||
|
image::Image,
|
||||||
input::{Input, InputKind},
|
input::{Input, InputKind},
|
||||||
link::Link,
|
link::Link,
|
||||||
|
profile::Profile,
|
||||||
select::Select,
|
select::Select,
|
||||||
text_input::TextInput,
|
text_input::TextInput,
|
||||||
|
tile::Tile,
|
||||||
};
|
};
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
|
|
|
@ -27,17 +27,17 @@ impl Link {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title(&mut self, title: &str) -> &mut Self {
|
pub fn title(mut self, title: &str) -> Self {
|
||||||
self.title = Some(title.to_owned());
|
self.title = Some(title.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dark(&mut self, dark: bool) -> &mut Self {
|
pub fn dark(mut self, dark: bool) -> Self {
|
||||||
self.dark = dark;
|
self.dark = dark;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plain(&mut self, plain: bool) -> &mut Self {
|
pub fn plain(mut self, plain: bool) -> Self {
|
||||||
self.plain = plain;
|
self.plain = plain;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
67
toolkit/src/profile.rs
Normal file
67
toolkit/src/profile.rs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
use crate::{banner::Banner, icon::Icon, image::Image};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Profile {
|
||||||
|
pub(crate) handle: String,
|
||||||
|
pub(crate) display_name: Option<String>,
|
||||||
|
pub(crate) description: Option<String>,
|
||||||
|
pub(crate) icon: Icon,
|
||||||
|
pub(crate) banner: Banner,
|
||||||
|
dark: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Profile {
|
||||||
|
pub fn new(handle: String, href: String) -> Self {
|
||||||
|
Profile {
|
||||||
|
handle,
|
||||||
|
display_name: None,
|
||||||
|
description: None,
|
||||||
|
icon: Icon::new(href),
|
||||||
|
banner: Banner::new(),
|
||||||
|
dark: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn display_name(mut self, display_name: &str) -> Self {
|
||||||
|
self.display_name = Some(display_name.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn description(mut self, description: &str) -> Self {
|
||||||
|
self.description = Some(description.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn icon_image(self, image: impl Image + 'static) -> Self {
|
||||||
|
Profile {
|
||||||
|
icon: self.icon.image(image),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn banner_image(self, image: impl Image + 'static) -> Self {
|
||||||
|
Profile {
|
||||||
|
banner: self.banner.image(image),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dark(self, dark: bool) -> Self {
|
||||||
|
Profile {
|
||||||
|
icon: self.icon.dark(dark),
|
||||||
|
banner: self.banner.dark(dark),
|
||||||
|
dark,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn class_string(&self) -> String {
|
||||||
|
let mut classes = vec!["toolkit-profile".to_owned()];
|
||||||
|
|
||||||
|
if self.dark {
|
||||||
|
classes.push("toolkit-dark".to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
classes.join(" ")
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,22 +24,22 @@ impl Select {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title(&mut self, title: &str) -> &mut Self {
|
pub fn title(mut self, title: &str) -> Self {
|
||||||
self.title = Some(title.to_owned());
|
self.title = Some(title.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_option(&mut self, value: &str) -> &mut Self {
|
pub fn default_option(mut self, value: &str) -> Self {
|
||||||
self.default = Some(value.to_owned());
|
self.default = Some(value.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_option(&mut self, text: String, value: String) -> &mut Self {
|
pub fn add_option(mut self, text: String, value: String) -> Self {
|
||||||
self.options.push(SelectOption { value, text });
|
self.options.push(SelectOption { value, text });
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn options(&mut self, options: &[(&str, &str)]) -> &mut Self {
|
pub fn options(mut self, options: &[(&str, &str)]) -> Self {
|
||||||
self.options = options
|
self.options = options
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(text, value)| SelectOption {
|
.map(|(text, value)| SelectOption {
|
||||||
|
@ -50,7 +50,7 @@ impl Select {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dark(&mut self, dark: bool) -> &mut Self {
|
pub fn dark(mut self, dark: bool) -> Self {
|
||||||
self.dark = dark;
|
self.dark = dark;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,47 +17,57 @@ impl TextInput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn password(&mut self) -> &mut Self {
|
pub fn password(self) -> Self {
|
||||||
self.input.kind(InputKind::Password);
|
TextInput {
|
||||||
self
|
input: self.input.kind(InputKind::Password),
|
||||||
|
..self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn textarea(&mut self) -> &mut Self {
|
pub fn textarea(self) -> Self {
|
||||||
self.input.kind(InputKind::TextArea);
|
TextInput {
|
||||||
self
|
input: self.input.kind(InputKind::TextArea),
|
||||||
|
..self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn title(&mut self, title: &str) -> &mut Self {
|
pub fn title(mut self, title: &str) -> Self {
|
||||||
self.title = Some(title.to_owned());
|
self.title = Some(title.to_owned());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(&mut self, value: &str) -> &mut Self {
|
pub fn value(self, value: &str) -> Self {
|
||||||
self.input.value(value);
|
TextInput {
|
||||||
self
|
input: self.input.value(value),
|
||||||
|
..self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn placeholder(&mut self, placeholder: &str) -> &mut Self {
|
pub fn placeholder(self, placeholder: &str) -> Self {
|
||||||
self.input.placeholder(placeholder);
|
TextInput {
|
||||||
self
|
input: self.input.placeholder(placeholder),
|
||||||
|
..self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn classes(&mut self, classes: &[&str]) -> &mut Self {
|
pub fn classes(mut self, classes: &[&str]) -> Self {
|
||||||
self.classes = classes.into_iter().map(|s| s.to_string()).collect();
|
self.classes = classes.into_iter().map(|s| s.to_string()).collect();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value_opt(&mut self, value: Option<String>) -> &mut Self {
|
pub fn value_opt(self, value: Option<String>) -> Self {
|
||||||
self.input.value_opt(value);
|
TextInput {
|
||||||
self
|
input: self.input.value_opt(value),
|
||||||
|
..self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error_opt(&mut self, error: Option<String>) -> &mut Self {
|
pub fn error_opt(mut self, error: Option<String>) -> Self {
|
||||||
self.error = error;
|
self.error = error;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dark(&mut self, dark: bool) -> &mut Self {
|
pub fn dark(mut self, dark: bool) -> Self {
|
||||||
self.dark = dark;
|
self.dark = dark;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
78
toolkit/src/tile.rs
Normal file
78
toolkit/src/tile.rs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
use crate::image::Image;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum TileFlag {
|
||||||
|
Normal,
|
||||||
|
Primary,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Tile {
|
||||||
|
pub(crate) title: Option<String>,
|
||||||
|
pub(crate) description: Option<String>,
|
||||||
|
pub(crate) link: Option<String>,
|
||||||
|
pub(crate) flag: TileFlag,
|
||||||
|
image: Rc<dyn Image>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tile {
|
||||||
|
pub fn new(image: impl Image + 'static) -> Self {
|
||||||
|
Tile {
|
||||||
|
title: None,
|
||||||
|
description: None,
|
||||||
|
link: None,
|
||||||
|
flag: TileFlag::Normal,
|
||||||
|
image: Rc::new(image),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn title(mut self, title: &str) -> Self {
|
||||||
|
self.title = Some(title.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn description(mut self, description: &str) -> Self {
|
||||||
|
self.description = Some(description.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn link(mut self, link: &str) -> Self {
|
||||||
|
self.link = Some(link.to_owned());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn flag(mut self, flag: TileFlag) -> Self {
|
||||||
|
self.flag = flag;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn image(&self) -> &dyn Image {
|
||||||
|
&*self.image
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn class_string(&self) -> String {
|
||||||
|
let mut classes = vec!["toolkit-tile".to_owned()];
|
||||||
|
|
||||||
|
match self.flag {
|
||||||
|
TileFlag::Normal => (),
|
||||||
|
TileFlag::Primary => {
|
||||||
|
classes.push("toolkit-tile__primary".to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
classes.join(" ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for Tile {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
f.debug_struct("Tile")
|
||||||
|
.field("title", &self.title)
|
||||||
|
.field("description", &self.description)
|
||||||
|
.field("link", &self.link)
|
||||||
|
.field("flag", &self.flag)
|
||||||
|
.field("image", &"Box<dyn Image>")
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,10 @@
|
||||||
@(dark: bool, img: Content)
|
@use crate::banner::Banner;
|
||||||
|
@use crate::templates::image;
|
||||||
|
|
||||||
@if dark {
|
@(banner: &Banner)
|
||||||
<div class="toolkit-banner toolkit-dark">
|
|
||||||
@:img()
|
<div class="@banner.class_string()">
|
||||||
</div>
|
@if let Some(img) = banner.image_opt() {
|
||||||
} else {
|
@:image(img)
|
||||||
<div class="toolkit-banner">
|
}
|
||||||
@:img()
|
</div>
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
@(button: &Button)
|
@(button: &Button)
|
||||||
|
|
||||||
@if let Some(action) = button.inner.borrow().action.as_ref() {
|
@if let Some(action) = button.action.as_ref() {
|
||||||
<form class="@button.class_string()" method="POST" action="@action">
|
<form class="@button.class_string()" method="POST" action="@action">
|
||||||
@:button_inner(button)
|
@:button_inner(button)
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
@use crate::Button;
|
@use crate::Button;
|
||||||
@use super::button;
|
@use super::button;
|
||||||
|
|
||||||
@(buttons: &[&Button])
|
@(buttons: &[Button])
|
||||||
|
|
||||||
<div class="toolkit-button-group">
|
<div class="toolkit-button-group">
|
||||||
@for btn in buttons {
|
@for btn in buttons {
|
||||||
|
|
|
@ -2,18 +2,18 @@
|
||||||
|
|
||||||
@(button: &Button)
|
@(button: &Button)
|
||||||
|
|
||||||
<span>@button.inner.borrow().label</span>
|
<span>@button.label</span>
|
||||||
@if let Some(href) = button.inner.borrow().href.as_ref() {
|
@if let Some(href) = button.href.as_ref() {
|
||||||
@match button.inner.borrow().link_kind {
|
@match button.link_kind {
|
||||||
LinkKind::CurrentTab => {
|
LinkKind::CurrentTab => {
|
||||||
<a href="@href" class="toolkit-button--action">@button.inner.borrow().label</a>
|
<a href="@href" class="toolkit-button--action">@button.label</a>
|
||||||
}
|
}
|
||||||
LinkKind::NewTab => {
|
LinkKind::NewTab => {
|
||||||
<a href="@href" target="_blank" rel="noopener noreferer" class="toolkit-button--action">
|
<a href="@href" target="_blank" rel="noopener noreferer" class="toolkit-button--action">
|
||||||
@button.inner.borrow().label
|
@button.label
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
<button class="toolkit-button--action">@button.inner.borrow().label</button>
|
<button class="toolkit-button--action">@button.label</button>
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,31 +1,12 @@
|
||||||
@(href: &str, small: bool, dark: bool, picture: Content)
|
@use crate::icon::Icon;
|
||||||
|
@use crate::templates::image;
|
||||||
|
|
||||||
@if small {
|
@(icon: &Icon)
|
||||||
@if dark {
|
|
||||||
<a href="@href" class="toolkit-icon--link toolkit-icon--link__small toolkit-dark">
|
<a href="@icon.href" class="@icon.class_string()">
|
||||||
<div class="toolkit-icon">
|
<div class="toolkit-icon">
|
||||||
@:picture()
|
@if let Some(img) = icon.image_opt() {
|
||||||
</div>
|
@:image(img)
|
||||||
</a>
|
}
|
||||||
} else {
|
</div>
|
||||||
<a href="@href" class="toolkit-icon--link toolkit-icon--link__small">
|
</a>
|
||||||
<div class="toolkit-icon">
|
|
||||||
@:picture()
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
@if dark {
|
|
||||||
<a href="@href" class="toolkit-icon--link toolkit-dark">
|
|
||||||
<div class="toolkit-icon">
|
|
||||||
@:picture()
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
} else {
|
|
||||||
<a href="@href" class="toolkit-icon--link">
|
|
||||||
<div class="toolkit-icon">
|
|
||||||
@:picture()
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
17
toolkit/templates/image.rs.html
Normal file
17
toolkit/templates/image.rs.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
@use crate::image::Image;
|
||||||
|
|
||||||
|
@(image: &dyn Image)
|
||||||
|
|
||||||
|
<picture>
|
||||||
|
@if let Some(srcset) = image.webp_srcset() {
|
||||||
|
<source type="image/webp" srcset="@srcset" />
|
||||||
|
}
|
||||||
|
@if let Some(srcset) = image.png_srcset() {
|
||||||
|
<source type="image/png" srcset="@srcset" />
|
||||||
|
}
|
||||||
|
@if let Some(srcset) = image.jpeg_srcset() {
|
||||||
|
<source type="image/jpeg" srcset="@srcset" />
|
||||||
|
}
|
||||||
|
|
||||||
|
<img src="@image.src()" title="@image.title()" alt="@image.title()" />
|
||||||
|
</picture>
|
|
@ -1,49 +1,26 @@
|
||||||
@use crate::templates::{icon, banner};
|
@use crate::templates::{icon, banner};
|
||||||
|
@use crate::profile::Profile;
|
||||||
|
|
||||||
@(view_path: &str, display_name: Option<&str>, handle: &str, description: Option<&str>, dark: bool, icon_img: Content, banner_img: Content)
|
@(profile: &Profile)
|
||||||
|
|
||||||
@if dark {
|
<div class="@profile.class_string()">
|
||||||
<div class="toolkit-profile toolkit-dark">
|
@:banner(&profile.banner)
|
||||||
@:banner(dark, { @:banner_img() })
|
<div class="toolkit-profile--content">
|
||||||
<div class="toolkit-profile--content">
|
<div class="toolkit-profile--content--top">
|
||||||
<div class="toolkit-profile--content--top">
|
@:icon(&profile.icon)
|
||||||
@:icon(view_path, false, dark, { @:icon_img() })
|
<div class="toolkit-profile--meta">
|
||||||
<div class="toolkit-profile--meta">
|
<div class="toolkit-profile--meta--display">
|
||||||
<div class="toolkit-profile--meta--display">
|
@if let Some(display_name) = &profile.display_name {
|
||||||
@if let Some(display_name) = display_name {
|
@display_name
|
||||||
@display_name
|
} else {
|
||||||
} else {
|
|
||||||
|
}
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="toolkit-profile--meta--handle">@handle</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="toolkit-profile--meta--handle">@profile.handle</div>
|
||||||
</div>
|
</div>
|
||||||
@if let Some(description) = description {
|
|
||||||
<div class="toolkit-profile--description">@description</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
|
@if let Some(description) = &profile.description {
|
||||||
|
<div class="toolkit-profile--description">@description</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
} else {
|
</div>
|
||||||
<div class="toolkit-profile">
|
|
||||||
@:banner(dark, { @:banner_img() })
|
|
||||||
<div class="toolkit-profile--content">
|
|
||||||
<div class="toolkit-profile--content--top">
|
|
||||||
@:icon(view_path, false, dark, { @:icon_img() })
|
|
||||||
<div class="toolkit-profile--meta">
|
|
||||||
<div class="toolkit-profile--meta--display">
|
|
||||||
@if let Some(display_name) = display_name {
|
|
||||||
@display_name
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div class="toolkit-profile--meta--handle">@handle</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@if let Some(description) = description {
|
|
||||||
<div class="toolkit-profile--description">@description</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
13
toolkit/templates/tile.rs.html
Normal file
13
toolkit/templates/tile.rs.html
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
@use crate::link::Link;
|
||||||
|
@use crate::tile::Tile;
|
||||||
|
@use crate::templates::{link, tile_inner};
|
||||||
|
|
||||||
|
@(tile: &Tile)
|
||||||
|
|
||||||
|
@if let Some(href) = &tile.link {
|
||||||
|
@:link(&Link::current_tab(href).plain(true).dark(true), {
|
||||||
|
@:tile_inner(tile)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
@:tile_inner(tile)
|
||||||
|
}
|
20
toolkit/templates/tile_inner.rs.html
Normal file
20
toolkit/templates/tile_inner.rs.html
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
@use crate::tile::Tile;
|
||||||
|
@use crate::templates::image;
|
||||||
|
|
||||||
|
@(tile: &Tile)
|
||||||
|
|
||||||
|
<div class="@tile.class_string()">
|
||||||
|
<div class="toolkit-tile--overlay">
|
||||||
|
@if tile.title.is_some() || tile.description.is_some() {
|
||||||
|
<div class="toolkit-tile--meta">
|
||||||
|
@if let Some(title) = &tile.title {
|
||||||
|
<h2>@title</h2>
|
||||||
|
}
|
||||||
|
@if let Some(description) = &tile.description {
|
||||||
|
<p>@description</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
@:image(tile.image())
|
||||||
|
</div>
|
5
toolkit/templates/tiles.rs.html
Normal file
5
toolkit/templates/tiles.rs.html
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
@(body: Content)
|
||||||
|
|
||||||
|
<div class="toolkit-tiles">
|
||||||
|
@:body()
|
||||||
|
</div>
|
Loading…
Reference in a new issue