go-htmx-gsd #1
13 changed files with 209 additions and 53 deletions
|
|
@ -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: "Nouveau projet",
|
||||
Variant: ui.ButtonVariantPrimary,
|
||||
Variant: ui.ButtonVariantDefault,
|
||||
Size: ui.SizeMD,
|
||||
Type: "button",
|
||||
})</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: "Relancer",
|
||||
Variant: ui.ButtonVariantWarning,
|
||||
Tone: ui.ButtonToneSoft,
|
||||
Size: ui.SizeMD,
|
||||
Type: "button",
|
||||
})</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: "Supprimer",
|
||||
Variant: ui.ButtonVariantDanger,
|
||||
Tone: ui.ButtonToneSoft,
|
||||
Size: ui.SizeLG,
|
||||
Type: "submit",
|
||||
})</code></pre></section></div></main>
|
||||
|
|
|
|||
|
|
@ -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: "Aucun projet trouvé",
|
||||
Description: "Créez votre premier projet",
|
||||
Icon: ui.UIIcon("grid3x3"),
|
||||
|
|
|
|||
|
|
@ -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: "Créer un projet",
|
||||
Body: ui.FormField(...),
|
||||
Actions: ui.Button(...),
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue