initial os release. I really expect SO much bugs, guys. good luck =)
This commit is contained in:
commit
a6eac5275c
47 changed files with 7965 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
**/target
|
||||||
|
rust-toolchain.toml
|
||||||
|
.vscode
|
||||||
|
.profile
|
||||||
1476
Cargo.lock
generated
Normal file
1476
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
80
Cargo.toml
Normal file
80
Cargo.toml
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
|
members = [
|
||||||
|
"sabry_procmacro",
|
||||||
|
"sabry_procmacro_impl",
|
||||||
|
"sabry_intrnl",
|
||||||
|
]
|
||||||
|
exclude = [
|
||||||
|
"examples"
|
||||||
|
]
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
sabry_intrnl = {path = "sabry_intrnl", version = "0.0.1"}
|
||||||
|
sabry_procmacro = {path = "sabry_procmacro", version = "0.0.1"}
|
||||||
|
sabry_procmacro_impl = {path = "sabry_procmacro_impl", version = "0.0.1"}
|
||||||
|
sabry_build = {path = "sabry_build", version = "0.0.1"}
|
||||||
|
|
||||||
|
syn = {version = "^2.0"}
|
||||||
|
quote = {version = "^1.0"}
|
||||||
|
proc-macro2 = {version = "^1.0"}
|
||||||
|
raffia = {version = "^0.9"}
|
||||||
|
regex = {version = "^1.11"}
|
||||||
|
grass = {version = "^0.13"}
|
||||||
|
lightningcss = {version = "1.0.0-alpha.59"}
|
||||||
|
blake3 = {version = "^1.5"}
|
||||||
|
base64 = {version = "^0.22"}
|
||||||
|
const_format = {version = "^0.2"}
|
||||||
|
|
||||||
|
thiserror = {version = "^1.0"}
|
||||||
|
serde = {version = "^1.0"}
|
||||||
|
toml = {version = "^0.8"}
|
||||||
|
|
||||||
|
|
||||||
|
[workspace.package]
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.82"
|
||||||
|
authors = ["Svyatoslav Pushkarev <yiffyrusdev@yandex.ru>"]
|
||||||
|
license = "MIT"
|
||||||
|
publish = true
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "sabry"
|
||||||
|
description = "Syntactically Awesome But RustY - crate that brings SCSS/SASS into rust."
|
||||||
|
keywords = ["web", "sass", "scss", "macro"]
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
authors.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
publish.workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sabry_procmacro = {workspace = true, optional = true}
|
||||||
|
sabry_build = {workspace = true, optional = true}
|
||||||
|
sabry_intrnl = {workspace = true}
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["scss"]
|
||||||
|
procmacro = [
|
||||||
|
"dep:sabry_procmacro"
|
||||||
|
]
|
||||||
|
sass = [
|
||||||
|
"procmacro",
|
||||||
|
"sabry_procmacro/sass",
|
||||||
|
"sabry_intrnl/sass",
|
||||||
|
"sabry_build/sass"
|
||||||
|
]
|
||||||
|
scss = [
|
||||||
|
"procmacro",
|
||||||
|
"sabry_procmacro/scss",
|
||||||
|
"sabry_intrnl/scss",
|
||||||
|
"sabry_build/scss"
|
||||||
|
]
|
||||||
|
build = [
|
||||||
|
"dep:sabry_build"
|
||||||
|
]
|
||||||
|
net-files = [
|
||||||
|
"sabry_build/net-files"
|
||||||
|
]
|
||||||
0
LICENSE
Normal file
0
LICENSE
Normal file
589
README.md
Normal file
589
README.md
Normal file
|
|
@ -0,0 +1,589 @@
|
||||||
|
# 🧙🏻 SABRY - Syntactically Awesome, But RustY
|
||||||
|
|
||||||
|
**Y**et another **R**usty **B**oilerplate-free **A**gnostic **S**tyling crate, which brings your SASS/SCSS style into Rust. Written by a fox this time.
|
||||||
|
|
||||||
|
\* sabry isn't "syntactically awesome", it refers to SASS abbr expansion.
|
||||||
|
|
||||||
|
> **Project status** - early, good enough for my team's non-critical "for-fun" pre-production, on demand. WIP features have no ETA. I'm pretty happy with ergonomics and taste of the crate, and I'll do my best to keep DX the way it is between minor versions - but there's no guarantee on backwards-compatibility and no refunds if something breaks.
|
||||||
|
>
|
||||||
|
> "master" branch is what's currently on crates.io
|
||||||
|
>
|
||||||
|
> each version ever been on crates.io (except the latest release) is available in "r_x.x.x" branch
|
||||||
|
>
|
||||||
|
> the latest-trashy state is in the "window" branch
|
||||||
|
|
||||||
|
At first, I'll show how this crate "tastes". With SABRY, its in your power to:
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Write arbitrary SASS/SCSS code and ship it *as a crate* however you please: with modules, with feature flags, etc. Say "bye" to manual copying, cli-tools and consts.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
sassy!(tokens {@mixin colored{color: red;}});
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
📦
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Code your SASS in separate files to get proper syntax highlighting, or do sass-in-the-rust to keep things in one place
|
||||||
|
|
||||||
|
```rust
|
||||||
|
styly!(component {.btn {color: green;}});
|
||||||
|
styly!(extras "src/components/extras.scss");
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
:3
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Depend on styles with cargo, at build time, which brings all the rusty sweeties in: versions, updates, cratesio, local registries, workspaces, etc.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[build-dependencies]
|
||||||
|
tgk_brandstyle = {version = "0.0.1", features = ["utils"]}
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
🦀
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
`@use` your style-crates in sass code *naturally*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
styly!(breadcumb {
|
||||||
|
@use 'tokens';
|
||||||
|
.scope {@include tokens.badge(primary);}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
🪄
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Keep things as private and modular as you wish
|
||||||
|
|
||||||
|
```rust
|
||||||
|
styly!(pub cats "src/sections/cats/style.scss");
|
||||||
|
styly!(dogs {#howl {border: none;}})
|
||||||
|
|
||||||
|
/// something like render function
|
||||||
|
{
|
||||||
|
<div class={cats::meow}>
|
||||||
|
<ul id={dogs::thehowl}></ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
^_^
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
Compile all the sweet SASS/SCSS into the optimized CSS bundle, ship it in CSS shunks or even include the compiled style into the binary
|
||||||
|
|
||||||
|
```rust
|
||||||
|
styly!(cssbundle {.c1 {color: white;}})
|
||||||
|
styly!(const binary {.c2 {color: black;}})
|
||||||
|
```
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
🏗️
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
Sabry will gladly:
|
||||||
|
|
||||||
|
- scope and hash your styles, so they won't conflict, with amazing [raffia](https://crates.io/crates/raffia) parser
|
||||||
|
- compile SASS/SCSS into CSS with [grass](https://crates.io/crates/grass)
|
||||||
|
- optimize produced CSS with [lightningcss](https://crates.io/crates/lightningcss)
|
||||||
|
- prepare ready CSS bundle and put it wherever you wish
|
||||||
|
- include CSS into the build artifact - if you really want it
|
||||||
|
|
||||||
|
Also, just about everything is pub-available in this crate - Sabry is ready for experiments.
|
||||||
|
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Feel free to check out examples:
|
||||||
|
|
||||||
|
|[crate of styles](./examples//define-styles/)|[style usage](./examples/use-styles/)|[leptox-axum with sabry](./examples/leptos-axum)|
|
||||||
|
|-|-|-|
|
||||||
|
|
||||||
|
### Create a crate full of arbitrary SASS
|
||||||
|
|
||||||
|
The only need is the dependency
|
||||||
|
|
||||||
|
```toml
|
||||||
|
#Cargo.toml
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sabry = {version = "0.0.1"}
|
||||||
|
```
|
||||||
|
And a proc-macro
|
||||||
|
```rust
|
||||||
|
// lib.rs
|
||||||
|
use sabry::sassy;
|
||||||
|
|
||||||
|
sassy!(mixins "assets/mixins.scss");
|
||||||
|
sassy!(styles {
|
||||||
|
$primary-color: black;
|
||||||
|
@mixin colored($col: primary) {
|
||||||
|
@if $col == primary {
|
||||||
|
color: $primary-color;
|
||||||
|
} @else {
|
||||||
|
color: $col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
Now you can build and see two ready for export macros: `mixins!` and `styles!`.
|
||||||
|
These are usefull on their own, as invocation of `mixins!()` or `styles!()` - both shall give you the code literal.
|
||||||
|
|
||||||
|
However there's more sweet use case for them, which is covered below.
|
||||||
|
|
||||||
|
### Write scoped styles
|
||||||
|
|
||||||
|
Depend on sabry
|
||||||
|
```toml
|
||||||
|
# Cargo.toml
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sabry = {version = "0.0.1"}
|
||||||
|
```
|
||||||
|
And create a style scope wherever you want:
|
||||||
|
```rust
|
||||||
|
// breadcumblist.rs
|
||||||
|
use sabry::styly;
|
||||||
|
|
||||||
|
styly!(const styles {
|
||||||
|
.cumbs {
|
||||||
|
display: flex;
|
||||||
|
&__list {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#wolf {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fn render() -> HtmlElement {
|
||||||
|
div().class(styles::cumbs).chain(
|
||||||
|
ul().class(styles::_list(styles::cumbs))
|
||||||
|
).chain(
|
||||||
|
span().id(styles::thewolf)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> That `const` usage is covered in the [following](#constant-styly-scopes) section. In this example we dont invoke sabry build-magic, so, to be as close to real life as possible, I used a const.
|
||||||
|
|
||||||
|
Every selector, if that does make sense, now available for you as a member of `styles` scope. In this example - `styles::cumbs`, `styles::thewolf` and `styles::_list()`. More about scoping and member names you can read [here](#styly-scopes).
|
||||||
|
|
||||||
|
### Use styles earlier created in another crate
|
||||||
|
|
||||||
|
The combination of previous two, with some additional work to do and some extra sugar to enjoy.
|
||||||
|
|
||||||
|
Sabry is needed as both dependency and build-dependency.
|
||||||
|
To be able to compile all styles sabry also needs the *build* feature flag:
|
||||||
|
```toml
|
||||||
|
# Cargo.toml
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sabry = {version = "0.0.1"}
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
sabry = {version = "0.0.1", features = ["build"]}
|
||||||
|
```
|
||||||
|
> If you do use some non-default feature flags make sure to keep them in sync between sabry-dependency and sabry-build-dependency.
|
||||||
|
|
||||||
|
Then you have to tell sabry when code should be compiled. We'll do this in *build.rs* file.
|
||||||
|
```rust
|
||||||
|
// build.rs
|
||||||
|
use shared_styles::{mixins, styles};
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
sabry::buildy(
|
||||||
|
sabry::usey!(
|
||||||
|
mixins!(),
|
||||||
|
styles!()
|
||||||
|
)
|
||||||
|
).expect("Failed to build sabry styles");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`buildy` is the entry function of sabry build-time process. The handy `usey!` macro will do just proper handling of our style-macros for it.
|
||||||
|
|
||||||
|
Now lets get back to the code and use the mixin defined in another crate:
|
||||||
|
```rust
|
||||||
|
// breadcumblist.rs
|
||||||
|
use sabry::styly;
|
||||||
|
|
||||||
|
styly!(styles {
|
||||||
|
@use "mixins";
|
||||||
|
.cumbs {
|
||||||
|
display: flex;
|
||||||
|
&__list {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#wolf {
|
||||||
|
@include mixins.colored(white);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
fn render() -> HtmlElement {
|
||||||
|
div().class(styles::cumbs).chain(
|
||||||
|
ul().class(styles::_list(styles::cumbs))
|
||||||
|
).chain(
|
||||||
|
span().id(styles::thewolf)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
So the `mixins!` macro we just passed to the `usey!` macro inside of `buildy` function call is now accessible with simple and natural `@use "mixins"` SASS rule!
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Sabry configuration lives in `[package.metadata.sabry]` table of the manifest file.
|
||||||
|
|
||||||
|
All configurations are optional, but with default configuration sabry won't produce any CSS files.
|
||||||
|
|
||||||
|
Full example, close to defaults:
|
||||||
|
```toml
|
||||||
|
# Cargo.toml
|
||||||
|
|
||||||
|
[package.metadata.sabry]
|
||||||
|
css.bundle = "target/static/style.css"
|
||||||
|
css.bundle_prelude = ["assets/prelude.css"]
|
||||||
|
css.scopes = "target/statis/scopes/"
|
||||||
|
css.minify = true
|
||||||
|
|
||||||
|
sass.intermediate_dir = "target/.sabry/sass"
|
||||||
|
sass.module_name_collision = "merge"
|
||||||
|
sass.modules = ["assets/sass/mod1.scss"]
|
||||||
|
sass.scanroot = "src"
|
||||||
|
|
||||||
|
hash.size = 6
|
||||||
|
hash.collision = "error"
|
||||||
|
hash.use_scope_name = true
|
||||||
|
hash.use_code_size = true
|
||||||
|
hash.use_item_names = false
|
||||||
|
hash.use_code_text = false
|
||||||
|
|
||||||
|
[package.metadata.sabry.lightningcss.targets]
|
||||||
|
chrome = "120"
|
||||||
|
safari = "13.2"
|
||||||
|
ie = "6"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `sabry.css`
|
||||||
|
|
||||||
|
**bundle** *(no default)* - file path ro write CSS bundle into relative to project root
|
||||||
|
|
||||||
|
**bundle_prelude** *(no default)* - collection of CSS files, relative to the project root, which content will be inserted before the compiled style into the *bundle* file if any
|
||||||
|
|
||||||
|
**scopes** *(no default)* - dir path to put separate CSS for every scope into relative to project root
|
||||||
|
|
||||||
|
**minify** *(default true)* - print compressed CSS output and do the lightningcss thing
|
||||||
|
|
||||||
|
### `sabry.sass`
|
||||||
|
|
||||||
|
**intermediate_dir** *(default "target/.sabry/sass")* - file to put SASS/SCSS modules into so they are available with `@use` in code
|
||||||
|
|
||||||
|
**scanroot** *(default "src")* - root directory to start scanning "rs" files from. Used in build function
|
||||||
|
|
||||||
|
**modules** *(no default)* - collection of SASS/SCSS files, relative to the project root, which should be available as modules as well
|
||||||
|
|
||||||
|
**module_name_collision** *(default "merge")* - how to handle similary named modules.
|
||||||
|
|
||||||
|
*merge* - merge content
|
||||||
|
|
||||||
|
*error* - break building process with an error
|
||||||
|
|
||||||
|
### `sabry.hash`
|
||||||
|
|
||||||
|
**size** *(default 6)* - size of hash in bytes. Feel free to increase/decrease.
|
||||||
|
|
||||||
|
**use_scope_name** *(default true)* - wether to use scope identifier to calculate hash
|
||||||
|
|
||||||
|
**use_code_size** *(default true)* - wether to use scope code size to calculate hash
|
||||||
|
|
||||||
|
**use_item_names** *(default false)* - wether to use all scoped item idents to calculate hash
|
||||||
|
|
||||||
|
**use_code_text** *(default false)* - wether to use the scope code text to calculate hash
|
||||||
|
|
||||||
|
**collision** *(default "ignore")* - how to handle similarity of generated hashes
|
||||||
|
|
||||||
|
*ignore* - dont do anything
|
||||||
|
|
||||||
|
*error* - break building process with an error
|
||||||
|
|
||||||
|
### `sabry.lightningcss.targets`
|
||||||
|
|
||||||
|
Does require `css.minify` to be *true*.
|
||||||
|
|
||||||
|
Empty by default.
|
||||||
|
|
||||||
|
Available keys: chrome, firefox, edge, safari, saf_ios, samsung, android, ie
|
||||||
|
|
||||||
|
Value - minimal browser version to support in "M.m.p" format, where:
|
||||||
|
|
||||||
|
- *M* - major
|
||||||
|
- *m* - minor
|
||||||
|
- *p* - patch
|
||||||
|
|
||||||
|
For example `{ie = "9", saf_ios = "13.2"}` will try to generate CSS supported on both IE 9 and Safari-on-ios 13.2
|
||||||
|
|
||||||
|
## Detailed guide
|
||||||
|
|
||||||
|
### Style definition with `sassy!`
|
||||||
|
|
||||||
|
The `sassy!` macro is available with *procmacro* feature which is enabled by default.
|
||||||
|
|
||||||
|
It does accept the following syntax: `$name(:$syntax)? ({ $code })|($filename)`, where
|
||||||
|
|
||||||
|
- *$name* is any identifier valid for `macro_rules!`
|
||||||
|
- *$syntax* is either `sass` or `scss`
|
||||||
|
- *$code* is valid arbitrary style code in specified syntax
|
||||||
|
- *$filename* is a string literal which contains path to the file relative to package root
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
```rust
|
||||||
|
sassy!(module1 {$primary-color: red;});
|
||||||
|
sassy!(module2 "src/assets/module2.scss");
|
||||||
|
sassy!(module3:sass "src/assets/module3.sass");
|
||||||
|
// works, but there are catches.
|
||||||
|
sassy!(module4:sass {
|
||||||
|
=colored
|
||||||
|
color: red
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
You may omit the syntax specifier - sabry uses SCSS as the default one.
|
||||||
|
|
||||||
|
The given code to `sassy!` is not checked to be valid code in given syntax (wip).
|
||||||
|
|
||||||
|
> SASS support inside of rust files is experimental. If you do want to use SASS tabbed syntax - consider to use files path instead of sass-in-rust option.
|
||||||
|
|
||||||
|
### Scoping with `styly!`
|
||||||
|
|
||||||
|
The `styly!` macro is available with *procmacro* feature flag which is enabled by default.
|
||||||
|
|
||||||
|
It does accept the following syntax: `pub? const? $ident(:$syntax)? ({ $code })|($filename)`, where
|
||||||
|
|
||||||
|
- *pub* is explained [here](#public-styly-scopes)
|
||||||
|
- *const* is explained [here](#constant-styly-scopes)
|
||||||
|
- *$ident* is any identifier valid for `mod`
|
||||||
|
- *$syntax* is either `sass` or `scss`
|
||||||
|
- *$code* is arbitrary style code valid with given syntax
|
||||||
|
- *$filename* is a string literal which contains path to the file relative to package root
|
||||||
|
|
||||||
|
Examples
|
||||||
|
```rust
|
||||||
|
styly!(fox {.fur {color: red; &-dark {color: black;}}})
|
||||||
|
styly!(pub fox {.fur {color: red; &-dark {color: black;}}})
|
||||||
|
styly!(pub const fox:sass {
|
||||||
|
.fur
|
||||||
|
color: red
|
||||||
|
&-dark
|
||||||
|
color: black
|
||||||
|
})
|
||||||
|
```
|
||||||
|
Every of those calls will produce the styling scope as a module. Differences are explained right below.
|
||||||
|
|
||||||
|
In general the scope does look like this:
|
||||||
|
```rust
|
||||||
|
const FOX: &str = "J9k_s9";
|
||||||
|
mod fox {
|
||||||
|
pub const fur: &str = "J9k_s9 fur";
|
||||||
|
pub fn _dark(c: &str) -> String {format!("{c}-dark")}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Styly scopes
|
||||||
|
|
||||||
|
Styly macro itself does not generate the scope. It is done in the `sabry_intrnl::scoper`. However, as a result, you will have the following:
|
||||||
|
|
||||||
|
- `const` with the UPPER_CASE name of the scope, which contains its hash
|
||||||
|
- `mod` with exact scope name which is the scope you're going to use
|
||||||
|
- for simple selectors, like `.fur` you will have a const members with hashed original selectors to use wherever you need a class/id/etc.
|
||||||
|
- for parent-selectors like `&-dark` you will have a non-const function, which will create matching the selector from any other.
|
||||||
|
|
||||||
|
You can read more about scoping and hashing in the [scoping](#scoping) section.
|
||||||
|
|
||||||
|
#### Public styly scopes
|
||||||
|
|
||||||
|
By default generated `mod` is private. You can make both mod and wrapper style constant public by adding the `pub` to macro call:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
styly!(pub whatever "src/assets/whatever.scss");
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Constant styly scopes
|
||||||
|
|
||||||
|
As you've seen above, scope doe not contain any style code by itself. That's the use case i advise mostly.
|
||||||
|
|
||||||
|
However you could still compile styles into the artifact by simply adding the `const` to the macro call:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
styly!(const scope "src/assets/scope.scss");
|
||||||
|
```
|
||||||
|
Which results in following:
|
||||||
|
```rust
|
||||||
|
const SCOPE: &str = /* scope hash */;
|
||||||
|
const SCOPE_CSS: &str = /* compiled from src/assets/scope.scss */;
|
||||||
|
mod scope {/* selector collection */}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **There is a catch** | with the `const` modifier macro must compile CSS at compile-time. That results in several game changers:
|
||||||
|
>
|
||||||
|
> *First*. You could avoid the "build magic". Sabry will just compile given styles with procmacro at compile time.
|
||||||
|
>
|
||||||
|
> *Second*. If you `@use` something inside of constant-flavored scope, you can only success if sabry *did the build magic before compilation of that macro call*. So you still can compile the styles into the artifact and enjoy mixins from other crates, but, in general, you are going to receive some false-positives from editor.
|
||||||
|
>
|
||||||
|
> Worth of notice: sabry will still include const-flavored styles into the CSS bundle during build time.
|
||||||
|
|
||||||
|
### Building with `buildy` and `usey!`
|
||||||
|
|
||||||
|
The `buildy` function is available with *build* feature which needs to be enabled explicitly.
|
||||||
|
|
||||||
|
This function accepts an iterator of pairs: (file_name, code) in form of `(String, String)` type. File name should have an extension, so grass can infere syntax during CSS compilation.
|
||||||
|
|
||||||
|
Each of those pairs is processed as a file which sabry needs to write into
|
||||||
|
the configured `intermediate_dir` and then passed into the CSS compiler.
|
||||||
|
|
||||||
|
You could, for example, define the module "mixin_a":
|
||||||
|
```rust
|
||||||
|
buildy(vec![("mixin_a".to_string(), "@mixin a(){}".to_string())]);
|
||||||
|
```
|
||||||
|
|
||||||
|
However there's a usey macro, which handles this for you:
|
||||||
|
```rust
|
||||||
|
buildy(
|
||||||
|
usey!(mixins!(), utils!())
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `usey!` macro accepts the following syntax:
|
||||||
|
`#($macro,)*`, where
|
||||||
|
|
||||||
|
- *$macro* is a macro which handles three expansions:
|
||||||
|
- `() => { $code }`
|
||||||
|
- `(name) => { $name }`
|
||||||
|
- `(syntax) => { $syntax }`
|
||||||
|
|
||||||
|
Where for the *$macro*:
|
||||||
|
|
||||||
|
- *$code* is a source code of style as a string literal
|
||||||
|
- *$name* is a name of module without extension as a string literal
|
||||||
|
- *$syntax* is either "sass" or "scss"
|
||||||
|
|
||||||
|
|
||||||
|
Exactly this kind of macros is produced by [`sassy!`](#style-definition-with-sassy).
|
||||||
|
|
||||||
|
### Scoping
|
||||||
|
|
||||||
|
Sabry handles scoping by restriction or mutation of existing selectors
|
||||||
|
with the hash. Hash is calculated for the entire scope by the [`styly!`](#scoping-with-styly) macro.
|
||||||
|
|
||||||
|
Currently the following types of selectors are scoped:
|
||||||
|
|
||||||
|
- class
|
||||||
|
- id
|
||||||
|
- SASS parent selectors (see below, there is a catch)
|
||||||
|
- tagname (see below, there is a catch)
|
||||||
|
|
||||||
|
Sabry does not make difference between top-level and nested selectors,
|
||||||
|
also selector complexity isn't taken into account: sabry simply walks through all compound selectors
|
||||||
|
and apply scoping for supported ones.
|
||||||
|
|
||||||
|
Different selector types are scoped differently:
|
||||||
|
|
||||||
|
- class selectors are restricted with scope hash: `.class` -> `.HASH.class`
|
||||||
|
- id selector are mutated with scope hash: `#id` -> `#id-HASH`
|
||||||
|
- tagname selectors are changed into indirect descendance: `div` -> `.HASH div`
|
||||||
|
|
||||||
|
> **There is a catch** | currently tagname selectors are scoped with indirect descendancy
|
||||||
|
> hash restriction. That means - if you do use tagnames in scoped stylesheets, you have to wrap your markdown
|
||||||
|
> with `SCOPE` class generated by `styly!` macro.
|
||||||
|
>
|
||||||
|
> Also if there are nested tagname selectors - sabry won't take this into account and you'll
|
||||||
|
> have to wrap them with `SCOPE` class as well
|
||||||
|
|
||||||
|
As for **SASS parent selectors**: they are currently handled in different way. Instead of
|
||||||
|
walking up the syntax tree sabry just creates function member for the scope and leave the rest to grass:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
styly!(scope {
|
||||||
|
.cls1 {
|
||||||
|
&-dark {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
is something like
|
||||||
|
```rust
|
||||||
|
const SCOPE: &str = "Ut8CskJ";
|
||||||
|
mod scope {
|
||||||
|
pub const cls1: &str = "Ut8CskJ cls1";
|
||||||
|
pub fn _dark(c: &str) -> String {format!("{c}-dark")}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
So you still can get the scoped variant of `cls1-dark` class: `scope::_dark(scope::cls1)`.
|
||||||
|
|
||||||
|
This isn't very handy, also isn't strict enough, and is a high-priority subject to change. wip.
|
||||||
|
|
||||||
|
## WIP
|
||||||
|
|
||||||
|
*(sorted by my own priority)*, "dones" are excluded
|
||||||
|
|
||||||
|
- [] Crates of styled components - currently the only way to create them seems to be const styly.
|
||||||
|
- [] CSS support
|
||||||
|
- [] There are some strange parsing errors, seems like a bug, however very hard to reproduce. Have to investigate. Maybe do more tests.
|
||||||
|
- [] Experience with cargo-leptos is fine, and we do use it, however its a bit "raughy". Need to do something about it.
|
||||||
|
|
||||||
|
## Contributions
|
||||||
|
|
||||||
|
Any contributions are always welcome!
|
||||||
|
|
||||||
|
If you find this crate usefull, wanna stick with it in some project, but do miss some
|
||||||
|
features - feel free to submit a PR.
|
||||||
|
|
||||||
|
> If you'd like to fork for the PR - please, use the "window" branch, not the "master".
|
||||||
|
|
||||||
|
If you encounter any bugs/problems or have use case where things dont work as they should
|
||||||
|
for the latest version - please, open an issue!
|
||||||
|
|
||||||
|
If you'd like to lend a paw - feel free to check the [WIP](#wip) section out, or to search for "TODO" comments.
|
||||||
|
|
||||||
|
## MSRV
|
||||||
|
|
||||||
|
Sabry passes its own tests on 1.82 nightly.
|
||||||
|
|
||||||
|
There *were* some strange parsing issues reports on *stable* channel, seems to be fixed. idk.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT.
|
||||||
1483
examples/define-styles/Cargo.lock
generated
Normal file
1483
examples/define-styles/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
9
examples/define-styles/Cargo.toml
Normal file
9
examples/define-styles/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "define-styles"
|
||||||
|
version = "0.0.0"
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.82"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sabry = {path = "../../", features = ["sass"]}
|
||||||
104
examples/define-styles/src/lib.rs
Normal file
104
examples/define-styles/src/lib.rs
Normal file
|
|
@ -0,0 +1,104 @@
|
||||||
|
use sabry::sassy;
|
||||||
|
|
||||||
|
sassy!(utils {
|
||||||
|
@mixin flex($direction, $align, $justify, $gap: .5rem) {
|
||||||
|
display: flex;
|
||||||
|
list-style: none;
|
||||||
|
gap: $gap;
|
||||||
|
flex-direction: $direction;
|
||||||
|
|
||||||
|
@if $align == start{
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
@else if $align == end{
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
@else{
|
||||||
|
align-items: $align;
|
||||||
|
}
|
||||||
|
|
||||||
|
@if $justify == start {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
@else if $justify == end {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
@else {
|
||||||
|
justify-content: $justify;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sassy!(theme {
|
||||||
|
$thm-surface-primary: #2b2a29;
|
||||||
|
$thm-surface-secondary: #6C6C6C;
|
||||||
|
$thm-surface-tertiary: #4C4C4C;
|
||||||
|
$thm-surface-accent: #B0CB1F;
|
||||||
|
|
||||||
|
$thm-text-primary: #ffffff;
|
||||||
|
$thm-text-secondary: #ffffff;
|
||||||
|
$thm-text-tertiary: #ffffff;
|
||||||
|
$thm-text-accent: #B0CB1F;
|
||||||
|
|
||||||
|
@mixin surface($style: primary) {
|
||||||
|
@if $style == primary {
|
||||||
|
@include txt(primary);
|
||||||
|
background-color: $thm-surface-primary;
|
||||||
|
}
|
||||||
|
@else if $style == secondary {
|
||||||
|
@include txt(secondary);
|
||||||
|
background-color: $thm-surface-secondary;
|
||||||
|
}
|
||||||
|
@else if $style == accent {
|
||||||
|
@include txt;
|
||||||
|
background-color: $thm-surface-accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin txt($style: primary) {
|
||||||
|
@if $style == primary {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $thm-text-primary;
|
||||||
|
}
|
||||||
|
@else if $style == secondary {
|
||||||
|
font-weight: 400;
|
||||||
|
color: $thm-text-secondary;
|
||||||
|
}
|
||||||
|
@else if $style == tertiary {
|
||||||
|
font-weight: 400;
|
||||||
|
color: $thm-text-tertiary;
|
||||||
|
}
|
||||||
|
@else if $style == accent {
|
||||||
|
font-weight: 500;
|
||||||
|
color: $thm-text-accent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
sassy!(tokens {
|
||||||
|
@use "theme";
|
||||||
|
|
||||||
|
@mixin clickable($style: accent, $scale: 1.2, $clickscale: 0.9){
|
||||||
|
@if $style == accent{
|
||||||
|
@include theme.surface(accent);
|
||||||
|
}
|
||||||
|
@else if $style == secondary {
|
||||||
|
@include theme.surface(secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
-webkit-tap-highlight-color: #00000000;
|
||||||
|
transition: transform .07s, filter .07s;
|
||||||
|
&:hover{
|
||||||
|
transform: scale($scale);
|
||||||
|
}
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid #fff;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
filter: brightness(.9);
|
||||||
|
transform: scale($clickscale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
14
examples/leptos-axum/.gitignore
vendored
Normal file
14
examples/leptos-axum/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Generated by Cargo
|
||||||
|
# will have compiled files and executables
|
||||||
|
debug/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
|
Cargo.lock
|
||||||
|
|
||||||
|
# These are backup files generated by rustfmt
|
||||||
|
**/*.rs.bk
|
||||||
|
|
||||||
|
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||||
|
*.pdb
|
||||||
67
examples/leptos-axum/Cargo.toml
Normal file
67
examples/leptos-axum/Cargo.toml
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
[package]
|
||||||
|
name = "leptos-axum-sabry"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
leptos = { version = "0.7.0-gamma3" }
|
||||||
|
leptos_axum = { version = "0.7.0-gamma3", optional = true }
|
||||||
|
leptos_meta = { version = "0.7.0-gamma3" }
|
||||||
|
leptos_router = { version = "0.7.0-gamma3" }
|
||||||
|
axum = { version = "0.7", optional = true }
|
||||||
|
console_error_panic_hook = "0.1"
|
||||||
|
tokio = { version = "1", features = ["rt-multi-thread"], optional = true }
|
||||||
|
tower = { version = "0.4", optional = true }
|
||||||
|
tower-http = { version = "0.5", features = ["fs"], optional = true }
|
||||||
|
wasm-bindgen = "=0.2.93"
|
||||||
|
thiserror = "1"
|
||||||
|
tracing = { version = "0.1", optional = true }
|
||||||
|
http = "1"
|
||||||
|
|
||||||
|
# sabry with sass
|
||||||
|
sabry = {path = "../../", features = ["sass"]}
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
# sabry for build with sass
|
||||||
|
sabry = {path = "../../", features = ["build", "sass"]}
|
||||||
|
# lets depend on our styles
|
||||||
|
define-styles = {path = "../define-styles"}
|
||||||
|
|
||||||
|
[features]
|
||||||
|
hydrate = ["leptos/hydrate"]
|
||||||
|
ssr = [
|
||||||
|
"dep:axum",
|
||||||
|
"dep:tokio",
|
||||||
|
"dep:tower",
|
||||||
|
"dep:tower-http",
|
||||||
|
"dep:leptos_axum",
|
||||||
|
"leptos/ssr",
|
||||||
|
"leptos_meta/ssr",
|
||||||
|
"leptos_router/ssr",
|
||||||
|
"dep:tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata.sabry]
|
||||||
|
css.minify = true
|
||||||
|
# We'll use bundle for leptos
|
||||||
|
css.bundle = "target/.sabry/target/bundle.css"
|
||||||
|
|
||||||
|
[package.metadata.leptos]
|
||||||
|
output-name = "leptos-axum"
|
||||||
|
site-root = "target/site"
|
||||||
|
site-pkg-dir = "pkg"
|
||||||
|
# Sabry-generated bundle for leptos
|
||||||
|
style-file = "target/.sabry/target/bundle.css"
|
||||||
|
assets-dir = "public"
|
||||||
|
site-addr = "127.0.0.1:3000"
|
||||||
|
reload-port = 3001
|
||||||
|
browserquery = "defaults"
|
||||||
|
env = "DEV"
|
||||||
|
bin-features = ["ssr"]
|
||||||
|
bin-default-features = false
|
||||||
|
lib-features = ["hydrate"]
|
||||||
|
lib-default-features = false
|
||||||
24
examples/leptos-axum/LICENSE
Normal file
24
examples/leptos-axum/LICENSE
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <https://unlicense.org>
|
||||||
90
examples/leptos-axum/README.md
Normal file
90
examples/leptos-axum/README.md
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
<picture>
|
||||||
|
<source srcset="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_Solid_White.svg" media="(prefers-color-scheme: dark)">
|
||||||
|
<img src="https://raw.githubusercontent.com/leptos-rs/leptos/main/docs/logos/Leptos_logo_RGB.svg" alt="Leptos Logo">
|
||||||
|
</picture>
|
||||||
|
|
||||||
|
# Leptos Axum Starter Template
|
||||||
|
|
||||||
|
This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool using [Axum](https://github.com/tokio-rs/axum).
|
||||||
|
|
||||||
|
## Creating your template repo
|
||||||
|
|
||||||
|
If you don't have `cargo-leptos` installed you can install it with
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo install cargo-leptos --locked
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run
|
||||||
|
```bash
|
||||||
|
cargo leptos new --git https://github.com/leptos-rs/start-axum-0.7
|
||||||
|
```
|
||||||
|
|
||||||
|
to generate a new project template.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd leptos-axum
|
||||||
|
```
|
||||||
|
|
||||||
|
to go to your newly created project.
|
||||||
|
Feel free to explore the project structure, but the best place to start with your application code is in `src/app.rs`.
|
||||||
|
Addtionally, Cargo.toml may need updating as new versions of the dependencies are released, especially if things are not working after a `cargo update`.
|
||||||
|
|
||||||
|
## Running your project
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo leptos watch
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installing Additional Tools
|
||||||
|
|
||||||
|
By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools.
|
||||||
|
|
||||||
|
1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly
|
||||||
|
2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly
|
||||||
|
3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future)
|
||||||
|
4. `npm install -g sass` - install `dart-sass` (should be optional in future
|
||||||
|
|
||||||
|
## Compiling for Release
|
||||||
|
```bash
|
||||||
|
cargo leptos build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
Will generate your server binary in target/server/release and your site package in target/site
|
||||||
|
|
||||||
|
## Testing Your Project
|
||||||
|
```bash
|
||||||
|
cargo leptos end-to-end
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo leptos end-to-end --release
|
||||||
|
```
|
||||||
|
|
||||||
|
Cargo-leptos uses Playwright as the end-to-end test tool.
|
||||||
|
Tests are located in end2end/tests directory.
|
||||||
|
|
||||||
|
## Executing a Server on a Remote Machine Without the Toolchain
|
||||||
|
After running a `cargo leptos build --release` the minimum files needed are:
|
||||||
|
|
||||||
|
1. The server binary located in `target/server/release`
|
||||||
|
2. The `site` directory and all files within located in `target/site`
|
||||||
|
|
||||||
|
Copy these files to your remote server. The directory structure should be:
|
||||||
|
```text
|
||||||
|
leptos-axum
|
||||||
|
site/
|
||||||
|
```
|
||||||
|
Set the following environment variables (updating for your project as needed):
|
||||||
|
```text
|
||||||
|
LEPTOS_OUTPUT_NAME="leptos-axum"
|
||||||
|
LEPTOS_SITE_ROOT="site"
|
||||||
|
LEPTOS_SITE_PKG_DIR="pkg"
|
||||||
|
LEPTOS_SITE_ADDR="127.0.0.1:3000"
|
||||||
|
LEPTOS_RELOAD_PORT="3001"
|
||||||
|
```
|
||||||
|
Finally, run the server binary.
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
|
||||||
|
This template itself is released under the Unlicense. You should replace the LICENSE for your own application with an appropriate license if you plan to release it publicly.
|
||||||
11
examples/leptos-axum/build.rs
Normal file
11
examples/leptos-axum/build.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use define_styles::{theme, utils, tokens};
|
||||||
|
|
||||||
|
fn main(){
|
||||||
|
sabry::buildy(
|
||||||
|
sabry::usey!(
|
||||||
|
utils!(),
|
||||||
|
theme!(),
|
||||||
|
tokens!()
|
||||||
|
)
|
||||||
|
).expect("Failed to build with sabry");
|
||||||
|
}
|
||||||
BIN
examples/leptos-axum/public/favicon.ico
Normal file
BIN
examples/leptos-axum/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
10
examples/leptos-axum/src/lib.rs
Normal file
10
examples/leptos-axum/src/lib.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
pub mod shell;
|
||||||
|
pub mod routes;
|
||||||
|
|
||||||
|
#[cfg(feature = "hydrate")]
|
||||||
|
#[wasm_bindgen::prelude::wasm_bindgen]
|
||||||
|
pub fn hydrate() {
|
||||||
|
use crate::shell::*;
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
leptos::mount::hydrate_body(App);
|
||||||
|
}
|
||||||
38
examples/leptos-axum/src/main.rs
Normal file
38
examples/leptos-axum/src/main.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
#[cfg(feature = "ssr")]
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
use axum::Router;
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos_axum::{generate_route_list, LeptosRoutes};
|
||||||
|
use leptos_axum_sabry::shell::*;
|
||||||
|
|
||||||
|
let conf = get_configuration(None).unwrap();
|
||||||
|
let addr = conf.leptos_options.site_addr;
|
||||||
|
let leptos_options = conf.leptos_options;
|
||||||
|
// Generate the list of routes in your Leptos App
|
||||||
|
let routes = generate_route_list(App);
|
||||||
|
|
||||||
|
let app = Router::new()
|
||||||
|
.leptos_routes(&leptos_options, routes, {
|
||||||
|
let leptos_options = leptos_options.clone();
|
||||||
|
move || shell(leptos_options.clone())
|
||||||
|
})
|
||||||
|
.fallback(leptos_axum::file_and_error_handler(shell))
|
||||||
|
.with_state(leptos_options);
|
||||||
|
|
||||||
|
// run our app with hyper
|
||||||
|
// `axum::Server` is a re-export of `hyper::Server`
|
||||||
|
log!("listening on http://{}", &addr);
|
||||||
|
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
|
||||||
|
axum::serve(listener, app.into_make_service())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "ssr"))]
|
||||||
|
pub fn main() {
|
||||||
|
// no client-side main function
|
||||||
|
// unless we want this to work with e.g., Trunk for pure client-side testing
|
||||||
|
// see lib.rs for hydration function instead
|
||||||
|
}
|
||||||
33
examples/leptos-axum/src/routes/home.rs
Normal file
33
examples/leptos-axum/src/routes/home.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use sabry::styly;
|
||||||
|
|
||||||
|
styly!(s "src/routes/home.scss");
|
||||||
|
|
||||||
|
styly!(s2 {
|
||||||
|
@use "theme";
|
||||||
|
.card {
|
||||||
|
@include theme.surface(secondary);
|
||||||
|
}
|
||||||
|
.pocwarn {
|
||||||
|
@include theme.surface(secondary);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Renders the home page of your application.
|
||||||
|
#[component]
|
||||||
|
pub fn Route() -> impl IntoView {
|
||||||
|
// Creates a reactive value to update the button
|
||||||
|
let count = RwSignal::new(0);
|
||||||
|
let on_click = move |_| *count.write() += 1;
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<section class=s::table>
|
||||||
|
<h1>"Welcome to Leptos!"</h1>
|
||||||
|
<button class=s::btn on:click=on_click>"Ima CRAZY button, clicked: " {count} " times!"</button>
|
||||||
|
<span class=s2::card>"DISCLAIMER:"</span>
|
||||||
|
<p class=s2::pocwarn>"This isn't a design example! Its just proof of sabry's capabilities."</p>
|
||||||
|
<p class=s2::pocwarn>"Plz dont make websites/apps which look like this page :D"</p>
|
||||||
|
</section>
|
||||||
|
}
|
||||||
|
}
|
||||||
12
examples/leptos-axum/src/routes/home.scss
Normal file
12
examples/leptos-axum/src/routes/home.scss
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
@use "tokens";
|
||||||
|
@use "utils";
|
||||||
|
@use "theme";
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
@include tokens.clickable(accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
@include utils.flex(column, center, center);
|
||||||
|
@include theme.surface(primary);
|
||||||
|
}
|
||||||
1
examples/leptos-axum/src/routes/mod.rs
Normal file
1
examples/leptos-axum/src/routes/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod home;
|
||||||
43
examples/leptos-axum/src/shell.rs
Normal file
43
examples/leptos-axum/src/shell.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
use leptos::prelude::*;
|
||||||
|
use leptos_meta::{provide_meta_context, MetaTags, Stylesheet, Title};
|
||||||
|
use leptos_router::{
|
||||||
|
components::{Route, Router, Routes},
|
||||||
|
StaticSegment,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::routes;
|
||||||
|
|
||||||
|
pub fn shell(options: LeptosOptions) -> impl IntoView {
|
||||||
|
view! {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<AutoReload options=options.clone() />
|
||||||
|
<HydrationScripts options/>
|
||||||
|
<MetaTags/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<App/>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
pub fn App() -> impl IntoView {
|
||||||
|
provide_meta_context();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
<Stylesheet id="leptos" href="/pkg/leptos-axum.css"/>
|
||||||
|
<Title text="Welcome to Leptos"/>
|
||||||
|
<Router>
|
||||||
|
<main>
|
||||||
|
<Routes fallback=|| "Page not found.".into_view()>
|
||||||
|
<Route path=StaticSegment("") view=routes::home::Route/>
|
||||||
|
</Routes>
|
||||||
|
</main>
|
||||||
|
</Router>
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue