Swap Bulma for DaisyUI (Tailwind) (#111)
This commit is contained in:
parent
fc5db0e95a
commit
c1e9baabe6
53 changed files with 1124 additions and 632 deletions
|
|
@ -15,12 +15,12 @@ func About(ctx echo.Context) error {
|
|||
r.Title = "About"
|
||||
r.Metatags.Description = "Learn a little about what's included in Pagoda."
|
||||
|
||||
// The tabs are static so we can render and cache them.
|
||||
// The tabs are static, so we can render and cache them.
|
||||
tabs := cache.SetIfNotExists("pages.about.Tabs", func() Node {
|
||||
return Group{
|
||||
H2(Text("Frontend")),
|
||||
P(Text("The following incredible projects make developing advanced, modern frontends possible and simple without having to write a single line of JS or CSS. You can go extremely far without leaving the comfort of Go with server-side rendered HTML.")),
|
||||
Tabs(
|
||||
"Frontend",
|
||||
"The following incredible projects make developing advanced, modern frontends possible and simple without having to write a single line of JS or CSS. You can go extremely far without leaving the comfort of Go with server-side rendered HTML.",
|
||||
[]Tab{
|
||||
{
|
||||
Title: "HTMX",
|
||||
|
|
@ -31,15 +31,14 @@ func About(ctx echo.Context) error {
|
|||
Body: "Drop-in, Vue-like functionality written directly in your markup. Visit <a href=\"https://alpinejs.dev/\">alpinejs.dev</a> to learn more.",
|
||||
},
|
||||
{
|
||||
Title: "Bulma",
|
||||
Body: "Ready-to-use frontend components that you can easily combine to build responsive web interfaces with no JavaScript requirements. Visit <a href=\"https://bulma.io/\">bulma.io</a> to learn more.",
|
||||
Title: "DaisyUI",
|
||||
Body: "DaisyUI is the Tailwind CSS plugin you will love! It provides useful component class names to help you write less code and build faster. No JavaScript requirements. Visit <a href=\"https://daisyui.com/\">daisyui.com</a> to learn more.",
|
||||
},
|
||||
},
|
||||
),
|
||||
Div(Class("mb-4")),
|
||||
H2(Text("Backend")),
|
||||
P(Text("The following incredible projects provide the foundation of the Go backend. See the repository for a complete list of included projects.")),
|
||||
Tabs(
|
||||
"Backend",
|
||||
"The following incredible projects provide the foundation of the Go backend. See the repository for a complete list of included projects.",
|
||||
[]Tab{
|
||||
{
|
||||
Title: "Echo",
|
||||
|
|
|
|||
|
|
@ -7,14 +7,12 @@ import (
|
|||
"entgo.io/ent/entc/load"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/mikestefanello/pagoda/ent/admin"
|
||||
"github.com/mikestefanello/pagoda/pkg/pager"
|
||||
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui"
|
||||
. "github.com/mikestefanello/pagoda/pkg/ui/components"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/forms"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/layouts"
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/components"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
|
|
@ -51,12 +49,12 @@ func AdminEntityList(
|
|||
r.Title = entityTypeName
|
||||
|
||||
genHeader := func() Node {
|
||||
g := make(Group, 0, len(entityList.Columns)+3)
|
||||
g := make(Group, 0, len(entityList.Columns)+2)
|
||||
g = append(g, Th(Text("ID")))
|
||||
for _, h := range entityList.Columns {
|
||||
g = append(g, Th(Text(h)))
|
||||
}
|
||||
g = append(g, Th(), Th())
|
||||
g = append(g, Th())
|
||||
return g
|
||||
}
|
||||
|
||||
|
|
@ -69,14 +67,14 @@ func AdminEntityList(
|
|||
g = append(g,
|
||||
Td(
|
||||
ButtonLink(
|
||||
ColorInfo,
|
||||
r.Path(routenames.AdminEntityEdit(entityTypeName), row.ID),
|
||||
"is-link",
|
||||
"Edit",
|
||||
),
|
||||
),
|
||||
Td(
|
||||
ButtonLink(r.Path(routenames.AdminEntityDelete(entityTypeName), row.ID),
|
||||
"is-danger",
|
||||
Span(Class("mr-2")),
|
||||
ButtonLink(
|
||||
ColorError,
|
||||
r.Path(routenames.AdminEntityDelete(entityTypeName), row.ID),
|
||||
"Delete",
|
||||
),
|
||||
),
|
||||
|
|
@ -92,45 +90,27 @@ func AdminEntityList(
|
|||
return g
|
||||
}
|
||||
|
||||
pagedHref := func(page int) string {
|
||||
return fmt.Sprintf("%s?%s=%d",
|
||||
r.Path(routenames.AdminEntityList(entityTypeName)),
|
||||
pager.QueryKey,
|
||||
page,
|
||||
)
|
||||
}
|
||||
|
||||
return r.Render(layouts.Primary, Group{
|
||||
ButtonLink(
|
||||
r.Path(routenames.AdminEntityAdd(entityTypeName)),
|
||||
"is-primary",
|
||||
fmt.Sprintf("Add %s", entityTypeName),
|
||||
Div(
|
||||
Class("form-control mb-2"),
|
||||
ButtonLink(
|
||||
ColorAccent,
|
||||
r.Path(routenames.AdminEntityAdd(entityTypeName)),
|
||||
fmt.Sprintf("Add %s", entityTypeName),
|
||||
),
|
||||
),
|
||||
Table(
|
||||
Class("table"),
|
||||
Class("table table-zebra mb-2"),
|
||||
THead(
|
||||
Tr(genHeader()),
|
||||
),
|
||||
TBody(genRows()),
|
||||
),
|
||||
Nav(
|
||||
Class("pagination"),
|
||||
A(
|
||||
Classes{
|
||||
"pagination-previous": true,
|
||||
"is-disabled": entityList.Page == 1,
|
||||
},
|
||||
If(entityList.Page != 1, Href(pagedHref(entityList.Page-1))),
|
||||
Text("Previous page"),
|
||||
),
|
||||
A(
|
||||
Classes{
|
||||
"pagination-previous": true,
|
||||
"is-disabled": !entityList.HasNextPage,
|
||||
},
|
||||
If(entityList.HasNextPage, Href(pagedHref(entityList.Page+1))),
|
||||
Text("Next page"),
|
||||
),
|
||||
Pager(
|
||||
entityList.Page,
|
||||
r.Path(routenames.AdminEntityAdd(entityTypeName)),
|
||||
entityList.HasNextPage,
|
||||
"",
|
||||
),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package pages
|
|||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/components"
|
||||
. "github.com/mikestefanello/pagoda/pkg/ui/components"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/forms"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/layouts"
|
||||
. "maragu.dev/gomponents"
|
||||
|
|
@ -17,21 +17,25 @@ func ContactUs(ctx echo.Context, form *forms.Contact) error {
|
|||
|
||||
g := Group{
|
||||
Iff(r.Htmx.Target != "contact", func() Node {
|
||||
return components.Message(
|
||||
"is-link",
|
||||
"",
|
||||
Group{
|
||||
P(Text("This is an example of a form with inline, server-side validation and HTMX-powered AJAX submissions without writing a single line of JavaScript.")),
|
||||
P(Text("Only the form below will update async upon submission.")),
|
||||
return Card(CardParams{
|
||||
Title: "Card component",
|
||||
Body: Group{
|
||||
Span(Text("This is an example of a form with inline, server-side validation and HTMX-powered AJAX submissions without writing a single line of JavaScript.")),
|
||||
Span(Text("Only the form below will update async upon submission.")),
|
||||
},
|
||||
)
|
||||
Color: ColorWarning,
|
||||
Size: SizeMedium,
|
||||
})
|
||||
}),
|
||||
Iff(form.IsDone(), func() Node {
|
||||
return components.Message(
|
||||
"is-large is-success",
|
||||
"Thank you!",
|
||||
Text("No email was actually sent but this entire operation was handled server-side and degrades without JavaScript enabled."),
|
||||
)
|
||||
return Card(CardParams{
|
||||
Title: "Thank you!",
|
||||
Body: Group{
|
||||
Span(Text("No email was actually sent but this entire operation was handled server-side and degrades without JavaScript enabled.")),
|
||||
},
|
||||
Color: ColorSuccess,
|
||||
Size: SizeLarge,
|
||||
})
|
||||
}),
|
||||
Iff(!form.IsDone(), func() Node {
|
||||
return form.Render(r)
|
||||
|
|
|
|||
|
|
@ -21,19 +21,19 @@ func UploadFile(ctx echo.Context, files []*models.File) error {
|
|||
}
|
||||
|
||||
n := Group{
|
||||
Message(
|
||||
"is-link",
|
||||
"",
|
||||
P(Text("This is a very basic example of how to handle file uploads. Files uploaded will be saved to the directory specified in your configuration.")),
|
||||
),
|
||||
Hr(),
|
||||
P(Text("This is a very basic example of how to handle file uploads. Files uploaded will be saved to the directory specified in your configuration.")),
|
||||
Divider(""),
|
||||
forms.File{}.Render(r),
|
||||
Hr(),
|
||||
Divider(""),
|
||||
H3(
|
||||
Class("title"),
|
||||
Text("Uploaded files"),
|
||||
),
|
||||
Message("is-warning", "", P(Text("Below are all files in the configured upload directory."))),
|
||||
Card(CardParams{
|
||||
Body: Group{Text("Below are all files in the configured upload directory.")},
|
||||
Color: ColorWarning,
|
||||
Size: SizeMedium,
|
||||
}),
|
||||
Table(
|
||||
Class("table"),
|
||||
THead(
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
package pages
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/mikestefanello/pagoda/pkg/routenames"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui"
|
||||
. "github.com/mikestefanello/pagoda/pkg/ui/components"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/icons"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/layouts"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/models"
|
||||
. "maragu.dev/gomponents"
|
||||
. "maragu.dev/gomponents/components"
|
||||
. "maragu.dev/gomponents/html"
|
||||
)
|
||||
|
||||
|
|
@ -38,69 +36,71 @@ func Home(ctx echo.Context, posts *models.Posts) error {
|
|||
|
||||
headerMsg := func() Node {
|
||||
return Group{
|
||||
Section(
|
||||
Class("hero is-info welcome is-small mb-3"),
|
||||
Div(
|
||||
Class("hero-body"),
|
||||
Div(
|
||||
Class("container"),
|
||||
H1(
|
||||
Class("title"),
|
||||
Iff(r.IsAuth, func() Node {
|
||||
return Text(fmt.Sprintf("Hello, %s", r.AuthUser.Name))
|
||||
}),
|
||||
If(!r.IsAuth, Text("Hello")),
|
||||
),
|
||||
H2(
|
||||
Class("subtitle"),
|
||||
If(!r.IsAuth, Text("Please login in to your account.")),
|
||||
If(r.IsAuth, Text("Welcome back!")),
|
||||
),
|
||||
),
|
||||
),
|
||||
Stats(
|
||||
Stat{
|
||||
Title: "User name",
|
||||
Value: func() string {
|
||||
if r.IsAuth {
|
||||
return r.AuthUser.Name
|
||||
}
|
||||
return "(not logged in)"
|
||||
}(),
|
||||
Description: "The logged in user's name",
|
||||
Icon: icons.UserCircle(),
|
||||
},
|
||||
Stat{
|
||||
Title: "Admin status",
|
||||
Value: func() string {
|
||||
if r.IsAdmin {
|
||||
return "Administrator"
|
||||
}
|
||||
return "Non-administrator"
|
||||
}(),
|
||||
Description: "Use `make admin` to create an admin account",
|
||||
Icon: icons.LockClosed(),
|
||||
},
|
||||
Stat{
|
||||
Title: "GitHub Stars",
|
||||
Value: "2,500+",
|
||||
Description: "Star if you like Pagoda",
|
||||
Icon: icons.Star(),
|
||||
},
|
||||
),
|
||||
Section(
|
||||
Class("hero is-light is-small mb-5"),
|
||||
Div(
|
||||
Class("hero-body"),
|
||||
Div(
|
||||
Class("container"),
|
||||
B(Text("Admin status: ")),
|
||||
Span(
|
||||
Classes{
|
||||
"tag": true,
|
||||
"is-success": r.IsAdmin,
|
||||
"is-danger": !r.IsAdmin,
|
||||
},
|
||||
Text(fmt.Sprint(r.IsAdmin)),
|
||||
),
|
||||
If(!r.IsAdmin, Span(
|
||||
Class("is-size-7 ml-3"),
|
||||
Raw(`(<a href="https://github.com/mikestefanello/pagoda#create-an-admin-account">click here</a> for instructions to make an admin account)`),
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
H2(Class("title"), Text("Recent posts")),
|
||||
H3(Class("subtitle"), Text("Below is an example of both paging and AJAX fetching using HTMX")),
|
||||
H2(Text("Recent posts")),
|
||||
Span(Text("Below is an example of both paging and AJAX fetching using HTMX")),
|
||||
}
|
||||
}
|
||||
|
||||
filesMsg := func() Node {
|
||||
return Message(
|
||||
"is-small is-warning mt-5",
|
||||
"Serving files",
|
||||
Group{
|
||||
Text("In the example posts above, check how the file URL contains a cache-buster query parameter which changes only when the app is restarted. "),
|
||||
Text("Static files also contain cache-control headers which are configured via middleware."),
|
||||
},
|
||||
cards := func() Node {
|
||||
return Div(
|
||||
Class("flex w-full gap-2 mt-5"),
|
||||
Card(CardParams{
|
||||
Title: "Serving files",
|
||||
Body: Group{
|
||||
Text("In the example posts above, check how the file URL contains a cache-buster query parameter which changes only when the app is restarted. "),
|
||||
Text("Static files also contain cache-control headers which are configured via middleware."),
|
||||
},
|
||||
Color: ColorWarning,
|
||||
Size: SizeSmall,
|
||||
}),
|
||||
Card(CardParams{
|
||||
Title: "Documentation",
|
||||
Body: Group{
|
||||
Text("Have you read through the entire documentation? If not, you may be missing functionality or have questions. "),
|
||||
},
|
||||
Footer: Group{
|
||||
ButtonLink(ColorNeutral, "https://github.com/mikestefanello/pagoda?tab=readme-ov-file#table-of-contents", "Learn more"),
|
||||
},
|
||||
Color: ColorNeutral,
|
||||
Size: SizeSmall,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
g := Group{
|
||||
Iff(r.Htmx.Target != "posts", headerMsg),
|
||||
posts.Render(r.Path(routenames.Home)),
|
||||
Iff(r.Htmx.Target != "posts", filesMsg),
|
||||
Iff(r.Htmx.Target != "posts", cards),
|
||||
}
|
||||
|
||||
return r.Render(layouts.Primary, g)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package pages
|
|||
import (
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/components"
|
||||
. "github.com/mikestefanello/pagoda/pkg/ui/components"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/forms"
|
||||
"github.com/mikestefanello/pagoda/pkg/ui/layouts"
|
||||
. "maragu.dev/gomponents"
|
||||
|
|
@ -17,23 +17,23 @@ func AddTask(ctx echo.Context, form *forms.Task) error {
|
|||
|
||||
g := Group{
|
||||
Iff(r.Htmx.Target != "task", func() Node {
|
||||
return components.Message(
|
||||
"is-link",
|
||||
"",
|
||||
Group{
|
||||
P(Raw("Submitting this form will create an <i>ExampleTask</i> in the task queue. After the specified delay, the message will be logged by the queue processor.")),
|
||||
P(Raw("See <i>pkg/tasks</i> and the README for more information.")),
|
||||
})
|
||||
return Group{
|
||||
P(Raw("Submitting this form will create an <i>ExampleTask</i> in the task queue. After the specified delay, the message will be logged by the queue processor.")),
|
||||
P(Raw("See <i>pkg/tasks</i> and the README for more information.")),
|
||||
}
|
||||
}),
|
||||
form.Render(r),
|
||||
Iff(r.Htmx.Target != "task", func() Node {
|
||||
return components.Message(
|
||||
"is-warning",
|
||||
"",
|
||||
Group{
|
||||
If(!r.IsAdmin, P(Text("Log in as an admin in order to access the task and queue monitoring UI."))),
|
||||
If(r.IsAdmin, P(Text("View all queued tasks by clicking on the Tasks link in the sidebar."))),
|
||||
})
|
||||
var text string
|
||||
if r.IsAdmin {
|
||||
text = "View all queued tasks by clicking on the Tasks link in the sidebar."
|
||||
} else {
|
||||
text = "Log in as an admin in order to access the task and queue monitoring UI."
|
||||
}
|
||||
return Group{
|
||||
Div(Class("mt-5")),
|
||||
Alert(ColorWarning, text),
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue