feat: refresh go-backend button variants and tablos styling

This commit is contained in:
Arthur Belleville 2026-05-10 09:22:22 +02:00
parent a089f35a9b
commit cf64404d25
No known key found for this signature in database
13 changed files with 209 additions and 53 deletions

View file

@ -8,14 +8,21 @@
<link rel="stylesheet" href="../../go-backend/static/styles.css">
</head>
<body>
<main class="catalog-page"><nav class="catalog-nav" aria-label="Catalog navigation"><a href="./index.html" class="catalog-home-link">Catalog</a><div class="catalog-nav-links"><a href="./tokens.html" class="catalog-nav-link">Tokens</a><a href="./buttons.html" class="catalog-nav-link is-active">Buttons</a><a href="./badges.html" class="catalog-nav-link">Badges</a><a href="./icon-buttons.html" class="catalog-nav-link">Icon Buttons</a><a href="./inputs.html" class="catalog-nav-link">Inputs</a><a href="./form-fields.html" class="catalog-nav-link">Form Fields</a><a href="./modals.html" class="catalog-nav-link">Modals</a><a href="./tables.html" class="catalog-nav-link">Tables</a><a href="./empty-states.html" class="catalog-nav-link">Empty States</a><a href="./cards.html" class="catalog-nav-link">Cards</a></div></nav><header class="catalog-page-header"><p class="catalog-eyebrow">Design System</p><h1>Buttons</h1><p>Primary, secondary, ghost, and destructive actions built from shared templ primitives.</p></header><div class="catalog-example-list"><section class="catalog-example"><div class="catalog-example-copy"><h2>Primary action</h2><p>Used for the main action in a page section or modal footer.</p></div><div class="catalog-example-preview"><button type="button" class="ui-button ui-button-primary ui-button-md">Nouveau projet</button></div><pre class="catalog-example-snippet"><code>@ui.Button(ui.ButtonProps{
<main class="catalog-page"><nav class="catalog-nav" aria-label="Catalog navigation"><a href="./index.html" class="catalog-home-link">Catalog</a><div class="catalog-nav-links"><a href="./tokens.html" class="catalog-nav-link">Tokens</a><a href="./buttons.html" class="catalog-nav-link is-active">Buttons</a><a href="./badges.html" class="catalog-nav-link">Badges</a><a href="./icon-buttons.html" class="catalog-nav-link">Icon Buttons</a><a href="./inputs.html" class="catalog-nav-link">Inputs</a><a href="./form-fields.html" class="catalog-nav-link">Form Fields</a><a href="./modals.html" class="catalog-nav-link">Modals</a><a href="./tables.html" class="catalog-nav-link">Tables</a><a href="./empty-states.html" class="catalog-nav-link">Empty States</a><a href="./cards.html" class="catalog-nav-link">Cards</a></div></nav><header class="catalog-page-header"><p class="catalog-eyebrow">Design System</p><h1>Buttons</h1><p>Primary, secondary, ghost, and destructive actions built from shared templ primitives.</p></header><div class="catalog-example-list"><section class="catalog-example"><div class="catalog-example-copy"><h2>Default solid action</h2><p>Used for the main action in a page section or modal footer.</p></div><div class="catalog-example-preview"><button type="button" class="ui-button ui-button-solid ui-button-default ui-button-md">Nouveau projet</button></div><pre class="catalog-example-snippet"><code>@ui.Button(ui.ButtonProps{
Label: &#34;Nouveau projet&#34;,
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: &#34;button&#34;,
})</code></pre></section><section class="catalog-example"><div class="catalog-example-copy"><h2>Danger action</h2><p>Used for irreversible actions after explicit confirmation.</p></div><div class="catalog-example-preview"><button type="submit" class="ui-button ui-button-danger ui-button-lg">Supprimer</button></div><pre class="catalog-example-snippet"><code>@ui.Button(ui.ButtonProps{
})</code></pre></section><section class="catalog-example"><div class="catalog-example-copy"><h2>Soft warning action</h2><p>Used for inline actions that need emphasis without the weight of a solid button.</p></div><div class="catalog-example-preview"><button type="button" class="ui-button ui-button-soft ui-button-warning ui-button-md">Relancer</button></div><pre class="catalog-example-snippet"><code>@ui.Button(ui.ButtonProps{
Label: &#34;Relancer&#34;,
Variant: ui.ButtonVariantWarning,
Tone: ui.ButtonToneSoft,
Size: ui.SizeMD,
Type: &#34;button&#34;,
})</code></pre></section><section class="catalog-example"><div class="catalog-example-copy"><h2>Soft danger action</h2><p>Used for irreversible actions after explicit confirmation.</p></div><div class="catalog-example-preview"><button type="submit" class="ui-button ui-button-soft ui-button-danger ui-button-lg">Supprimer</button></div><pre class="catalog-example-snippet"><code>@ui.Button(ui.ButtonProps{
Label: &#34;Supprimer&#34;,
Variant: ui.ButtonVariantDanger,
Tone: ui.ButtonToneSoft,
Size: ui.SizeLG,
Type: &#34;submit&#34;,
})</code></pre></section></div></main>

View file

@ -8,7 +8,7 @@
<link rel="stylesheet" href="../../go-backend/static/styles.css">
</head>
<body>
<main class="catalog-page"><nav class="catalog-nav" aria-label="Catalog navigation"><a href="./index.html" class="catalog-home-link">Catalog</a><div class="catalog-nav-links"><a href="./tokens.html" class="catalog-nav-link">Tokens</a><a href="./buttons.html" class="catalog-nav-link">Buttons</a><a href="./badges.html" class="catalog-nav-link">Badges</a><a href="./icon-buttons.html" class="catalog-nav-link">Icon Buttons</a><a href="./inputs.html" class="catalog-nav-link">Inputs</a><a href="./form-fields.html" class="catalog-nav-link">Form Fields</a><a href="./modals.html" class="catalog-nav-link">Modals</a><a href="./tables.html" class="catalog-nav-link">Tables</a><a href="./empty-states.html" class="catalog-nav-link is-active">Empty States</a><a href="./cards.html" class="catalog-nav-link">Cards</a></div></nav><header class="catalog-page-header"><p class="catalog-eyebrow">Design System</p><h1>Empty States</h1><p>Centered fallback messaging with optional icon and action.</p></header><div class="catalog-example-list"><section class="catalog-example"><div class="catalog-example-copy"><h2>Centered empty state</h2><p>Used when a list has no rows yet and the next action should stay obvious.</p></div><div class="catalog-example-preview"><section class="ui-empty-state"><div class="ui-empty-state-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2"></rect> <path d="M3 9h18"></path> <path d="M3 15h18"></path> <path d="M9 3v18"></path> <path d="M15 3v18"></path></svg></div><h3 class="ui-empty-state-title">Aucun projet trouvé</h3><p class="ui-empty-state-description">Créez votre premier projet</p><div class="ui-empty-state-action"><button type="button" class="ui-button ui-button-primary ui-button-md"><span class="ui-button-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"></path> <path d="M12 5v14"></path></svg></span> Nouveau projet</button></div></section></div><pre class="catalog-example-snippet"><code>@ui.EmptyState(ui.EmptyStateProps{
<main class="catalog-page"><nav class="catalog-nav" aria-label="Catalog navigation"><a href="./index.html" class="catalog-home-link">Catalog</a><div class="catalog-nav-links"><a href="./tokens.html" class="catalog-nav-link">Tokens</a><a href="./buttons.html" class="catalog-nav-link">Buttons</a><a href="./badges.html" class="catalog-nav-link">Badges</a><a href="./icon-buttons.html" class="catalog-nav-link">Icon Buttons</a><a href="./inputs.html" class="catalog-nav-link">Inputs</a><a href="./form-fields.html" class="catalog-nav-link">Form Fields</a><a href="./modals.html" class="catalog-nav-link">Modals</a><a href="./tables.html" class="catalog-nav-link">Tables</a><a href="./empty-states.html" class="catalog-nav-link is-active">Empty States</a><a href="./cards.html" class="catalog-nav-link">Cards</a></div></nav><header class="catalog-page-header"><p class="catalog-eyebrow">Design System</p><h1>Empty States</h1><p>Centered fallback messaging with optional icon and action.</p></header><div class="catalog-example-list"><section class="catalog-example"><div class="catalog-example-copy"><h2>Centered empty state</h2><p>Used when a list has no rows yet and the next action should stay obvious.</p></div><div class="catalog-example-preview"><section class="ui-empty-state"><div class="ui-empty-state-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2"></rect> <path d="M3 9h18"></path> <path d="M3 15h18"></path> <path d="M9 3v18"></path> <path d="M15 3v18"></path></svg></div><h3 class="ui-empty-state-title">Aucun projet trouvé</h3><p class="ui-empty-state-description">Créez votre premier projet</p><div class="ui-empty-state-action"><button type="button" class="ui-button ui-button-solid ui-button-default ui-button-md"><span class="ui-button-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"></path> <path d="M12 5v14"></path></svg></span> Nouveau projet</button></div></section></div><pre class="catalog-example-snippet"><code>@ui.EmptyState(ui.EmptyStateProps{
Title: &#34;Aucun projet trouvé&#34;,
Description: &#34;Créez votre premier projet&#34;,
Icon: ui.UIIcon(&#34;grid3x3&#34;),

View file

@ -8,7 +8,7 @@
<link rel="stylesheet" href="../../go-backend/static/styles.css">
</head>
<body>
<main class="catalog-page"><nav class="catalog-nav" aria-label="Catalog navigation"><a href="./index.html" class="catalog-home-link">Catalog</a><div class="catalog-nav-links"><a href="./tokens.html" class="catalog-nav-link">Tokens</a><a href="./buttons.html" class="catalog-nav-link">Buttons</a><a href="./badges.html" class="catalog-nav-link">Badges</a><a href="./icon-buttons.html" class="catalog-nav-link">Icon Buttons</a><a href="./inputs.html" class="catalog-nav-link">Inputs</a><a href="./form-fields.html" class="catalog-nav-link">Form Fields</a><a href="./modals.html" class="catalog-nav-link is-active">Modals</a><a href="./tables.html" class="catalog-nav-link">Tables</a><a href="./empty-states.html" class="catalog-nav-link">Empty States</a><a href="./cards.html" class="catalog-nav-link">Cards</a></div></nav><header class="catalog-page-header"><p class="catalog-eyebrow">Design System</p><h1>Modals</h1><p>Shared modal shell for focused create, edit, and confirm flows.</p></header><div class="catalog-example-list"><section class="catalog-example"><div class="catalog-example-copy"><h2>Create modal</h2><p>Shared modal shell with a form body and action footer.</p></div><div class="catalog-example-preview"><div class="ui-modal-backdrop"><div class="ui-modal-panel"><div class="ui-modal-header"><h2>Créer un projet</h2></div><div class="ui-modal-body"><div class="ui-form-field"><label for="modal-name" class="ui-form-label">Nom du projet</label> <input id="modal-name" type="text" name="name" value="" placeholder="Nom du projet" class="ui-input"></div></div><div class="ui-modal-actions"><button type="button" class="ui-button ui-button-secondary ui-button-md">Annuler</button><button type="submit" class="ui-button ui-button-primary ui-button-md">Créer le projet</button></div></div></div></div><pre class="catalog-example-snippet"><code>@ui.Modal(ui.ModalProps{
<main class="catalog-page"><nav class="catalog-nav" aria-label="Catalog navigation"><a href="./index.html" class="catalog-home-link">Catalog</a><div class="catalog-nav-links"><a href="./tokens.html" class="catalog-nav-link">Tokens</a><a href="./buttons.html" class="catalog-nav-link">Buttons</a><a href="./badges.html" class="catalog-nav-link">Badges</a><a href="./icon-buttons.html" class="catalog-nav-link">Icon Buttons</a><a href="./inputs.html" class="catalog-nav-link">Inputs</a><a href="./form-fields.html" class="catalog-nav-link">Form Fields</a><a href="./modals.html" class="catalog-nav-link is-active">Modals</a><a href="./tables.html" class="catalog-nav-link">Tables</a><a href="./empty-states.html" class="catalog-nav-link">Empty States</a><a href="./cards.html" class="catalog-nav-link">Cards</a></div></nav><header class="catalog-page-header"><p class="catalog-eyebrow">Design System</p><h1>Modals</h1><p>Shared modal shell for focused create, edit, and confirm flows.</p></header><div class="catalog-example-list"><section class="catalog-example"><div class="catalog-example-copy"><h2>Create modal</h2><p>Shared modal shell with a form body and action footer.</p></div><div class="catalog-example-preview"><div class="ui-modal-backdrop"><div class="ui-modal-panel"><div class="ui-modal-header"><h2>Créer un projet</h2></div><div class="ui-modal-body"><div class="ui-form-field"><label for="modal-name" class="ui-form-label">Nom du projet</label> <input id="modal-name" type="text" name="name" value="" placeholder="Nom du projet" class="ui-input"></div></div><div class="ui-modal-actions"><button type="button" class="ui-button ui-button-solid ui-button-neutral ui-button-md">Annuler</button><button type="submit" class="ui-button ui-button-solid ui-button-default ui-button-md">Créer le projet</button></div></div></div></div><pre class="catalog-example-snippet"><code>@ui.Modal(ui.ModalProps{
Title: &#34;Créer un projet&#34;,
Body: ui.FormField(...),
Actions: ui.Button(...),

View file

@ -237,7 +237,7 @@ func TestGetTablosPageUsesSharedToolbarButtonAndStatusBadge(t *testing.T) {
body := rec.Body.String()
for _, want := range []string{
`ui-button ui-button-primary ui-button-md`,
`ui-button ui-button-solid ui-button-default ui-button-md`,
`ui-badge ui-badge-warning`,
} {
if !strings.Contains(body, want) {

View file

@ -3,6 +3,7 @@ package ui
type ButtonProps struct {
Label string
Variant ButtonVariant
Tone ButtonTone
Size Size
Type string
Icon string
@ -10,7 +11,7 @@ type ButtonProps struct {
}
templ Button(props ButtonProps) {
<button type={ buttonType(props.Type) } class={ buttonClass(props.Variant, props.Size) } { props.Attrs... }>
<button type={ buttonType(props.Type) } class={ buttonClass(props.Variant, props.Tone, props.Size) } { props.Attrs... }>
if props.Icon != "" {
<span class="ui-button-icon">
@UIIcon(props.Icon)

View file

@ -11,6 +11,7 @@ import templruntime "github.com/a-h/templ/runtime"
type ButtonProps struct {
Label string
Variant ButtonVariant
Tone ButtonTone
Size Size
Type string
Icon string
@ -38,7 +39,7 @@ func Button(props ButtonProps) templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
var templ_7745c5c3_Var2 = []any{buttonClass(props.Variant, props.Size)}
var templ_7745c5c3_Var2 = []any{buttonClass(props.Variant, props.Tone, props.Size)}
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var2...)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
@ -50,7 +51,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(buttonType(props.Type))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/ui/button.templ`, Line: 13, Col: 38}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/ui/button.templ`, Line: 14, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
@ -98,7 +99,7 @@ func Button(props ButtonProps) templ.Component {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(props.Label)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/ui/button.templ`, Line: 19, Col: 15}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `internal/web/ui/button.templ`, Line: 20, Col: 15}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {

View file

@ -70,7 +70,8 @@ func TestButtonPageExamplesRenderRealPrimitives(t *testing.T) {
html := renderToString(t, page.Examples[0].Preview)
for _, want := range []string{
`ui-button`,
`ui-button-primary`,
`ui-button-solid`,
`ui-button-default`,
`Nouveau projet`,
} {
if !strings.Contains(html, want) {

View file

@ -14,33 +14,53 @@ type anyComponent = templ.Component
func buttonExamples() []Example {
return []Example{
{
Title: "Primary action",
Title: "Default solid action",
Description: "Used for the main action in a page section or modal footer.",
Preview: ui.Button(ui.ButtonProps{
Label: "Nouveau projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "button",
}),
Snippet: `@ui.Button(ui.ButtonProps{
Label: "Nouveau projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "button",
})`,
},
{
Title: "Danger action",
Title: "Soft warning action",
Description: "Used for inline actions that need emphasis without the weight of a solid button.",
Preview: ui.Button(ui.ButtonProps{
Label: "Relancer",
Variant: ui.ButtonVariantWarning,
Tone: ui.ButtonToneSoft,
Size: ui.SizeMD,
Type: "button",
}),
Snippet: `@ui.Button(ui.ButtonProps{
Label: "Relancer",
Variant: ui.ButtonVariantWarning,
Tone: ui.ButtonToneSoft,
Size: ui.SizeMD,
Type: "button",
})`,
},
{
Title: "Soft danger action",
Description: "Used for irreversible actions after explicit confirmation.",
Preview: ui.Button(ui.ButtonProps{
Label: "Supprimer",
Variant: ui.ButtonVariantDanger,
Tone: ui.ButtonToneSoft,
Size: ui.SizeLG,
Type: "submit",
}),
Snippet: `@ui.Button(ui.ButtonProps{
Label: "Supprimer",
Variant: ui.ButtonVariantDanger,
Tone: ui.ButtonToneSoft,
Size: ui.SizeLG,
Type: "submit",
})`,
@ -205,13 +225,13 @@ func modalExamples() []Example {
return renderComponents(ctx, w,
ui.Button(ui.ButtonProps{
Label: "Annuler",
Variant: ui.ButtonVariantSecondary,
Variant: ui.ButtonVariantNeutral,
Size: ui.SizeMD,
Type: "button",
}),
ui.Button(ui.ButtonProps{
Label: "Créer le projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "submit",
}),
@ -255,7 +275,7 @@ func emptyStateExamples() []Example {
Icon: ui.UIIcon("grid3x3"),
Action: ui.Button(ui.ButtonProps{
Label: "Nouveau projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "button",
Icon: "plus",

View file

@ -12,10 +12,10 @@ import (
"github.com/a-h/templ"
)
func TestButtonRendersPrimaryMediumMarkup(t *testing.T) {
func TestButtonRendersDefaultSolidMediumMarkup(t *testing.T) {
component := Button(ButtonProps{
Label: "Nouveau projet",
Variant: ButtonVariantPrimary,
Variant: ButtonVariantDefault,
Size: SizeMD,
Type: "button",
})
@ -26,7 +26,8 @@ func TestButtonRendersPrimaryMediumMarkup(t *testing.T) {
`type="button"`,
`Nouveau projet`,
`ui-button`,
`ui-button-primary`,
`ui-button-solid`,
`ui-button-default`,
`ui-button-md`,
} {
if !strings.Contains(html, want) {
@ -101,7 +102,7 @@ func TestModalRendersShellStructure(t *testing.T) {
func TestButtonUsesSharedTokenBackedClasses(t *testing.T) {
component := Button(ButtonProps{
Label: "Create",
Variant: ButtonVariantPrimary,
Variant: ButtonVariantDefault,
Size: SizeSM,
Type: "button",
})
@ -110,7 +111,8 @@ func TestButtonUsesSharedTokenBackedClasses(t *testing.T) {
for _, want := range []string{
`ui-button`,
`ui-button-primary`,
`ui-button-solid`,
`ui-button-default`,
`ui-button-sm`,
} {
if !strings.Contains(html, want) {
@ -128,11 +130,12 @@ func TestSharedSemanticClassesExistInStylesheet(t *testing.T) {
css := string(body)
for _, want := range []string{
`.ui-button-primary`,
`.ui-button-solid.ui-button-default`,
`.ui-button-sm`,
`.ui-badge-warning`,
`.ui-modal-panel`,
`.borderless-icon-button`,
`.ui-button-soft.ui-button-danger`,
} {
if !strings.Contains(css, want) {
t.Fatalf("expected stylesheet to contain %q", want)
@ -144,6 +147,7 @@ func TestButtonRendersDangerLargeMarkup(t *testing.T) {
component := Button(ButtonProps{
Label: "Supprimer",
Variant: ButtonVariantDanger,
Tone: ButtonToneSoft,
Size: SizeLG,
Type: "submit",
})
@ -152,6 +156,7 @@ func TestButtonRendersDangerLargeMarkup(t *testing.T) {
for _, want := range []string{
`type="submit"`,
`ui-button-soft`,
`ui-button-danger`,
`ui-button-lg`,
`Supprimer`,
@ -162,6 +167,30 @@ func TestButtonRendersDangerLargeMarkup(t *testing.T) {
}
}
func TestButtonRendersSoftWarningMarkup(t *testing.T) {
component := Button(ButtonProps{
Label: "Relancer",
Variant: ButtonVariantWarning,
Tone: ButtonToneSoft,
Size: SizeMD,
Type: "button",
})
html := renderToString(t, component)
for _, want := range []string{
`type="button"`,
`ui-button-soft`,
`ui-button-warning`,
`ui-button-md`,
`Relancer`,
} {
if !strings.Contains(html, want) {
t.Fatalf("expected %q in %q", want, html)
}
}
}
func TestInputRendersSharedControlMarkup(t *testing.T) {
component := Input(InputProps{
Name: "name",

View file

@ -11,10 +11,18 @@ const (
type ButtonVariant string
const (
ButtonVariantPrimary ButtonVariant = "primary"
ButtonVariantSecondary ButtonVariant = "secondary"
ButtonVariantGhost ButtonVariant = "ghost"
ButtonVariantDanger ButtonVariant = "danger"
ButtonVariantDefault ButtonVariant = "default"
ButtonVariantNeutral ButtonVariant = "neutral"
ButtonVariantWarning ButtonVariant = "warning"
ButtonVariantSuccess ButtonVariant = "success"
ButtonVariantDanger ButtonVariant = "danger"
)
type ButtonTone string
const (
ButtonToneSolid ButtonTone = "solid"
ButtonToneSoft ButtonTone = "soft"
)
type IconButtonVariant string
@ -33,8 +41,8 @@ const (
BadgeVariantDanger BadgeVariant = "danger"
)
func buttonClass(variant ButtonVariant, size Size) string {
return "ui-button ui-button-" + string(normalizedButtonVariant(variant)) + " ui-button-" + string(normalizedSize(size))
func buttonClass(variant ButtonVariant, tone ButtonTone, size Size) string {
return "ui-button ui-button-" + string(normalizedButtonTone(tone)) + " ui-button-" + string(normalizedButtonVariant(variant)) + " ui-button-" + string(normalizedSize(size))
}
func iconButtonClass(variant IconButtonVariant) string {
@ -61,10 +69,19 @@ func normalizedSize(size Size) Size {
func normalizedButtonVariant(variant ButtonVariant) ButtonVariant {
switch variant {
case ButtonVariantSecondary, ButtonVariantGhost, ButtonVariantDanger:
case ButtonVariantNeutral, ButtonVariantWarning, ButtonVariantSuccess, ButtonVariantDanger:
return variant
default:
return ButtonVariantPrimary
return ButtonVariantDefault
}
}
func normalizedButtonTone(tone ButtonTone) ButtonTone {
switch tone {
case ButtonToneSoft:
return tone
default:
return ButtonToneSolid
}
}

View file

@ -8,7 +8,7 @@ templ TablosPageContent(vm TablosPageViewModel) {
<h1 class="text-2xl font-bold text-gray-900 dark:text-gray-100">Mes Projets</h1>
@ui.Button(ui.ButtonProps{
Label: "Nouveau projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "button",
Icon: "plus",
@ -99,7 +99,7 @@ templ TablosPageContent(vm TablosPageViewModel) {
Icon: ui.UIIcon("grid3x3"),
Action: ui.Button(ui.ButtonProps{
Label: "Nouveau projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "button",
Icon: "plus",
@ -278,13 +278,13 @@ templ CreateTabloModalBody(vm TablosPageViewModel) {
hx-target="#app-main-content"
hx-swap="outerHTML"
hx-push-url="true"
class="ui-button ui-button-secondary ui-button-md"
class="ui-button ui-button-solid ui-button-neutral ui-button-md"
>
Annuler
</a>
@ui.Button(ui.ButtonProps{
Label: "Créer le projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "submit",
})

View file

@ -37,7 +37,7 @@ func TablosPageContent(vm TablosPageViewModel) templ.Component {
}
templ_7745c5c3_Err = ui.Button(ui.ButtonProps{
Label: "Nouveau projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "button",
Icon: "plus",
@ -287,7 +287,7 @@ func TablosPageContent(vm TablosPageViewModel) templ.Component {
Icon: ui.UIIcon("grid3x3"),
Action: ui.Button(ui.ButtonProps{
Label: "Nouveau projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "button",
Icon: "plus",
@ -1005,13 +1005,13 @@ func CreateTabloModalBody(vm TablosPageViewModel) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "\" hx-target=\"#app-main-content\" hx-swap=\"outerHTML\" hx-push-url=\"true\" class=\"ui-button ui-button-secondary ui-button-md\">Annuler</a>")
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "\" hx-target=\"#app-main-content\" hx-swap=\"outerHTML\" hx-push-url=\"true\" class=\"ui-button ui-button-solid ui-button-neutral ui-button-md\">Annuler</a>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Err = ui.Button(ui.ButtonProps{
Label: "Créer le projet",
Variant: ui.ButtonVariantPrimary,
Variant: ui.ButtonVariantDefault,
Size: ui.SizeMD,
Type: "submit",
}).Render(ctx, templ_7745c5c3_Buffer)

View file

@ -1062,46 +1062,126 @@ input {
.ui-button-lg {
font-size: 1rem;
padding: 0.9rem 1.25rem;
padding: 0.82rem 1.15rem;
}
.ui-button-primary {
.ui-button-solid.ui-button-default {
background: var(--secondary);
color: #fff;
}
.ui-button-primary:hover {
.ui-button-solid.ui-button-default:hover {
background: #6d28d9;
}
.ui-button-secondary {
.ui-button-solid.ui-button-default:active {
background: #5b21b6;
}
.ui-button-solid.ui-button-neutral {
background: #f3f4f6;
color: #111827;
}
.ui-button-secondary:hover {
.ui-button-solid.ui-button-neutral:hover {
background: #e5e7eb;
}
.ui-button-ghost {
background: transparent;
color: #4b5563;
.ui-button-solid.ui-button-neutral:active {
background: #d1d5db;
}
.ui-button-ghost:hover {
background: #f9fafb;
color: #111827;
.ui-button-solid.ui-button-warning {
background: #db9729;
color: #fff;
}
.ui-button-danger {
.ui-button-solid.ui-button-warning:hover {
background: #c37f12;
}
.ui-button-solid.ui-button-warning:active {
background: #a9670c;
}
.ui-button-solid.ui-button-success {
background: #16a34a;
color: #fff;
}
.ui-button-solid.ui-button-success:hover {
background: #15803d;
}
.ui-button-solid.ui-button-success:active {
background: #166534;
}
.ui-button-solid.ui-button-danger {
background: #dc2626;
color: #fff;
}
.ui-button-danger:hover {
.ui-button-solid.ui-button-danger:hover {
background: #b91c1c;
}
.ui-button-solid.ui-button-danger:active {
background: #991b1b;
}
.ui-button-soft.ui-button-default {
background: #ede9fe;
color: #6d28d9;
}
.ui-button-soft.ui-button-default:hover {
background: #ddd6fe;
}
.ui-button-soft.ui-button-default:active {
background: #c4b5fd;
}
.ui-button-soft.ui-button-warning {
background: #fff4e2;
color: #b86e00;
}
.ui-button-soft.ui-button-warning:hover {
background: #fee6b7;
}
.ui-button-soft.ui-button-warning:active {
background: #fdd58e;
}
.ui-button-soft.ui-button-success {
background: #ecfdf3;
color: #15803d;
}
.ui-button-soft.ui-button-success:hover {
background: #d1fadf;
}
.ui-button-soft.ui-button-success:active {
background: #a6f4c5;
}
.ui-button-soft.ui-button-danger {
background: #fef3f2;
color: #b42318;
}
.ui-button-soft.ui-button-danger:hover {
background: #fee4e2;
}
.ui-button-soft.ui-button-danger:active {
background: #fecdca;
}
.ui-badge {
border: 1px solid transparent;
border-radius: 999px;