Merge pull request #1 from yiffyrusdev/window
Window merge (lepty-scoping)
This commit is contained in:
commit
258d362c0a
14 changed files with 255 additions and 98 deletions
1
.github/workflows/cbt.yml
vendored
1
.github/workflows/cbt.yml
vendored
|
|
@ -22,4 +22,5 @@ jobs:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
|
- run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
|
||||||
- run: cargo build --verbose
|
- run: cargo build --verbose
|
||||||
|
- run: cargo test --verbose --all
|
||||||
- run: cargo test --verbose --all --all-features
|
- run: cargo test --verbose --all --all-features
|
||||||
|
|
|
||||||
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1012,6 +1012,7 @@ version = "0.0.1-alpha.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"blake3",
|
"blake3",
|
||||||
|
"cfg-if",
|
||||||
"const_format",
|
"const_format",
|
||||||
"grass",
|
"grass",
|
||||||
"lightningcss",
|
"lightningcss",
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,9 @@ sabry_intrnl = {workspace = true}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["procmacro"]
|
default = ["procmacro"]
|
||||||
|
lepty-scoping = [
|
||||||
|
"sabry_intrnl/lepty-scoping"
|
||||||
|
]
|
||||||
procmacro = [
|
procmacro = [
|
||||||
"dep:sabry_procmacro"
|
"dep:sabry_procmacro"
|
||||||
]
|
]
|
||||||
|
|
|
||||||
21
LICENSE
21
LICENSE
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Svyatoslav Pushkarev
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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 OR COPYRIGHT HOLDERS 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.
|
||||||
97
README.md
97
README.md
|
|
@ -12,6 +12,10 @@
|
||||||
>
|
>
|
||||||
> the latest-trashy state is in the "window" branch
|
> the latest-trashy state is in the "window" branch
|
||||||
|
|
||||||
|
[](https://crates.io/crates/sabry)
|
||||||
|
[](https://docs.rs/sabry)
|
||||||
|
[](https://github.com/yiffyrusdev/sabry/blob/master/LICENSE)
|
||||||
|
|
||||||
At first, I'll show how this crate "tastes". With SABRY, its in your power to:
|
At first, I'll show how this crate "tastes". With SABRY, its in your power to:
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
|
|
@ -65,7 +69,7 @@ tgk_brandstyle = {version = "0.0.1", features = ["utils"]}
|
||||||
`@use` your style-crates in sass code *naturally*
|
`@use` your style-crates in sass code *naturally*
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
styly!(breadcumb {
|
styly!(breadbadge {
|
||||||
@use 'tokens';
|
@use 'tokens';
|
||||||
.scope {@include tokens.badge(primary);}
|
.scope {@include tokens.badge(primary);}
|
||||||
})
|
})
|
||||||
|
|
@ -130,7 +134,7 @@ Also, just about everything is pub-available in this crate - Sabry is ready for
|
||||||
|
|
||||||
Feel free to check out examples:
|
Feel free to check out examples:
|
||||||
|
|
||||||
|[crate of styles](./examples//define-styles/)|[style usage](./examples/use-styles/)|[leptox-axum with sabry](./examples/leptos-axum)|
|
|[crate of styles](./examples//define-styles/)|[style usage](./examples/use-styles/)|[leptos-axum with sabry](./examples/leptos-axum)|
|
||||||
|-|-|-|
|
|-|-|-|
|
||||||
|
|
||||||
### Create a crate full of arbitrary SASS
|
### Create a crate full of arbitrary SASS
|
||||||
|
|
@ -176,11 +180,11 @@ sabry = {version = "0.0.1"}
|
||||||
```
|
```
|
||||||
And create a style scope wherever you want:
|
And create a style scope wherever you want:
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
// breadcumblist.rs
|
// breadbadgelist.rs
|
||||||
use sabry::styly;
|
use sabry::styly;
|
||||||
|
|
||||||
styly!(const styles {
|
styly!(const styles {
|
||||||
.cumbs {
|
.badges {
|
||||||
display: flex;
|
display: flex;
|
||||||
&__list {
|
&__list {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -192,8 +196,8 @@ styly!(const styles {
|
||||||
});
|
});
|
||||||
|
|
||||||
fn render() -> HtmlElement {
|
fn render() -> HtmlElement {
|
||||||
div().class(styles::cumbs).chain(
|
div().class(styles::badges).chain(
|
||||||
ul().class(styles::_list(styles::cumbs))
|
ul().class(styles::_list(styles::badges))
|
||||||
).chain(
|
).chain(
|
||||||
span().id(styles::thewolf)
|
span().id(styles::thewolf)
|
||||||
)
|
)
|
||||||
|
|
@ -201,10 +205,12 @@ fn render() -> HtmlElement {
|
||||||
```
|
```
|
||||||
> 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.
|
> 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).
|
Every selector, if that does make sense, now available for you as a member of `styles` scope. In this example - `styles::badges`, `styles::thewolf` and `styles::_list()`. More about scoping and member names you can read [here](#styly-scopes).
|
||||||
|
|
||||||
### Use styles earlier created in another crate
|
### Use styles earlier created in another crate
|
||||||
|
|
||||||
|
> **Tip** | If you use [leptos](https://github.com/leptos-rs/leptos) - check [this](#leptos-specials) section as well
|
||||||
|
|
||||||
The combination of previous two, with some additional work to do and some extra sugar to enjoy.
|
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.
|
Sabry is needed as both dependency and build-dependency.
|
||||||
|
|
@ -238,12 +244,12 @@ fn main(){
|
||||||
|
|
||||||
Now lets get back to the code and use the mixin defined in another crate:
|
Now lets get back to the code and use the mixin defined in another crate:
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
// breadcumblist.rs
|
// breadbadgelist.rs
|
||||||
use sabry::styly;
|
use sabry::styly;
|
||||||
|
|
||||||
styly!(styles {
|
styly!(styles {
|
||||||
@use "mixins";
|
@use "mixins";
|
||||||
.cumbs {
|
.badges {
|
||||||
display: flex;
|
display: flex;
|
||||||
&__list {
|
&__list {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -255,8 +261,8 @@ styly!(styles {
|
||||||
});
|
});
|
||||||
|
|
||||||
fn render() -> HtmlElement {
|
fn render() -> HtmlElement {
|
||||||
div().class(styles::cumbs).chain(
|
div().class(styles::badges).chain(
|
||||||
ul().class(styles::_list(styles::cumbs))
|
ul().class(styles::_list(styles::badges))
|
||||||
).chain(
|
).chain(
|
||||||
span().id(styles::thewolf)
|
span().id(styles::thewolf)
|
||||||
)
|
)
|
||||||
|
|
@ -264,6 +270,73 @@ fn render() -> HtmlElement {
|
||||||
```
|
```
|
||||||
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!
|
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!
|
||||||
|
|
||||||
|
### Leptos specials
|
||||||
|
|
||||||
|
With [leptos](https://github.com/leptos-rs/leptos) framework you can do the trick to apply some class to most of HtmlElements for the entire component/island:
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
#[component]
|
||||||
|
fn component() -> impl IntoView {
|
||||||
|
view! {class="cls1", /* <- here */
|
||||||
|
<h1>"Head"</h1>
|
||||||
|
<p>"text"</p>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
... and have "cls1" on both `h1` and `p` auto-assigned. Isn't this cool?
|
||||||
|
|
||||||
|
So, if you're on leptos, and don't mind to take this approach, I'd highly recommend turning the *lepty-scoping* feature on:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# Cargo.toml
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
sabry = {version = "0.0.1", features = ["lepty-scoping"]}
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
sabry = {version = "0.0.1", features = ["build", "lepty-scoping"]}
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
styly!(scope {
|
||||||
|
@use "tokens";
|
||||||
|
h1 {
|
||||||
|
@include tokens.sectionhead();
|
||||||
|
img {
|
||||||
|
@include tokens.sectionimg();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.breadcumbs {
|
||||||
|
@include tokens.badgelist();
|
||||||
|
&__item {
|
||||||
|
@include tokens.badge(secondary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
#[component]
|
||||||
|
fn component() -> impl IntoView {
|
||||||
|
view! {class=SCOPE,
|
||||||
|
<h1>
|
||||||
|
"Head"
|
||||||
|
<img src="whatever"/>
|
||||||
|
</h1>
|
||||||
|
<ul class=scope::breadcumbs>
|
||||||
|
<li class=scope::___item(scope::breadcumbs)>
|
||||||
|
"Home page"
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
That will perform *much* better:
|
||||||
|
|
||||||
|
- All scope members - like `scope::breadcumbs` - wont contain repeating scope hash, just the original class/id selector
|
||||||
|
- You will not encounter [the catch](#scoping) with nested tagname selectors
|
||||||
|
|
||||||
|
Also, this isn't really exclusive leptos-supporting feature. It just changes scoping behavour.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Sabry configuration lives in `[package.metadata.sabry]` table of the manifest file.
|
Sabry configuration lives in `[package.metadata.sabry]` table of the manifest file.
|
||||||
|
|
@ -531,6 +604,8 @@ Different selector types are scoped differently:
|
||||||
>
|
>
|
||||||
> Also if there are nested tagname selectors - sabry won't take this into account and you'll
|
> 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
|
> have to wrap them with `SCOPE` class as well
|
||||||
|
>
|
||||||
|
> **However** If you are able to apply some class to all html elements you have - like `view!{class=CLASS...}` with Leptos - you could use *lepty-scoping* feature flag for sabry and get rid of this catch! See more [here](#leptos-specials).
|
||||||
|
|
||||||
As for **SASS parent selectors**: they are currently handled in different way. Instead of
|
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:
|
walking up the syntax tree sabry just creates function member for the scope and leave the rest to grass:
|
||||||
|
|
|
||||||
50
examples/define-styles/Cargo.lock
generated
50
examples/define-styles/Cargo.lock
generated
|
|
@ -994,28 +994,15 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sabry"
|
name = "sabry"
|
||||||
version = "0.0.1"
|
version = "0.0.1-alpha.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sabry_build",
|
|
||||||
"sabry_intrnl",
|
"sabry_intrnl",
|
||||||
"sabry_procmacro",
|
"sabry_procmacro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sabry_build"
|
|
||||||
version = "0.0.0"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"sabry_intrnl",
|
|
||||||
"sabry_procmacro_impl",
|
|
||||||
"syn 2.0.85",
|
|
||||||
"thiserror",
|
|
||||||
"walkdir",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sabry_intrnl"
|
name = "sabry_intrnl"
|
||||||
version = "0.0.0"
|
version = "0.0.1-alpha.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"blake3",
|
"blake3",
|
||||||
|
|
@ -1023,6 +1010,7 @@ dependencies = [
|
||||||
"grass",
|
"grass",
|
||||||
"lightningcss",
|
"lightningcss",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
"raffia",
|
"raffia",
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
@ -1033,14 +1021,14 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sabry_procmacro"
|
name = "sabry_procmacro"
|
||||||
version = "0.0.0"
|
version = "0.0.1-alpha.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sabry_procmacro_impl",
|
"sabry_procmacro_impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sabry_procmacro_impl"
|
name = "sabry_procmacro_impl"
|
||||||
version = "0.0.0"
|
version = "0.0.1-alpha.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -1050,15 +1038,6 @@ dependencies = [
|
||||||
"syn 2.0.85",
|
"syn 2.0.85",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "same-file"
|
|
||||||
version = "1.0.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
|
||||||
dependencies = [
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
|
@ -1290,16 +1269,6 @@ version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff"
|
checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "walkdir"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
|
||||||
dependencies = [
|
|
||||||
"same-file",
|
|
||||||
"winapi-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
version = "0.11.0+wasi-snapshot-preview1"
|
||||||
|
|
@ -1361,15 +1330,6 @@ version = "0.2.95"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winapi-util"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.59.0"
|
version = "0.59.0"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use sabry::sassy;
|
use sabry::sassy;
|
||||||
|
|
||||||
|
sassy!(style "src/style.scss");
|
||||||
|
|
||||||
sassy!(utils {
|
sassy!(utils {
|
||||||
@mixin flex($direction, $align, $justify, $gap: .5rem) {
|
@mixin flex($direction, $align, $justify, $gap: .5rem) {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
||||||
5
examples/define-styles/src/style.scss
Normal file
5
examples/define-styles/src/style.scss
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
@use "theme" as *;
|
||||||
|
|
||||||
|
.codeblock {
|
||||||
|
background: $thm-surface-primary;
|
||||||
|
}
|
||||||
|
|
@ -23,11 +23,11 @@ tracing = { version = "0.1", optional = true }
|
||||||
http = "1"
|
http = "1"
|
||||||
|
|
||||||
# sabry with sass
|
# sabry with sass
|
||||||
sabry = {path = "../../"}
|
sabry = {path = "../../", features = ["lepty-scoping"]}
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
# sabry for build with sass
|
# sabry for build with sass
|
||||||
sabry = {path = "../../", features = ["build"]}
|
sabry = {path = "../../", features = ["build", "lepty-scoping"]}
|
||||||
# lets depend on our styles
|
# lets depend on our styles
|
||||||
define-styles = {path = "../define-styles"}
|
define-styles = {path = "../define-styles"}
|
||||||
|
|
||||||
|
|
@ -51,11 +51,12 @@ css.minify = true
|
||||||
css.bundle = "target/.sabry/target/bundle.css"
|
css.bundle = "target/.sabry/target/bundle.css"
|
||||||
|
|
||||||
[package.metadata.leptos]
|
[package.metadata.leptos]
|
||||||
|
# Sabry-specific quality of life config
|
||||||
|
style-file = "target/.sabry/target/bundle.css"
|
||||||
|
|
||||||
output-name = "leptos-axum"
|
output-name = "leptos-axum"
|
||||||
site-root = "target/site"
|
site-root = "target/site"
|
||||||
site-pkg-dir = "pkg"
|
site-pkg-dir = "pkg"
|
||||||
# Sabry-generated bundle for leptos
|
|
||||||
style-file = "target/.sabry/target/bundle.css"
|
|
||||||
assets-dir = "public"
|
assets-dir = "public"
|
||||||
site-addr = "127.0.0.1:3000"
|
site-addr = "127.0.0.1:3000"
|
||||||
reload-port = 3001
|
reload-port = 3001
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,32 @@
|
||||||
use leptos::prelude::*;
|
use leptos::prelude::*;
|
||||||
use sabry::styly;
|
use sabry::styly;
|
||||||
|
|
||||||
styly!(s "src/routes/home.scss");
|
styly!(style {
|
||||||
|
@use "tokens";
|
||||||
styly!(s2 {
|
@use "utils";
|
||||||
@use "theme";
|
@use "theme";
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
@include theme.surface(primary);
|
||||||
|
@include theme.txt(primary);
|
||||||
|
span {
|
||||||
|
@include theme.txt(accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
@include tokens.clickable(accent);
|
||||||
|
&-dark {
|
||||||
|
@include tokens.clickable(secondary, 0.8, 1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
@include utils.flex(column, center, center);
|
||||||
|
@include theme.surface(primary);
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
@include theme.surface(secondary);
|
@include theme.surface(secondary);
|
||||||
}
|
}
|
||||||
|
|
@ -12,6 +34,7 @@ styly!(s2 {
|
||||||
@include theme.surface(secondary);
|
@include theme.surface(secondary);
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Renders the home page of your application.
|
/// Renders the home page of your application.
|
||||||
|
|
@ -21,13 +44,20 @@ pub fn Route() -> impl IntoView {
|
||||||
let count = RwSignal::new(0);
|
let count = RwSignal::new(0);
|
||||||
let on_click = move |_| *count.write() += 1;
|
let on_click = move |_| *count.write() += 1;
|
||||||
|
|
||||||
view! {
|
view! {class = STYLE,
|
||||||
<section class=s::table>
|
<section class=style::table>
|
||||||
<h1>"Welcome to Leptos!"</h1>
|
<h2>"Welcome to Leptos"</h2>
|
||||||
<button class=s::btn on:click=on_click>"Ima CRAZY button, clicked: " {count} " times!"</button>
|
<h2 class="">
|
||||||
<span class=s2::card>"DISCLAIMER:"</span>
|
"This head is styled with lepty-scopes feature"
|
||||||
<p class=s2::pocwarn>"This isn't a design example! Its just proof of sabry's capabilities."</p>
|
<br/>
|
||||||
<p class=s2::pocwarn>"Plz dont make websites/apps which look like this page :D"</p>
|
<span class="">"And this child too!"</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<button class=style::btn on:click=on_click>"Ima CRAZY button, clicked: " {count} " times!"</button>
|
||||||
|
<button class=style::_dark(style::btn) on:click=on_click>"Ima CRAZY button, clicked: " {count} " times!"</button>
|
||||||
|
<span class=style::card>"DISCLAIMER:"</span>
|
||||||
|
<p class=style::pocwarn>"This isn't a design example! Its just proof of sabry's capabilities."</p>
|
||||||
|
<p class=style::pocwarn>"Plz dont make websites/apps which look like this page :D"</p>
|
||||||
</section>
|
</section>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
@use "tokens";
|
|
||||||
@use "utils";
|
|
||||||
@use "theme";
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
@include tokens.clickable(accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table {
|
|
||||||
@include utils.flex(column, center, center);
|
|
||||||
@include theme.surface(primary);
|
|
||||||
}
|
|
||||||
|
|
@ -23,5 +23,7 @@ const_format = {version = "^0.2"}
|
||||||
thiserror = {version = "^1.0"}
|
thiserror = {version = "^1.0"}
|
||||||
serde = {version = "^1.0", features = ["derive"]}
|
serde = {version = "^1.0", features = ["derive"]}
|
||||||
toml = {version = "^0.8"}
|
toml = {version = "^0.8"}
|
||||||
|
cfg-if = {version = "^1.0"}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
lepty-scoping = []
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
use cfg_if::cfg_if;
|
||||||
use hash::ScopeHash;
|
use hash::ScopeHash;
|
||||||
use raffia::Spanned;
|
use raffia::Spanned;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
@ -187,10 +188,22 @@ impl HashedSelector {
|
||||||
// As we dont want to use two HTML props for a single ID,
|
// As we dont want to use two HTML props for a single ID,
|
||||||
// ID scoping is done with id modification
|
// ID scoping is done with id modification
|
||||||
ScopedSelector::Id(a) => {
|
ScopedSelector::Id(a) => {
|
||||||
format!("{}-{}", hash.as_str(), a.ident)
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "lepty-scoping")] {
|
||||||
|
format!("{}.{}", a.ident, hash.as_str())
|
||||||
|
} else {
|
||||||
|
format!("{}-{}", hash.as_str(), a.ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ScopedSelector::Tag(a) => {
|
ScopedSelector::Tag(a) => {
|
||||||
format!(".{} {}", hash.as_str(), a.ident)
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "lepty-scoping")] {
|
||||||
|
format!("{}.{}", a.ident, hash.as_str())
|
||||||
|
} else {
|
||||||
|
format!(".{} {}", hash.as_str(), a.ident)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -205,10 +218,26 @@ impl HashedSelector {
|
||||||
pub fn make_hashed_html(value: &ScopedSelector, hash: &ScopeHash) -> Option<String> {
|
pub fn make_hashed_html(value: &ScopedSelector, hash: &ScopeHash) -> Option<String> {
|
||||||
match value {
|
match value {
|
||||||
// Class scoping is done with class composition
|
// Class scoping is done with class composition
|
||||||
ScopedSelector::Class(a) => Some(format!("{} {}", hash.as_str(), a.ident)),
|
ScopedSelector::Class(a) => {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "lepty-scoping")] {
|
||||||
|
Some(a.ident.to_string())
|
||||||
|
} else {
|
||||||
|
Some(format!("{} {}", hash.as_str(), a.ident))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
// As we dont want to use two HTML props for a single ID,
|
// As we dont want to use two HTML props for a single ID,
|
||||||
// ID scoping is done with id modification
|
// ID scoping is done with id modification
|
||||||
ScopedSelector::Id(a) => Some(format!("{}-{}", hash.as_str(), a.ident)),
|
ScopedSelector::Id(a) => {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "lepty-scoping")] {
|
||||||
|
Some(a.ident.to_string())
|
||||||
|
} else {
|
||||||
|
Some(format!("{}-{}", hash.as_str(), a.ident))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
ScopedSelector::Tag(_) => None,
|
ScopedSelector::Tag(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -330,6 +359,7 @@ pub fn apply_basic_rusty_member_gen_rules(source: &str) -> String {
|
||||||
mod test {
|
mod test {
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use cfg_if::cfg_if;
|
||||||
use syn::Ident;
|
use syn::Ident;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -345,14 +375,33 @@ mod test {
|
||||||
".cls1{color:red; &-dark{color: black;} #id1 {color:green;} div {color:blue;}} .cls3#id2{color: black;}";
|
".cls1{color:red; &-dark{color: black;} #id1 {color:green;} div {color:blue;}} .cls3#id2{color: black;}";
|
||||||
let hash = ScopeHash::test_init("F2kf8nMs".into());
|
let hash = ScopeHash::test_init("F2kf8nMs".into());
|
||||||
|
|
||||||
let expect_code = ".F2kf8nMs.cls1{color:red; &-dark{color: black;} #F2kf8nMs-id1 {color:green;} .F2kf8nMs div {color:blue;}} .F2kf8nMs.cls3#F2kf8nMs-id2{color: black;}";
|
cfg_if! {
|
||||||
let expect_selector_htmls = HashSet::from([
|
if #[cfg(feature = "lepty-scoping")]{
|
||||||
"F2kf8nMs cls1".to_string(),
|
let expect_code = ".F2kf8nMs.cls1{color:red; &-dark{color: black;} #id1.F2kf8nMs {color:green;} div.F2kf8nMs {color:blue;}} .F2kf8nMs.cls3#id2.F2kf8nMs{color: black;}";
|
||||||
"F2kf8nMs-id1".to_string(),
|
} else {
|
||||||
"F2kf8nMs cls3".to_string(),
|
let expect_code = ".F2kf8nMs.cls1{color:red; &-dark{color: black;} #F2kf8nMs-id1 {color:green;} .F2kf8nMs div {color:blue;}} .F2kf8nMs.cls3#F2kf8nMs-id2{color: black;}";
|
||||||
"F2kf8nMs-id2".to_string(),
|
}
|
||||||
"".to_string(), // comes from `div` which has no html hashed code, still want to check presense
|
}
|
||||||
]);
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "lepty-scoping")] {
|
||||||
|
let expect_selector_htmls = HashSet::from([
|
||||||
|
"cls1".to_string(),
|
||||||
|
"id1".to_string(),
|
||||||
|
"cls3".to_string(),
|
||||||
|
"id2".to_string(),
|
||||||
|
"".to_string(), // comes from `div` which has no html hashed code, still want to check presense
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
let expect_selector_htmls = HashSet::from([
|
||||||
|
"F2kf8nMs cls1".to_string(),
|
||||||
|
"F2kf8nMs-id1".to_string(),
|
||||||
|
"F2kf8nMs cls3".to_string(),
|
||||||
|
"F2kf8nMs-id2".to_string(),
|
||||||
|
"".to_string(), // comes from `div` which has no html hashed code, still want to check presense
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let scope = ArbitraryScope::from_source(
|
let scope = ArbitraryScope::from_source(
|
||||||
raffia::Syntax::Scss,
|
raffia::Syntax::Scss,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{fmt::Debug, fs};
|
use std::{fmt::Debug, fs, path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
|
|
@ -36,9 +36,28 @@ impl Parse for ArbitraryStyleBlock {
|
||||||
let (code, span) = if let Ok(path_tok) = input.parse::<LitStr>() {
|
let (code, span) = if let Ok(path_tok) = input.parse::<LitStr>() {
|
||||||
let path = path_tok.value();
|
let path = path_tok.value();
|
||||||
|
|
||||||
let iofile = match fs::read(&path) {
|
let path = match PathBuf::from_str(&path) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
path_tok.span(),
|
||||||
|
format!("Could not read {} as a path: Infallible", path),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let fullpath = match path.canonicalize() {
|
||||||
|
Ok(cp) => cp,
|
||||||
|
Err(e) => {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
path_tok.span(),
|
||||||
|
format!("Could not use path {path:?}: {:?}", e.kind()),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let iofile = match fs::read(&fullpath) {
|
||||||
Ok(bf) => bf,
|
Ok(bf) => bf,
|
||||||
Err(_) => return Err(syn::Error::new(path_tok.span(), format!("Could not read file '{path}'. Perhaps its relative? Thats not currently supported :(")))
|
Err(_) => return Err(syn::Error::new(path_tok.span(), format!("Could not read file at {fullpath:?}")))
|
||||||
};
|
};
|
||||||
let code = String::from_utf8_lossy(&iofile).to_string();
|
let code = String::from_utf8_lossy(&iofile).to_string();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue