initial os release. I really expect SO much bugs, guys. good luck =)

This commit is contained in:
Yiffy Dev 2024-10-30 10:59:43 +05:00
commit a2f1b72204
No known key found for this signature in database
GPG key ID: FB83DFEAFB3F4709
47 changed files with 7965 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
**/target
rust-toolchain.toml
.vscode
.profile

1476
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

80
Cargo.toml Normal file
View 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
View file

589
README.md Normal file
View 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

File diff suppressed because it is too large Load diff

View 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"]}

View 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
View 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

View 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

View 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>

View 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.

View 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");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View 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);
}

View 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
}

View 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>
}
}

View 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);
}

View file

@ -0,0 +1 @@
pub mod home;

View 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