AI prompts
base on CSS written in Pure Go [![Test](https://github.com/AccentDesign/gcss/actions/workflows/go-test.yml/badge.svg)](https://github.com/AccentDesign/gcss/actions/workflows/go-test.yml)
[![Go Report Card](https://goreportcard.com/badge/github.com/AccentDesign/gcss)](https://goreportcard.com/report/github.com/AccentDesign/gcss)
<a href="https://pkg.go.dev/github.com/AccentDesign/gcss"><img src="https://img.shields.io/badge/Documentation%20on-pkg.go.dev-blue.svg"/></a>
<img src="banner.jpg" alt="banner" style="width: 100%; height: auto;">
# gcss
CSS written in Pure Go.
## Motivation
This is really just a bit of fun and a way to write CSS in Go. I wanted to see if it was possible and what would it look like.
I wanted to find a way to easily control the CSS from the server side and not have to worry about pre-building the css to take variables and stuff.
I didnt want to use UI libraries that are written for JS frameworks and I didn't want to use preprocessors or linters that add more steps to the build process.
Could I just use CSS? Yes of course and I will, but I wanted to see if I could write CSS in Go as this is what is compiling the rest of the project.
## Gopher
No it looks nothing like the Go gopher, but it's a gopher and I like it. It's the best I could get from the LM without giving up, [ideogram.ai (1400097641)](https://ideogram.ai/g/E-5MQp7QTPO4uyF9PvERzw/3).
## Next steps
The next steps for this project are to add more features to the CSS package.
This includes adding support for more CSS properties when the need arises.
What I don't want to do is to add support for all CSS functionality as some things are better in CSS, but I do want to be able to create
a few UI components that are configurable using Go.
## Installation
```bash
go get github.com/AccentDesign/gcss
```
## Quickstart
There is a separate repo with the full example [here](https://github.com/AccentDesign/gcss-starter) which will evolve over time.
```bash
git clone https://github.com/AccentDesign/gcss-starter.git
```
install the dependencies:
```bash
# for hot reloading
go install github.com/cosmtrek/air@latest
```
```bash
go mod tidy
```
run the server:
```bash
air
```
## Usage
### Basic usage
`gcss` defines a `Style` type that can be used to hold the properties for a specific css selector, eg:
```go
style := gcss.Style{
Selector: "body",
Props: gcss.Props{
BackgroundColor: props.ColorRGBA(0, 0, 0, 128),
},
}
```
The `CSS` function on the `Style` is used to write the style to a `io.Writer`:
```go
style.CSS(os.Stdout)
```
which gives you:
```css
body{background-color:rgba(0,0,0,0.50);}
```
That's all there is to it. But it's not very useful on it's own I hear you say.
### Multiple styles
Well you can then use that to define a `Styles` type that can be used to hold multiple `Style` types:
```go
type Styles []gcss.Style
func (s Styles) CSS(w io.Writer) error {
// handle your errors
for _, style := range s {
style.CSS(w)
}
return nil
}
styles := Styles{
{
Selector: "body",
Props: gcss.Props{
BackgroundColor: props.ColorRGBA(0, 0, 0, 128),
},
},
{
Selector: "main",
Props: gcss.Props{
Padding: props.UnitRem(8.5),
},
},
}
styles.CSS(os.Stdout)
```
which gives you:
```css
/* formatted for visibility */
body{
background-color:rgba(0,0,0,0.50);
}
main{
padding:8.500rem;
}
```
### Need a bit more? what about a dark and light theme? keep the last example in mind and read on.
Define a `Theme` type that can be used to hold attributes for a specific theme, eg:
```go
type Theme struct {
MediaQuery string
Background props.Color
}
func (t *Theme) CSS(w io.Writer) error {
// handle your errors
fmt.Fprintf(w, "%s{", t.MediaQuery)
for _, style := range t.Styles() {
style.CSS(w)
}
fmt.Fprint(w, "}")
}
// Styles returns the styles for the theme.
// Can be any number of styles you want and any number of functions
// you just need them in the CSS function to loop over.
func (t *Theme) Styles() Styles {
return Styles{
{
Selector: "body",
Props: gcss.Props{
BackgroundColor: t.Background,
},
},
}
}
```
Then you can define a `Stylesheet` type that can be used to hold multiple `Theme` types:
```go
type Stylesheet struct {
Dark *Theme
Light *Theme
}
func (s *Stylesheet) CSS(w io.Writer) error {
// handle your errors
s.Dark.CSS(w)
s.Light.CSS(w)
return nil
}
```
Finally, you can use the `Stylesheet` type to write the css to a `io.Writer`:
```go
styles := Stylesheet{
Dark: &Theme{
MediaQuery: "@media (prefers-color-scheme: dark)",
Background: props.ColorRGBA(0, 0, 0, 255),
},
Light: &Theme{
MediaQuery: "@media (prefers-color-scheme: light)",
Background: props.ColorRGBA(255, 255, 255, 255),
},
}
styles.CSS(os.Stdout)
```
gives you:
```css
/* formatted for visibility */
@media (prefers-color-scheme: dark) {
body{
background-color:rgba(0,0,0,1.00);
}
}
@media (prefers-color-scheme: light) {
body{
background-color:rgba(255,255,255,1.00);
}
}
```
Hopefully this will get you going. The rest is up to you.
* Maybe create a button function that takes a `props.Color` and returns a Style.
* Or add extra `Styles` to the `Stylesheet` to additionally include non themed styles.
* It's all about how you construct the `Stylesheet` and use the `gcss.Style` type.
* If I could have created a `Stylesheet` type that fits well any use case at all I would have, but there is a world of possibility, so I left it up to you.
## The benefits
* Total control of the CSS from the server side.
* CSS doesn't have mixins, but you can create a function that returns a `Style` type and reuse it.
* Keeps the css free of variables.
* Keeps html free of classes like `bg-gray-50 text-black dark:bg-slate-800 dark:text-white` and eliminates the need to remember to add the dark variant.
* I recently saw a button component on an html page 10 times with over 1800 characters in the class attribute of each. This is not maintainable nor debuggable.
* Keeps the css clean and easy to debug with no overrides like the above.
## Examples
For example usage see the [examples](./examples) directory that include:
* [Full example](./examples/full) - A full example including base, media and themed styles with a `sync.Mutex` for caching the css in a `http.HandleFunc`.
* [CSS resets](./examples/css-resets) - A simple example collection of css resets.
* [Templ integration](./examples/integration-templ) - An example of how to load styles from gcss with the [templ](https://templ.guide) package.
* [Media queries](./examples/media-queries) - An example of how to use media queries.
* [Template function](./examples/template-function) - An example of how to write css to the template directly via `template.FuncMap` and `template.CSS`.
* [Write to a file](./examples/to-file) - An example of how to write to a file.
* [Write to an HTTP handler](./examples/to-http-handler) - An example of how to write to an http handler.
* [Write to stdout](./examples/to-stdout) - An example of how to write to stdout.
## Contributing
If you would like to contribute to this project, please open an issue or a pull request. We welcome all contributions and ideas.
## Mix it up with other CSS frameworks
You can mix `gcss` with other CSS frameworks like `tailwindcss` for example:
separate the css files into base and utils:
```css
/* base.css */
@tailwind base;
```
```css
/* utils.css */
@tailwind utilities;
```
Then add the `gcss` styles in between in your html:
```html
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="gcss-styles.css">
<link rel="stylesheet" href="utils.css">
```
Try to keep the specificity of the `gcss` styles to 1 by using single classes this will ensure any `tailwindcss` utilities
will be able to overwrite your styles where required.
", Assign "at most 3 tags" to the expected json: {"id":"10600","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"