-
-
Notifications
You must be signed in to change notification settings - Fork 284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
css: Support for selectors of pseudo-classes, pseudo-elements. And nested css #262
Comments
No need for SCSS: regular CSS supports nesting, I think templ may simply put it in the result without any transformation... |
That is not 100% accurate if your target browser is an older one. |
Sure! However, I think including SCSS into templ for nesting would be overkill... |
After thinking again about this, I agree it does not fix the pseudo-class problem with non-nested CSS... |
I believe this one still requires some decisions to be made, so have labelled as such so noone jumps to an implementation. |
I'm thinking that we may be able to implement CSS variables directly in The tdewolff parser is suitably open to extension such that I was able to put together a rough PoC of how JS variables could be introduced directly into script tags, without needing to have script components. package main
import (
"fmt"
"io"
"log"
"strings"
"unicode"
"github.com/a-h/templ/parser/v2/goexpression"
"github.com/tdewolff/parse/v2"
"github.com/tdewolff/parse/v2/js"
)
func NewJSExpressionParser(content string) *JSExpressionParser {
input := parse.NewInputString(content)
return &JSExpressionParser{
Content: content,
Input: input,
Lexer: js.NewLexer(input),
BraceCount: 0,
GoExpressions: nil,
}
}
type JSExpressionParser struct {
Content string
Input *parse.Input
Lexer *js.Lexer
// BraceCount is the number of sequential braces we've just seen.
// If we see `{{` then we should start parsing Go code.
BraceCount int
GoExpressions []Range
}
type Range struct {
Index int
Content string
}
func (p *JSExpressionParser) Parse() (err error) {
for {
tt, _ := p.Lexer.Next()
switch tt {
case js.ErrorToken:
if p.Lexer.Err() != io.EOF {
return p.Lexer.Err()
}
return
case js.OpenBraceToken:
p.BraceCount++
if p.BraceCount == 2 {
expr := Range{
Index: p.Input.Offset(),
}
_, e, err := goexpression.Expression(p.Content[p.Input.Offset():])
if err != nil {
return fmt.Errorf("failed to parse Go: %w", err)
}
expr.Content = p.Content[expr.Index : expr.Index+e]
p.GoExpressions = append(p.GoExpressions, expr)
// Seek past the end of the Go expression we just parsed.
p.Input.Move(e + 1)
// Get rid of whitespace.
for {
r, l := p.Input.PeekRune(1)
if unicode.IsSpace(r) {
p.Input.Move(l)
continue
}
break
}
// Clear braces.
if err = take(p.Input, "}}"); err != nil {
return fmt.Errorf("unclosed Go expression: %v", err)
}
}
default:
p.BraceCount = 0
}
}
}
func take(input *parse.Input, expected string) error {
var actual strings.Builder
for i := 0; i < len(expected); i++ {
a, _ := input.PeekRune(i)
actual.WriteRune(a)
}
if expected != actual.String() {
return fmt.Errorf("expected %q, got %q", expected, actual.String())
}
input.Move(len(expected))
return nil
}
func main() {
content := `const x = {{ y }};`
p := NewJSExpressionParser(content)
err := p.Parse()
if err != nil {
log.Fatalf("failed to parse: %v", err)
}
fmt.Printf("%#+v", p.GoExpressions)
} I think the same logic could be applied to CSS components, allowing the use of this sort of thing: templ Page(bgColor string) {
<style type="text/css">
@media print {
body {
background-color: {{ bgColor }};
}
}
</style>
} Some work would be required to think about if/how class names get scoped to their components, but the parser part, at least, looks like it's not hard to achieve. |
On the topic of how class name would be scoped, Vue does this by looking for a special <style scoped>
.myClass { }
</style> https://vuejs.org/api/sfc-css-features.html#scoped-css Another use cases that might be worth considering is when a project have seperate css files. It would be nice to be able to use |
what's the solution for this now? |
I used a plain CSS file and added conditional logic to add specific class names. <head>
<link rel="stylesheet" href="/assets/style.css"/>
</head> |
First if all. Thank you for you work with templ. I love everything about it! (except for googling the name "templ") :) I think CSS nesting and pseudo selectors would be fantastic to have in templ. And even other CSS features like media queries. Here's my thoughts: |
This would be much more ergonomic than declaring style components!
I was searching the issue queue because I wanted to open a feature request for this! I always liked how Svelte automatically scopes elements / classes / ids to the markup of the current component. They also allow a
I was hoping for a way to export these scoped style declarations from each component and collect them into an external stylesheet instead of having Just thought I'd add my input as a data point, huge thanks to the maintainers for such a great project! |
Is there anything in the pipeline that's being worked on? Nested CSS would be a game changer. |
I've documented my current thinking in the issue above. ^ |
Would it be possible to have an "Unsafe" flag to pass to templ for the time being so all CSS is rendered within the block? (whilst this being worked on) |
I was experimenting with the library and found that there is no way to access the :hover pseudo-class nor any other pseudo-class or pseudo-element.
First I tried nested css, something like this:
Error message after trying generation of the code above:
I know that the css expression is like a class in a css file so I think that it could be the only one way to do it. Other way to do it could be with SCSS support or some other crazy thing
The text was updated successfully, but these errors were encountered: