Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
Signed-off-by: Guillaume Hivert <[email protected]>
  • Loading branch information
ghivert committed Apr 3, 2024
0 parents commit c04dec2
Show file tree
Hide file tree
Showing 11 changed files with 1,541 additions and 0 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: test

on:
push:
branches:
- master
- main
pull_request:

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: erlef/setup-beam@v1
with:
otp-version: "26.0.2"
gleam-version: "1.0.0"
rebar3-version: "3"
# elixir-version: "1.15.4"
- run: gleam deps download
- run: gleam test
- run: gleam format --check src test
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.beam
*.ez
/build
erl_crash.dump
7 changes: 7 additions & 0 deletions LICENCE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright 2024 Guillaume Hivert

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.
155 changes: 155 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Craft

Craft is a small module providing CSS-in-Gleam in its simpler form.
Craft does not try to add complicated API on top of CSS. If you have CSS
knowledge, you'll feel right at home, with all the niceties offered by
Craft, i.e. type-checking of sizes and push-to-browser stylesheets of your
classes, as well as SSR support.
Craft has currently two run modes: directly in your browser and leverages on
all abilities of the JS runtime, and on backend, to leverages on SSR.
Craft has currently to way to use it: directly in your vanilla Gleam
application or in your fully-featured [Lustre](https://hexdocs.pm/lustre/) application.
Craft allows you to build two types of CSS classes: dynamic ones, changing
over time, and static ones, compiled once and for all, and reused during the
entire lifetime of the application, just like classic CSS stylesheets.

## Compiling static classes

Craft exposes a single function [`class`](#class) allowing you to build your
class. The first time your function is called, the corresponding styles will
be compiled into CSS rules, and pushed in your browser or your SSR stylesheet.
Every time you'll call the function in the future, no computation will be done,
the class name will be returned, thanks to memoization.

```gleam
import craft
fn my_class() -> String {
craft.class([
craft.display("flex"),
craft.flex_direction("column"),
])
|> craft.to_class_name()
}
```

## Compiling dynamic classes

Craft exposes another function [`variable`](#variable) allowing you to build a
dynamic class, changing over time. Each time the function is called, the
properties in the declaration will be compiled into CSS, the previous class
will be wiped from the browser, and the new one will pushed.

```gleam
import craft
fn my_variable_class(is_column: Bool) -> String {
craft.variable([
craft.display("flex"),
case is_column {
True -> craft.flex_direction("column")
False -> craft.flex_direction("row")
}
])
|> craft.to_class_name()
}
```

## Usage with Lustre

[Lustre](https://hexdocs.pm/lustre/) is the main framework for frontend
development in Gleam. Because of this, craft provides a function to directly
use classes in Lustre views: [`to_lustre()`](#to_lustre). Just use it in place
of [`to_class_name()`](#to_class_name) to get a Lustre attribute and use it
in your views.

```gleam
import craft
import lustre/element/html
// With a pipeline.
fn my_view() {
[craft.background("red")]
|> craft.class()
|> craft.to_lustre()
|> list.repeat(1)
|> html.div(_, [])
}
// With a variable class.
fn my_other_view(model: Bool) {
let color = case model {
True -> "red"
False -> "blue"
}
html.div(
[craft.to_lustre(craft.variable([craft.background(color)]))],
[],
)
}
```

## Using media queries and pseudo-selectors

Because we're in CSS-in-Gleam, we can leverage on the full CSS power,
contrarily to inline styling. This mean we can use media queries and pseudo-selectors!
You only need to call the proper functions, and craft will take care of the rest.

```gleam
import craft
import craft/media
import craft/size.{px}
fn my_class() {
craft.class([
craft.display("flex"),
craft.flex_direction("row"),
craft.background("red"),
craft.hover([
craft.background("blue"),
]),
craft.media(media.max_width(px(320)), [
craft.flex_direction("column"),
craft.hover([
craft.background("green"),
]),
]),
])
|> craft.to_lustre()
}
```

The example above will be compiled to the following CSS.

```gleam
.css-001 {
display: flex;
flex-direction: row;
background: red;
}
.css-001:hover {
background: blue;
}
@media (max-width: 320px) {
.css-001 {
flex-direction: column;
}
.css-001:hover {
background: green;
}
}
```

## Some opinions on properties

A lot of properties are accessible directly through the `craft` package.
But with time, some could be added, and new features for existing features
can appear. That's why craft will never try to be on your way: at any time
you can access [`property()`](#property), which allows you to push any
arbitrary property in a class. Another thing is that craft will always let
you access raw, low-level properties. If you're trying to use something like
`craft.width("auto")` and the property does not support String, look for a
variant with an underscore (`_`), it should fullfill your needs, like
`craft.width_("auto")`!
In case something is missing or a property does not have its underscore
alternative, [open an issue — or better, a PR — on the repo!](https://github.com/ghivert/craft)
15 changes: 15 additions & 0 deletions gleam.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name = "craft"
target = "javascript"
version = "1.0.0"

description = "A CSS-in-Gleam package, made to work with frontend, backend, and directly with lustre!"
licences = ["MIT"]
links = [{title = "Sponsor", href = "https://github.com/sponsors/ghivert"}]
repository = {type = "github", user = "ghivert", repo = "craft"}

[dependencies]
gleam_stdlib = "~> 0.34 or ~> 1.0"
lustre = "~> 4.1"

[dev-dependencies]
gleeunit = "~> 1.0"
17 changes: 17 additions & 0 deletions manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# This file was generated by Gleam
# You typically do not need to edit this file

packages = [
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" },
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" },
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" },
{ name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" },
{ name = "lustre", version = "4.1.4", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "BA9ED993187B0BB721FFBB1F01F6CCA14548F68873C55567B77918D33D0D9ECB" },
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
]

[requirements]
gleam_stdlib = { version = "~> 0.34 or ~> 1.0" }
gleeunit = { version = "~> 1.0" }
lustre = { version = "~> 4.1"}
Loading

0 comments on commit c04dec2

Please sign in to comment.