diff --git a/api/go.mod b/api/go.mod
index 0158f17..a25dc9f 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -4,7 +4,7 @@ go 1.22.2
require (
github.com/hashicorp/go-cleanhttp v0.5.2
- github.com/jonashiltl/openchangelog/apitypes v0.0.0-20240913181521-3708ddadc4d2
+ github.com/jonashiltl/openchangelog/apitypes v0.0.0-20240920110319-6925911f7f64
golang.org/x/net v0.25.0
)
diff --git a/api/go.sum b/api/go.sum
index 632e8d2..6bd492b 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -2,8 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
-github.com/jonashiltl/openchangelog/apitypes v0.0.0-20240913181521-3708ddadc4d2 h1:HasYzw37auhdq6nHXyvgEocAxeTPxRUjczIdLfkTdmY=
-github.com/jonashiltl/openchangelog/apitypes v0.0.0-20240913181521-3708ddadc4d2/go.mod h1:xnbFN3Wrw2B1F/D7pvjjwoeXSt+njRI31ccPFno0BM0=
+github.com/jonashiltl/openchangelog/apitypes v0.0.0-20240920110319-6925911f7f64 h1:yeoqi6Ur2IdboPLZU4I5XR+VzSQVEH+EwW4kPhun/EU=
+github.com/jonashiltl/openchangelog/apitypes v0.0.0-20240920110319-6925911f7f64/go.mod h1:xnbFN3Wrw2B1F/D7pvjjwoeXSt+njRI31ccPFno0BM0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
diff --git a/apitypes/changelog.go b/apitypes/changelog.go
index 41f62df..216a3a9 100644
--- a/apitypes/changelog.go
+++ b/apitypes/changelog.go
@@ -8,16 +8,17 @@ import (
// Represents the Changelog returned by the API via json encoding.
// Implements json un-/marshaling.
type Changelog struct {
- ID string
- WorkspaceID string
- Subdomain string
- Domain NullString
- Title NullString
- Subtitle NullString
- ColorScheme ColorScheme
- Logo Logo
- Source Source
- CreatedAt time.Time
+ ID string
+ WorkspaceID string
+ Subdomain string
+ Domain NullString
+ Title NullString
+ Subtitle NullString
+ ColorScheme ColorScheme
+ HidePoweredBy bool
+ Logo Logo
+ Source Source
+ CreatedAt time.Time
}
type ColorScheme string
@@ -30,25 +31,27 @@ const (
func (l Changelog) MarshalJSON() ([]byte, error) {
obj := struct {
- ID string `json:"id"`
- WorkspaceID string `json:"workspaceId"`
- Subdomain string `json:"subdomain,omitempty"`
- Title string `json:"title,omitempty"`
- Domain string `json:"domain,omitempty"`
- Subtitle string `json:"subtitle,omitempty"`
- ColorScheme string `json:"colorScheme,omitempty"`
- Logo *Logo `json:"logo,omitempty"`
- Source Source `json:"source,omitempty"`
- CreatedAt *time.Time `json:"createdAt,omitempty"`
+ ID string `json:"id"`
+ WorkspaceID string `json:"workspaceId"`
+ Subdomain string `json:"subdomain,omitempty"`
+ Title string `json:"title,omitempty"`
+ Domain string `json:"domain,omitempty"`
+ Subtitle string `json:"subtitle,omitempty"`
+ ColorScheme string `json:"colorScheme,omitempty"`
+ HidePoweredBy bool `json:"hidePoweredBy"`
+ Logo *Logo `json:"logo,omitempty"`
+ Source Source `json:"source,omitempty"`
+ CreatedAt *time.Time `json:"createdAt,omitempty"`
}{
- ID: l.ID,
- WorkspaceID: l.WorkspaceID,
- Subdomain: l.Subdomain,
- Domain: l.Domain.V(),
- Title: l.Title.V(),
- Subtitle: l.Subtitle.V(),
- ColorScheme: string(l.ColorScheme),
- Source: l.Source,
+ ID: l.ID,
+ WorkspaceID: l.WorkspaceID,
+ Subdomain: l.Subdomain,
+ Domain: l.Domain.V(),
+ Title: l.Title.V(),
+ Subtitle: l.Subtitle.V(),
+ ColorScheme: string(l.ColorScheme),
+ HidePoweredBy: l.HidePoweredBy,
+ Source: l.Source,
}
if l.Logo.IsValid() {
@@ -119,6 +122,13 @@ func (c *Changelog) UnmarshalJSON(b []byte) error {
}
}
+ if hidePoweredByRaw, ok := objMap["hidePoweredBy"]; ok {
+ err = json.Unmarshal(*hidePoweredByRaw, &c.HidePoweredBy)
+ if err != nil {
+ return err
+ }
+ }
+
if logoRaw, ok := objMap["logo"]; ok {
err = json.Unmarshal(*logoRaw, &c.Logo)
if err != nil {
@@ -207,14 +217,20 @@ func (l Logo) IsValid() bool {
}
type CreateChangelogBody struct {
- Title NullString `json:"title"`
- Subtitle NullString `json:"subtitle"`
- Logo Logo `json:"logo"`
- Domain NullString `json:"domain"`
- ColorScheme ColorScheme `json:"colorScheme"`
+ Title NullString `json:"title"`
+ Subtitle NullString `json:"subtitle"`
+ Logo Logo `json:"logo"`
+ Domain NullString `json:"domain"`
+ ColorScheme ColorScheme `json:"colorScheme"`
+ HidePoweredBy bool `json:"hidePoweredBy"`
}
type UpdateChangelogBody struct {
- CreateChangelogBody
- Subdomain NullString `json:"subdomain"`
+ Title NullString `json:"title"`
+ Subtitle NullString `json:"subtitle"`
+ Logo Logo `json:"logo"`
+ Domain NullString `json:"domain"`
+ ColorScheme ColorScheme `json:"colorScheme"`
+ Subdomain NullString `json:"subdomain"`
+ HidePoweredBy *bool `json:"hidePoweredBy,omitempty"`
}
diff --git a/apitypes/changelog_test.go b/apitypes/changelog_test.go
index d54047f..e365311 100644
--- a/apitypes/changelog_test.go
+++ b/apitypes/changelog_test.go
@@ -38,8 +38,9 @@ func TestChangelogMarshaling(t *testing.T) {
Repo: "openchangelog",
Path: ".testdata",
},
- ColorScheme: Dark,
- CreatedAt: now,
+ ColorScheme: Dark,
+ HidePoweredBy: true,
+ CreatedAt: now,
},
expect: fmt.Sprintf(`{
"id": "cl_xxxx",
@@ -63,23 +64,26 @@ func TestChangelogMarshaling(t *testing.T) {
"repo": "openchangelog",
"path": ".testdata"
},
+ "hidePoweredBy": true,
"colorScheme": "dark",
"createdAt": "%s"
}`, nowStr),
},
{
input: Changelog{
- ID: "cl_xxxx",
- WorkspaceID: "ws_xxxx",
- Title: NewString("Test Title"),
- ColorScheme: System,
- CreatedAt: now,
+ ID: "cl_xxxx",
+ WorkspaceID: "ws_xxxx",
+ Title: NewString("Test Title"),
+ ColorScheme: System,
+ HidePoweredBy: false,
+ CreatedAt: now,
},
expect: fmt.Sprintf(`{
"id": "cl_xxxx",
"workspaceId": "ws_xxxx",
"title": "Test Title",
"colorScheme": "system",
+ "hidePoweredBy": false,
"createdAt": "%s"
}`, nowStr),
},
@@ -94,6 +98,7 @@ func TestChangelogMarshaling(t *testing.T) {
expect: `{
"id": "cl_xxxx",
"workspaceId": "ws_xxxx",
+ "hidePoweredBy": false,
"logo": {
"alt": "test"
}
@@ -127,8 +132,9 @@ func TestChangelogUnmarshal(t *testing.T) {
Repo: "openchangelog",
Path: ".testdata",
},
- ColorScheme: Dark,
- CreatedAt: time.Unix(1715958564, 0).UTC(),
+ HidePoweredBy: true,
+ ColorScheme: Dark,
+ CreatedAt: time.Unix(1715958564, 0).UTC(),
},
{
ID: "cl_xxxx",
@@ -158,6 +164,7 @@ func TestChangelogUnmarshal(t *testing.T) {
}
func TestUpdateChangelogBodyMarshal(t *testing.T) {
+ hidePoweredBy := true
tests := []struct {
name string
input UpdateChangelogBody
@@ -178,9 +185,7 @@ func TestUpdateChangelogBodyMarshal(t *testing.T) {
{
name: "valid title",
input: UpdateChangelogBody{
- CreateChangelogBody: CreateChangelogBody{
- Title: NewString("test"),
- },
+ Title: NewString("test"),
},
expected: `{
"title": "test",
@@ -194,9 +199,7 @@ func TestUpdateChangelogBodyMarshal(t *testing.T) {
{
name: "null title",
input: UpdateChangelogBody{
- CreateChangelogBody: CreateChangelogBody{
- Title: NewNullString(),
- },
+ Title: NewNullString(),
},
expected: `{
"title": null,
@@ -210,10 +213,8 @@ func TestUpdateChangelogBodyMarshal(t *testing.T) {
{
name: "valid logo",
input: UpdateChangelogBody{
- CreateChangelogBody: CreateChangelogBody{
- Logo: Logo{
- Src: NewString("test"),
- },
+ Logo: Logo{
+ Src: NewString("test"),
},
},
expected: `{
@@ -230,9 +231,7 @@ func TestUpdateChangelogBodyMarshal(t *testing.T) {
{
name: "valid color scheme",
input: UpdateChangelogBody{
- CreateChangelogBody: CreateChangelogBody{
- ColorScheme: Dark,
- },
+ ColorScheme: Dark,
},
expected: `{
"title": "",
@@ -243,6 +242,21 @@ func TestUpdateChangelogBodyMarshal(t *testing.T) {
"colorScheme": "dark"
}`,
},
+ {
+ name: "valid hide powered by",
+ input: UpdateChangelogBody{
+ HidePoweredBy: &hidePoweredBy,
+ },
+ expected: `{
+ "title": "",
+ "subtitle": "",
+ "logo": {},
+ "domain": "",
+ "subdomain": "",
+ "colorScheme": "",
+ "hidePoweredBy": true
+ }`,
+ },
}
for _, test := range tests {
@@ -258,6 +272,7 @@ func TestUpdateChangelogBodyMarshal(t *testing.T) {
}
func TestUpdateChangelogBodyUnmarshal(t *testing.T) {
+ hidePoweredBy := true
tests := []struct {
name string
input UpdateChangelogBody
@@ -269,45 +284,41 @@ func TestUpdateChangelogBodyUnmarshal(t *testing.T) {
{
name: "valid title",
input: UpdateChangelogBody{
- CreateChangelogBody: CreateChangelogBody{
- Title: NewString("test"),
- },
+ Title: NewString("test"),
},
},
{
name: "null title",
input: UpdateChangelogBody{
- CreateChangelogBody: CreateChangelogBody{
- Title: NewNullString(),
- },
+ Title: NewNullString(),
},
},
{
name: "valid logo",
input: UpdateChangelogBody{
- CreateChangelogBody: CreateChangelogBody{
- Logo: Logo{
- Src: NewString("test"),
- },
+ Logo: Logo{
+ Src: NewString("test"),
},
},
},
{
name: "null logo src",
input: UpdateChangelogBody{
- CreateChangelogBody: CreateChangelogBody{
- Logo: Logo{
- Src: NewNullString(),
- },
+ Logo: Logo{
+ Src: NewNullString(),
},
},
},
{
name: "valid color scheme",
input: UpdateChangelogBody{
- CreateChangelogBody: CreateChangelogBody{
- ColorScheme: Dark,
- },
+ ColorScheme: Dark,
+ },
+ },
+ {
+ name: "valid hide powered by",
+ input: UpdateChangelogBody{
+ HidePoweredBy: &hidePoweredBy,
},
},
}
diff --git a/apitypes/null.go b/apitypes/null.go
index f33a9c6..512c3e5 100644
--- a/apitypes/null.go
+++ b/apitypes/null.go
@@ -106,3 +106,13 @@ func NewNullString() NullString {
}
type NullColorScheme = Null[ColorScheme]
+
+type NullBool = Null[bool]
+
+func NewBool(b bool) NullBool {
+ return NewValue(b)
+}
+
+func NewNullBool() NullBool {
+ return NewNull[bool]()
+}
diff --git a/components/footer.templ b/components/footer.templ
index 957f0ba..2460484 100644
--- a/components/footer.templ
+++ b/components/footer.templ
@@ -1,9 +1,15 @@
package components
-templ Footer() {
-
-}
\ No newline at end of file
+type FooterArgs struct {
+ HidePoweredBy bool
+}
+
+templ Footer(args FooterArgs) {
+
+}
diff --git a/components/footer_templ.go b/components/footer_templ.go
index 7418b30..ce7844d 100644
--- a/components/footer_templ.go
+++ b/components/footer_templ.go
@@ -8,7 +8,11 @@ package components
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
-func Footer() templ.Component {
+type FooterArgs struct {
+ HidePoweredBy bool
+}
+
+func Footer(args FooterArgs) templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
@@ -26,7 +30,17 @@ func Footer() templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
- _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/components/theme.templ b/components/theme.templ
index fc08252..369a272 100644
--- a/components/theme.templ
+++ b/components/theme.templ
@@ -31,7 +31,7 @@ templ Theme(args ThemeArgs) {
}
li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:initial;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;text-align:start;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:initial}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:#00000080;--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-top:.8888889em;margin-bottom:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.1428571em;margin-top:0;margin-bottom:.8em;line-height:1.2}.prose-sm :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.4285714em;margin-top:1.6em;margin-bottom:.8em;line-height:1.4}.prose-sm :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;margin-top:1.5555556em;margin-bottom:.4444444em;line-height:1.5555556}.prose-sm :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.4285714em;margin-bottom:.5714286em;line-height:1.4285714}.prose-sm :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;border-radius:.3125rem;padding-top:.1428571em;padding-inline-end:.3571429em;padding-bottom:.1428571em;padding-inline-start:.3571429em}.prose-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.6666667;margin-top:1.6666667em;margin-bottom:1.6666667em;border-radius:.25rem;padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;margin-bottom:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;padding-inline-start:1.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2.8571429em;margin-bottom:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.relative{position:relative}.sticky{position:sticky}.top-0{top:0}.z-\[1\]{z-index:1}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-8{margin-top:2rem;margin-bottom:2rem}.mb-4{margin-bottom:1rem}.mt-10{margin-top:2.5rem}.mt-12{margin-top:3rem}.mt-8{margin-top:2rem}.flex{display:flex}.h-10{height:2.5rem}.h-24{height:6rem}.h-5{height:1.25rem}.h-8{height:2rem}.h-full{height:100%}.max-h-full{max-height:100%}.w-3\/4{width:75%}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-full{max-width:100%}.max-w-prose{max-width:65ch}.flex-1{flex:1 1 0%}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.rounded{border-radius:.25rem}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-solid{border-style:solid}.border-b-black\/10{border-bottom-color:#0000001a}.border-t-gray-200{--tw-border-opacity:1;border-top-color:rgb(229 231 235/var(--tw-border-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-neutral-50{--tw-bg-opacity:1;background-color:rgb(250 250 250/var(--tw-bg-opacity))}.object-contain{-o-object-fit:contain;object-fit:contain}.p-1{padding:.25rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pt-10{padding-top:2.5rem}.text-center{text-align:center}.text-caption{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.opacity-0{opacity:0}.backdrop-blur-md{--tw-backdrop-blur:blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}@media (min-width:640px){.sm\:prose-base{font-size:1rem;line-height:1.75}.sm\:prose-base :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.sm\:prose-base :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.sm\:prose-base :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.sm\:prose-base :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.sm\:prose-base :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.sm\:prose-base :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.sm\:prose-base :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.sm\:prose-base :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.sm\:prose-base :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.sm\:prose-base :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.sm\:prose-base :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.sm\:prose-base :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.sm\:prose-base :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.sm\:prose-base :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.sm\:prose-base :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.sm\:prose-base :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.sm\:prose-base :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.sm\:prose-base :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.sm\:prose-base :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.sm\:prose-base :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.sm\:prose-base :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.sm\:prose-base :where(.sm\:prose-base>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.sm\:prose-base :where(.sm\:prose-base>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.sm\:prose-base :where(.sm\:prose-base>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.sm\:prose-base :where(.sm\:prose-base>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.sm\:prose-base :where(.sm\:prose-base>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.sm\:prose-base :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.sm\:prose-base :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.sm\:prose-base :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.sm\:prose-base :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.sm\:prose-base :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:3em;margin-bottom:3em}.sm\:prose-base :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857}.sm\:prose-base :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.sm\:prose-base :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.sm\:prose-base :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.sm\:prose-base :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.sm\:prose-base :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.sm\:prose-base :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.sm\:prose-base :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.sm\:prose-base :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.sm\:prose-base :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.sm\:prose-base :where(.sm\:prose-base>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(.sm\:prose-base>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}}.dark\:prose-invert:where([color-scheme=dark],[color-scheme=dark] *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.hover\:bg-orange-400\/10:hover{background-color:#fb923c1a}.hover\:text-orange-400:hover{--tw-text-opacity:1;color:rgb(251 146 60/var(--tw-text-opacity))}.group:hover .group-hover\:opacity-100{opacity:1}.prose-h1\:mb-3 :is(:where(h1):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.75rem}.prose-h2\:mb-2 :is(:where(h2):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.5rem}.prose-h3\:mb-2 :is(:where(h3):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.5rem}.prose-p\:my-2 :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){margin-top:.5rem;margin-bottom:.5rem}.prose-p\:leading-6 :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){line-height:1.5rem}.prose-a\:text-primary :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity))}.prose-a\:no-underline :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){text-decoration-line:none}.prose-a\:underline-offset-4 :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){text-underline-offset:4px}.hover\:prose-a\:text-primary-highlight :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))):hover{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.hover\:prose-a\:underline :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))):hover{text-decoration-line:underline}.prose-img\:rounded :is(:where(img):not(:where([class~=not-prose],[class~=not-prose] *))){border-radius:.25rem}@media (min-width:640px){.sm\:mx-0{margin-left:0;margin-right:0}.sm\:mt-10{margin-top:2.5rem}.sm\:px-0{padding-left:0;padding-right:0}}@media (min-width:768px){.md\:mt-20{margin-top:5rem}}@media (min-width:1024px){.lg\:absolute{position:absolute}.lg\:-left-40{left:-10rem}.lg\:top-0{top:0}.lg\:\!mt-1{margin-top:.25rem!important}}.dark\:border-b-white\/10:where([color-scheme=dark],[color-scheme=dark] *){border-bottom-color:#ffffff1a}.dark\:border-t-gray-800:where([color-scheme=dark],[color-scheme=dark] *){--tw-border-opacity:1;border-top-color:rgb(31 41 55/var(--tw-border-opacity))}.dark\:bg-neutral-950:where([color-scheme=dark],[color-scheme=dark] *){--tw-bg-opacity:1;background-color:rgb(10 10 10/var(--tw-bg-opacity))}.dark\:bg-white\/5:where([color-scheme=dark],[color-scheme=dark] *){background-color:#ffffff0d}.dark\:text-neutral-400:where([color-scheme=dark],[color-scheme=dark] *){--tw-text-opacity:1;color:rgb(163 163 163/var(--tw-text-opacity))}.dark\:text-white:where([color-scheme=dark],[color-scheme=dark] *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.\[\&\:not\(\.htmx-request\)\]\:h-0:not(.htmx-request){height:0}.\[\&\:not\(\.htmx-request\)\]\:overflow-hidden:not(.htmx-request){overflow:hidden}.\[\&\:not\(\.htmx-request\)\]\:opacity-0:not(.htmx-request){opacity:0}
\ No newline at end of file
+/*! tailwindcss v3.4.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter var,ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.prose :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);text-decoration:underline;font-weight:500}.prose :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{font-weight:400;color:var(--tw-prose-counters)}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.25em}.prose :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-top:3em;margin-bottom:3em}.prose :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-style:italic;color:var(--tw-prose-quotes);border-inline-start-width:.25rem;border-inline-start-color:var(--tw-prose-quote-borders);quotes:"\201C""\201D""\2018""\2019";margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:800;font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.prose :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:900;color:inherit}.prose :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:700;font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.prose :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:800;color:inherit}.prose :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.prose :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.prose :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:700;color:inherit}.prose :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-top:2em;margin-bottom:2em}.prose :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-weight:500;font-family:inherit;color:var(--tw-prose-kbd);box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-weight:600;font-size:.875em}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-pre-code);background-color:var(--tw-prose-pre-bg);overflow-x:auto;font-weight:400;font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:initial;border-width:0;border-radius:0;padding:0;font-weight:inherit;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){width:100%;table-layout:auto;text-align:start;margin-top:2em;margin-bottom:2em;font-size:.875em;line-height:1.7142857}.prose :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-th-borders)}.prose :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;vertical-align:bottom;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:1px;border-bottom-color:var(--tw-prose-td-borders)}.prose :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:initial}.prose :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-width:1px;border-top-color:var(--tw-prose-th-borders)}.prose :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.prose :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-kbd:#111827;--tw-prose-kbd-shadows:17 24 39;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:#00000080;--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.prose :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.prose :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.prose :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.prose :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.prose :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-top:.8888889em;margin-bottom:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.3333333em;margin-bottom:1.3333333em;padding-inline-start:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.1428571em;margin-top:0;margin-bottom:.8em;line-height:1.2}.prose-sm :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.4285714em;margin-top:1.6em;margin-bottom:.8em;line-height:1.4}.prose-sm :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.2857143em;margin-top:1.5555556em;margin-bottom:.4444444em;line-height:1.5555556}.prose-sm :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.4285714em;margin-bottom:.5714286em;line-height:1.4285714}.prose-sm :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;border-radius:.3125rem;padding-top:.1428571em;padding-inline-end:.3571429em;padding-bottom:.1428571em;padding-inline-start:.3571429em}.prose-sm :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.6666667;margin-top:1.6666667em;margin-bottom:1.6666667em;border-radius:.25rem;padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em;padding-inline-start:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;margin-bottom:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.4285714em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5714286em;margin-bottom:.5714286em}.prose-sm :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em;margin-bottom:1.1428571em}.prose-sm :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.2857143em;padding-inline-start:1.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2.8571429em;margin-bottom:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.6666667em;padding-inline-end:1em;padding-bottom:.6666667em;padding-inline-start:1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.prose-sm :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.7142857em;margin-bottom:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.prose-sm :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.relative{position:relative}.sticky{position:sticky}.top-0{top:0}.z-\[1\]{z-index:1}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-8{margin-top:2rem;margin-bottom:2rem}.mb-4{margin-bottom:1rem}.mt-10{margin-top:2.5rem}.mt-12{margin-top:3rem}.mt-8{margin-top:2rem}.flex{display:flex}.h-10{height:2.5rem}.h-24{height:6rem}.h-5{height:1.25rem}.h-8{height:2rem}.h-full{height:100%}.max-h-full{max-height:100%}.min-h-full{min-height:100%}.w-3\/4{width:75%}.w-full{width:100%}.max-w-2xl{max-width:42rem}.max-w-full{max-width:100%}.max-w-prose{max-width:65ch}.flex-1{flex:1 1 0%}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.rounded{border-radius:.25rem}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-solid{border-style:solid}.border-b-black\/10{border-bottom-color:#0000001a}.border-t-gray-200{--tw-border-opacity:1;border-top-color:rgb(229 231 235/var(--tw-border-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-neutral-50{--tw-bg-opacity:1;background-color:rgb(250 250 250/var(--tw-bg-opacity))}.object-contain{-o-object-fit:contain;object-fit:contain}.p-1{padding:.25rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.pb-20{padding-bottom:5rem}.pt-10{padding-top:2.5rem}.text-center{text-align:center}.text-caption{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.opacity-0{opacity:0}.backdrop-blur-md{--tw-backdrop-blur:blur(12px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}@media (min-width:640px){.sm\:prose-base{font-size:1rem;line-height:1.75}.sm\:prose-base :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.sm\:prose-base :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.25em;line-height:1.6;margin-top:1.2em;margin-bottom:1.2em}.sm\:prose-base :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.6em;margin-bottom:1.6em;padding-inline-start:1em}.sm\:prose-base :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:2.25em;margin-top:0;margin-bottom:.8888889em;line-height:1.1111111}.sm\:prose-base :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.5em;margin-top:2em;margin-bottom:1em;line-height:1.3333333}.sm\:prose-base :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:1.25em;margin-top:1.6em;margin-bottom:.6em;line-height:1.6}.sm\:prose-base :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.5em;margin-bottom:.5em;line-height:1.5}.sm\:prose-base :where(img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.sm\:prose-base :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.sm\:prose-base :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.sm\:prose-base :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.sm\:prose-base :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;border-radius:.3125rem;padding-top:.1875em;padding-inline-end:.375em;padding-bottom:.1875em;padding-inline-start:.375em}.sm\:prose-base :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.sm\:prose-base :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em}.sm\:prose-base :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.9em}.sm\:prose-base :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-top:1.7142857em;margin-bottom:1.7142857em;border-radius:.375rem;padding-top:.8571429em;padding-inline-end:1.1428571em;padding-bottom:.8571429em;padding-inline-start:1.1428571em}.sm\:prose-base :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.sm\:prose-base :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em;padding-inline-start:1.625em}.sm\:prose-base :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;margin-bottom:.5em}.sm\:prose-base :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.sm\:prose-base :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.375em}.sm\:prose-base :where(.sm\:prose-base>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.sm\:prose-base :where(.sm\:prose-base>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.sm\:prose-base :where(.sm\:prose-base>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.sm\:prose-base :where(.sm\:prose-base>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.sm\:prose-base :where(.sm\:prose-base>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.sm\:prose-base :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.75em;margin-bottom:.75em}.sm\:prose-base :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em;margin-bottom:1.25em}.sm\:prose-base :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.sm\:prose-base :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.5em;padding-inline-start:1.625em}.sm\:prose-base :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:3em;margin-bottom:3em}.sm\:prose-base :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.7142857}.sm\:prose-base :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.sm\:prose-base :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.sm\:prose-base :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.sm\:prose-base :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-top:.5714286em;padding-inline-end:.5714286em;padding-bottom:.5714286em;padding-inline-start:.5714286em}.sm\:prose-base :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.sm\:prose-base :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.sm\:prose-base :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:2em;margin-bottom:2em}.sm\:prose-base :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0;margin-bottom:0}.sm\:prose-base :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.sm\:prose-base :where(.sm\:prose-base>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.sm\:prose-base :where(.sm\:prose-base>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}}.dark\:prose-invert:where([color-scheme=dark],[color-scheme=dark] *){--tw-prose-body:var(--tw-prose-invert-body);--tw-prose-headings:var(--tw-prose-invert-headings);--tw-prose-lead:var(--tw-prose-invert-lead);--tw-prose-links:var(--tw-prose-invert-links);--tw-prose-bold:var(--tw-prose-invert-bold);--tw-prose-counters:var(--tw-prose-invert-counters);--tw-prose-bullets:var(--tw-prose-invert-bullets);--tw-prose-hr:var(--tw-prose-invert-hr);--tw-prose-quotes:var(--tw-prose-invert-quotes);--tw-prose-quote-borders:var(--tw-prose-invert-quote-borders);--tw-prose-captions:var(--tw-prose-invert-captions);--tw-prose-kbd:var(--tw-prose-invert-kbd);--tw-prose-kbd-shadows:var(--tw-prose-invert-kbd-shadows);--tw-prose-code:var(--tw-prose-invert-code);--tw-prose-pre-code:var(--tw-prose-invert-pre-code);--tw-prose-pre-bg:var(--tw-prose-invert-pre-bg);--tw-prose-th-borders:var(--tw-prose-invert-th-borders);--tw-prose-td-borders:var(--tw-prose-invert-td-borders)}.hover\:bg-orange-400\/10:hover{background-color:#fb923c1a}.hover\:text-orange-400:hover{--tw-text-opacity:1;color:rgb(251 146 60/var(--tw-text-opacity))}.group:hover .group-hover\:opacity-100{opacity:1}.prose-h1\:mb-3 :is(:where(h1):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.75rem}.prose-h2\:mb-2 :is(:where(h2):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.5rem}.prose-h3\:mb-2 :is(:where(h3):not(:where([class~=not-prose],[class~=not-prose] *))){margin-bottom:.5rem}.prose-p\:my-2 :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){margin-top:.5rem;margin-bottom:.5rem}.prose-p\:leading-6 :is(:where(p):not(:where([class~=not-prose],[class~=not-prose] *))){line-height:1.5rem}.prose-a\:text-primary :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity))}.prose-a\:no-underline :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){text-decoration-line:none}.prose-a\:underline-offset-4 :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))){text-underline-offset:4px}.hover\:prose-a\:text-primary-highlight :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))):hover{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity))}.hover\:prose-a\:underline :is(:where(a):not(:where([class~=not-prose],[class~=not-prose] *))):hover{text-decoration-line:underline}.prose-img\:rounded :is(:where(img):not(:where([class~=not-prose],[class~=not-prose] *))){border-radius:.25rem}@media (min-width:640px){.sm\:mx-0{margin-left:0;margin-right:0}.sm\:mt-10{margin-top:2.5rem}.sm\:px-0{padding-left:0;padding-right:0}}@media (min-width:768px){.md\:mt-20{margin-top:5rem}}@media (min-width:1024px){.lg\:absolute{position:absolute}.lg\:-left-40{left:-10rem}.lg\:top-0{top:0}.lg\:\!mt-1{margin-top:.25rem!important}}.dark\:border-b-white\/10:where([color-scheme=dark],[color-scheme=dark] *){border-bottom-color:#ffffff1a}.dark\:border-t-gray-800:where([color-scheme=dark],[color-scheme=dark] *){--tw-border-opacity:1;border-top-color:rgb(31 41 55/var(--tw-border-opacity))}.dark\:bg-neutral-950:where([color-scheme=dark],[color-scheme=dark] *){--tw-bg-opacity:1;background-color:rgb(10 10 10/var(--tw-bg-opacity))}.dark\:bg-white\/5:where([color-scheme=dark],[color-scheme=dark] *){background-color:#ffffff0d}.dark\:text-neutral-400:where([color-scheme=dark],[color-scheme=dark] *){--tw-text-opacity:1;color:rgb(163 163 163/var(--tw-text-opacity))}.dark\:text-white:where([color-scheme=dark],[color-scheme=dark] *){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.\[\&\:not\(\.htmx-request\)\]\:h-0:not(.htmx-request){height:0}.\[\&\:not\(\.htmx-request\)\]\:overflow-hidden:not(.htmx-request){overflow:hidden}.\[\&\:not\(\.htmx-request\)\]\:opacity-0:not(.htmx-request){opacity:0}
\ No newline at end of file
diff --git a/internal/handler/web/views/index.templ b/internal/handler/web/views/index.templ
index fe6190d..5fe2d9d 100644
--- a/internal/handler/web/views/index.templ
+++ b/internal/handler/web/views/index.templ
@@ -12,6 +12,7 @@ type IndexArgs struct {
components.Logo
components.HeaderArgs
components.ArticleListArgs
+ components.FooterArgs
}
templ Index(arg IndexArgs) {
@@ -28,7 +29,7 @@ templ Index(arg IndexArgs) {
}
@components.ArticleList(arg.ArticleListArgs)
}
- @components.Footer()
+ @components.Footer(arg.FooterArgs)
}
}
}
diff --git a/internal/handler/web/views/index_templ.go b/internal/handler/web/views/index_templ.go
index ecd4cda..3689cec 100644
--- a/internal/handler/web/views/index_templ.go
+++ b/internal/handler/web/views/index_templ.go
@@ -20,6 +20,7 @@ type IndexArgs struct {
components.Logo
components.HeaderArgs
components.ArticleListArgs
+ components.FooterArgs
}
func Index(arg IndexArgs) templ.Component {
@@ -162,7 +163,7 @@ func Index(arg IndexArgs) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
- templ_7745c5c3_Err = components.Footer().Render(ctx, templ_7745c5c3_Buffer)
+ templ_7745c5c3_Err = components.Footer(arg.FooterArgs).Render(ctx, templ_7745c5c3_Buffer)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
diff --git a/internal/store/config.go b/internal/store/config.go
index a9d4808..e8629b6 100644
--- a/internal/store/config.go
+++ b/internal/store/config.go
@@ -44,6 +44,7 @@ func (s *configStore) GetChangelog(ctx context.Context, wID WorkspaceID, cID Cha
if s.cfg.Page != nil {
cl.Title = apitypes.NewString(s.cfg.Page.Title)
cl.Subtitle = apitypes.NewString(s.cfg.Page.Subtitle)
+ cl.HidePoweredBy = s.cfg.Page.HidePoweredBy
switch strings.ToLower(s.cfg.Page.ColorScheme) {
case System.String():
cl.ColorScheme = System
diff --git a/internal/store/models.go b/internal/store/models.go
index 776dcad..cb33480 100644
--- a/internal/store/models.go
+++ b/internal/store/models.go
@@ -11,20 +11,21 @@ import (
)
type changelog struct {
- ID string
- WorkspaceID string
- Subdomain string
- Title apitypes.NullString
- Subtitle apitypes.NullString
- SourceID apitypes.NullString
- LogoSrc apitypes.NullString
- LogoLink apitypes.NullString
- LogoAlt apitypes.NullString
- LogoHeight apitypes.NullString
- LogoWidth apitypes.NullString
- CreatedAt int64
- Domain apitypes.NullString
- ColorScheme ColorScheme
+ ID string
+ WorkspaceID string
+ Subdomain string
+ Title apitypes.NullString
+ Subtitle apitypes.NullString
+ SourceID apitypes.NullString
+ LogoSrc apitypes.NullString
+ LogoLink apitypes.NullString
+ LogoAlt apitypes.NullString
+ LogoHeight apitypes.NullString
+ LogoWidth apitypes.NullString
+ CreatedAt int64
+ Domain apitypes.NullString
+ ColorScheme ColorScheme
+ HidePoweredBy int64
}
type changelogSource struct {
diff --git a/internal/store/query.sql b/internal/store/query.sql
index 1be76a6..d00c5dc 100644
--- a/internal/store/query.sql
+++ b/internal/store/query.sql
@@ -36,8 +36,8 @@ LIMIT 1;
-- name: createChangelog :one
INSERT INTO changelogs (
- workspace_id, id, subdomain, domain, title, subtitle, logo_src, logo_link, logo_alt, logo_height, logo_width, color_scheme
-) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ workspace_id, id, subdomain, domain, title, subtitle, logo_src, logo_link, logo_alt, logo_height, logo_width, color_scheme, hide_powered_by
+) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
RETURNING *;
-- name: deleteChangelog :exec
@@ -68,6 +68,7 @@ WHERE c.workspace_id = ?;
UPDATE changelogs
SET
subdomain = coalesce(sqlc.narg(subdomain), subdomain),
+ hide_powered_by = coalesce(sqlc.narg(hide_powered_by), hide_powered_by),
title = CASE WHEN cast(@set_title as bool) THEN @title ELSE title END,
subtitle = CASE WHEN cast(@set_subtitle as bool) THEN @subtitle ELSE subtitle END,
domain = CASE WHEN cast(@set_domain as bool) THEN @domain ELSE domain END,
diff --git a/internal/store/query.sql.go b/internal/store/query.sql.go
index 3d51515..21bca26 100644
--- a/internal/store/query.sql.go
+++ b/internal/store/query.sql.go
@@ -7,30 +7,32 @@ package store
import (
"context"
+ "database/sql"
"github.com/jonashiltl/openchangelog/apitypes"
)
const createChangelog = `-- name: createChangelog :one
INSERT INTO changelogs (
- workspace_id, id, subdomain, domain, title, subtitle, logo_src, logo_link, logo_alt, logo_height, logo_width, color_scheme
-) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-RETURNING id, workspace_id, subdomain, title, subtitle, source_id, logo_src, logo_link, logo_alt, logo_height, logo_width, created_at, domain, color_scheme
+ workspace_id, id, subdomain, domain, title, subtitle, logo_src, logo_link, logo_alt, logo_height, logo_width, color_scheme, hide_powered_by
+) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+RETURNING id, workspace_id, subdomain, title, subtitle, source_id, logo_src, logo_link, logo_alt, logo_height, logo_width, created_at, domain, color_scheme, hide_powered_by
`
type createChangelogParams struct {
- WorkspaceID string
- ID string
- Subdomain string
- Domain apitypes.NullString
- Title apitypes.NullString
- Subtitle apitypes.NullString
- LogoSrc apitypes.NullString
- LogoLink apitypes.NullString
- LogoAlt apitypes.NullString
- LogoHeight apitypes.NullString
- LogoWidth apitypes.NullString
- ColorScheme ColorScheme
+ WorkspaceID string
+ ID string
+ Subdomain string
+ Domain apitypes.NullString
+ Title apitypes.NullString
+ Subtitle apitypes.NullString
+ LogoSrc apitypes.NullString
+ LogoLink apitypes.NullString
+ LogoAlt apitypes.NullString
+ LogoHeight apitypes.NullString
+ LogoWidth apitypes.NullString
+ ColorScheme ColorScheme
+ HidePoweredBy int64
}
func (q *Queries) createChangelog(ctx context.Context, arg createChangelogParams) (changelog, error) {
@@ -47,6 +49,7 @@ func (q *Queries) createChangelog(ctx context.Context, arg createChangelogParams
arg.LogoHeight,
arg.LogoWidth,
arg.ColorScheme,
+ arg.HidePoweredBy,
)
var i changelog
err := row.Scan(
@@ -64,6 +67,7 @@ func (q *Queries) createChangelog(ctx context.Context, arg createChangelogParams
&i.CreatedAt,
&i.Domain,
&i.ColorScheme,
+ &i.HidePoweredBy,
)
return i, err
}
@@ -180,7 +184,7 @@ func (q *Queries) deleteWorkspace(ctx context.Context, id string) error {
}
const getChangelog = `-- name: getChangelog :one
-SELECT c.id, c.workspace_id, c.subdomain, c.title, c.subtitle, c.source_id, c.logo_src, c.logo_link, c.logo_alt, c.logo_height, c.logo_width, c.created_at, c.domain, c.color_scheme, cs.id, cs.workspace_id, cs.owner, cs.repo, cs.path, cs.installation_id
+SELECT c.id, c.workspace_id, c.subdomain, c.title, c.subtitle, c.source_id, c.logo_src, c.logo_link, c.logo_alt, c.logo_height, c.logo_width, c.created_at, c.domain, c.color_scheme, c.hide_powered_by, cs.id, cs.workspace_id, cs.owner, cs.repo, cs.path, cs.installation_id
FROM changelogs c
LEFT JOIN changelog_source cs ON c.workspace_id = cs.workspace_id AND c.source_id = cs.id
WHERE c.workspace_id = ? AND c.id = ?
@@ -214,6 +218,7 @@ func (q *Queries) getChangelog(ctx context.Context, arg getChangelogParams) (get
&i.changelog.CreatedAt,
&i.changelog.Domain,
&i.changelog.ColorScheme,
+ &i.changelog.HidePoweredBy,
&i.ChangelogSource.ID,
&i.ChangelogSource.WorkspaceID,
&i.ChangelogSource.Owner,
@@ -225,7 +230,7 @@ func (q *Queries) getChangelog(ctx context.Context, arg getChangelogParams) (get
}
const getChangelogByDomainOrSubdomain = `-- name: getChangelogByDomainOrSubdomain :one
-SELECT c.id, c.workspace_id, c.subdomain, c.title, c.subtitle, c.source_id, c.logo_src, c.logo_link, c.logo_alt, c.logo_height, c.logo_width, c.created_at, c.domain, c.color_scheme, cs.id, cs.workspace_id, cs.owner, cs.repo, cs.path, cs.installation_id
+SELECT c.id, c.workspace_id, c.subdomain, c.title, c.subtitle, c.source_id, c.logo_src, c.logo_link, c.logo_alt, c.logo_height, c.logo_width, c.created_at, c.domain, c.color_scheme, c.hide_powered_by, cs.id, cs.workspace_id, cs.owner, cs.repo, cs.path, cs.installation_id
FROM changelogs c
LEFT JOIN changelog_source cs ON c.workspace_id = cs.workspace_id AND c.source_id = cs.id
WHERE c.domain = ? OR c.subdomain = ?
@@ -261,6 +266,7 @@ func (q *Queries) getChangelogByDomainOrSubdomain(ctx context.Context, arg getCh
&i.changelog.CreatedAt,
&i.changelog.Domain,
&i.changelog.ColorScheme,
+ &i.changelog.HidePoweredBy,
&i.ChangelogSource.ID,
&i.ChangelogSource.WorkspaceID,
&i.ChangelogSource.Owner,
@@ -347,7 +353,7 @@ func (q *Queries) getWorkspace(ctx context.Context, id string) (getWorkspaceRow,
}
const listChangelogs = `-- name: listChangelogs :many
-SELECT c.id, c.workspace_id, c.subdomain, c.title, c.subtitle, c.source_id, c.logo_src, c.logo_link, c.logo_alt, c.logo_height, c.logo_width, c.created_at, c.domain, c.color_scheme, cs.id, cs.workspace_id, cs.owner, cs.repo, cs.path, cs.installation_id
+SELECT c.id, c.workspace_id, c.subdomain, c.title, c.subtitle, c.source_id, c.logo_src, c.logo_link, c.logo_alt, c.logo_height, c.logo_width, c.created_at, c.domain, c.color_scheme, c.hide_powered_by, cs.id, cs.workspace_id, cs.owner, cs.repo, cs.path, cs.installation_id
FROM changelogs c
LEFT JOIN changelog_source cs ON c.workspace_id = cs.workspace_id AND c.source_id = cs.id
WHERE c.workspace_id = ?
@@ -382,6 +388,7 @@ func (q *Queries) listChangelogs(ctx context.Context, workspaceID string) ([]lis
&i.changelog.CreatedAt,
&i.changelog.Domain,
&i.changelog.ColorScheme,
+ &i.changelog.HidePoweredBy,
&i.ChangelogSource.ID,
&i.ChangelogSource.WorkspaceID,
&i.ChangelogSource.Owner,
@@ -479,21 +486,23 @@ const updateChangelog = `-- name: updateChangelog :one
UPDATE changelogs
SET
subdomain = coalesce(?1, subdomain),
- title = CASE WHEN cast(?2 as bool) THEN ?3 ELSE title END,
- subtitle = CASE WHEN cast(?4 as bool) THEN ?5 ELSE subtitle END,
- domain = CASE WHEN cast(?6 as bool) THEN ?7 ELSE domain END,
- logo_src = CASE WHEN cast(?8 as bool) THEN ?9 ELSE logo_src END,
- logo_link = CASE WHEN cast(?10 as bool) THEN ?11 ELSE logo_link END,
- logo_alt = CASE WHEN cast(?12 as bool) THEN ?13 ELSE logo_alt END,
- logo_height = CASE WHEN cast(?14 as bool) THEN ?15 ELSE logo_height END,
- logo_width = CASE WHEN cast(?16 as bool) THEN ?17 ELSE logo_width END,
- color_scheme = CASE WHEN cast(?18 as bool) THEN ?19 ELSE color_scheme END
-WHERE workspace_id = ?20 AND id = ?21
-RETURNING id, workspace_id, subdomain, title, subtitle, source_id, logo_src, logo_link, logo_alt, logo_height, logo_width, created_at, domain, color_scheme
+ hide_powered_by = coalesce(?2, hide_powered_by),
+ title = CASE WHEN cast(?3 as bool) THEN ?4 ELSE title END,
+ subtitle = CASE WHEN cast(?5 as bool) THEN ?6 ELSE subtitle END,
+ domain = CASE WHEN cast(?7 as bool) THEN ?8 ELSE domain END,
+ logo_src = CASE WHEN cast(?9 as bool) THEN ?10 ELSE logo_src END,
+ logo_link = CASE WHEN cast(?11 as bool) THEN ?12 ELSE logo_link END,
+ logo_alt = CASE WHEN cast(?13 as bool) THEN ?14 ELSE logo_alt END,
+ logo_height = CASE WHEN cast(?15 as bool) THEN ?16 ELSE logo_height END,
+ logo_width = CASE WHEN cast(?17 as bool) THEN ?18 ELSE logo_width END,
+ color_scheme = CASE WHEN cast(?19 as bool) THEN ?20 ELSE color_scheme END
+WHERE workspace_id = ?21 AND id = ?22
+RETURNING id, workspace_id, subdomain, title, subtitle, source_id, logo_src, logo_link, logo_alt, logo_height, logo_width, created_at, domain, color_scheme, hide_powered_by
`
type updateChangelogParams struct {
Subdomain apitypes.NullString
+ HidePoweredBy sql.NullInt64
SetTitle bool
Title apitypes.NullString
SetSubtitle bool
@@ -519,6 +528,7 @@ type updateChangelogParams struct {
func (q *Queries) updateChangelog(ctx context.Context, arg updateChangelogParams) (changelog, error) {
row := q.db.QueryRowContext(ctx, updateChangelog,
arg.Subdomain,
+ arg.HidePoweredBy,
arg.SetTitle,
arg.Title,
arg.SetSubtitle,
@@ -556,6 +566,7 @@ func (q *Queries) updateChangelog(ctx context.Context, arg updateChangelogParams
&i.CreatedAt,
&i.Domain,
&i.ColorScheme,
+ &i.HidePoweredBy,
)
return i, err
}
diff --git a/internal/store/sqlite.go b/internal/store/sqlite.go
index ad64836..f2d237c 100644
--- a/internal/store/sqlite.go
+++ b/internal/store/sqlite.go
@@ -16,20 +16,21 @@ import (
func (cl changelog) toExported(source changelogSource) Changelog {
c := Changelog{
- WorkspaceID: WorkspaceID(cl.WorkspaceID),
- ID: ChangelogID(cl.ID),
- Subdomain: Subdomain(cl.Subdomain),
- Domain: Domain(cl.Domain),
- Title: cl.Title,
- Subtitle: cl.Subtitle,
- LogoSrc: cl.LogoSrc,
- LogoLink: cl.LogoLink,
- LogoAlt: cl.LogoAlt,
- LogoHeight: cl.LogoHeight,
- LogoWidth: cl.LogoWidth,
- ColorScheme: cl.ColorScheme,
- CreatedAt: time.Unix(cl.CreatedAt, 0),
- GHSource: null.NewValue(GHSource{}, false),
+ WorkspaceID: WorkspaceID(cl.WorkspaceID),
+ ID: ChangelogID(cl.ID),
+ Subdomain: Subdomain(cl.Subdomain),
+ Domain: Domain(cl.Domain),
+ Title: cl.Title,
+ Subtitle: cl.Subtitle,
+ LogoSrc: cl.LogoSrc,
+ LogoLink: cl.LogoLink,
+ LogoAlt: cl.LogoAlt,
+ LogoHeight: cl.LogoHeight,
+ LogoWidth: cl.LogoWidth,
+ ColorScheme: cl.ColorScheme,
+ HidePoweredBy: cl.HidePoweredBy == 1,
+ CreatedAt: time.Unix(cl.CreatedAt, 0),
+ GHSource: null.NewValue(GHSource{}, false),
}
if !source.ID.IsNull() && source.ID.IsValid() && !source.WorkspaceID.IsNull() && source.WorkspaceID.IsValid() {
@@ -77,18 +78,19 @@ type sqlite struct {
func (s *sqlite) CreateChangelog(ctx context.Context, cl Changelog) (Changelog, error) {
c, err := s.q.createChangelog(ctx, createChangelogParams{
- ID: cl.ID.String(),
- WorkspaceID: cl.WorkspaceID.String(),
- Subdomain: cl.Subdomain.String(),
- Domain: cl.Domain.NullString(),
- Title: cl.Title,
- Subtitle: cl.Subtitle,
- LogoSrc: cl.LogoSrc,
- LogoLink: cl.LogoLink,
- LogoAlt: cl.LogoAlt,
- LogoHeight: cl.LogoHeight,
- LogoWidth: cl.LogoWidth,
- ColorScheme: cl.ColorScheme,
+ ID: cl.ID.String(),
+ WorkspaceID: cl.WorkspaceID.String(),
+ Subdomain: cl.Subdomain.String(),
+ Domain: cl.Domain.NullString(),
+ Title: cl.Title,
+ Subtitle: cl.Subtitle,
+ LogoSrc: cl.LogoSrc,
+ LogoLink: cl.LogoLink,
+ LogoAlt: cl.LogoAlt,
+ LogoHeight: cl.LogoHeight,
+ LogoWidth: cl.LogoWidth,
+ ColorScheme: cl.ColorScheme,
+ HidePoweredBy: boolToInt(cl.HidePoweredBy),
})
if err != nil {
return Changelog{}, formatUnqueConstraint(err)
@@ -146,12 +148,33 @@ func (s *sqlite) ListChangelogs(ctx context.Context, wID WorkspaceID) ([]Changel
return res, nil
}
+// dereferences b to it's int representation
+func saveDerefToInt(b *bool) int64 {
+ if b != nil && *b {
+ return 1
+ }
+ return 0
+}
+
+// Returns 1 if b is true, otherwise 2
+func boolToInt(b bool) int64 {
+ var i int64
+ if b {
+ i = 1
+ }
+ return i
+}
+
func (s *sqlite) UpdateChangelog(ctx context.Context, wID WorkspaceID, cID ChangelogID, args UpdateChangelogArgs) (Changelog, error) {
// does not update string fields if they are zero value
c, err := s.q.updateChangelog(ctx, updateChangelogParams{
- ID: cID.String(),
- WorkspaceID: wID.String(),
- Subdomain: args.Subdomain,
+ ID: cID.String(),
+ WorkspaceID: wID.String(),
+ Subdomain: args.Subdomain,
+ HidePoweredBy: sql.NullInt64{ // update if value != nil
+ Int64: saveDerefToInt(args.HidePoweredBy),
+ Valid: args.HidePoweredBy != nil,
+ },
ColorScheme: args.ColorScheme,
SetColorScheme: int(args.ColorScheme) != 0,
Title: args.Title,
diff --git a/internal/store/store.go b/internal/store/store.go
index 0d19e20..ca5a148 100644
--- a/internal/store/store.go
+++ b/internal/store/store.go
@@ -11,21 +11,22 @@ import (
)
type Changelog struct {
- WorkspaceID WorkspaceID
- ID ChangelogID
- Subdomain Subdomain
- Domain Domain
- Title apitypes.NullString
- Subtitle apitypes.NullString
- LogoSrc apitypes.NullString
- LogoLink apitypes.NullString
- LogoAlt apitypes.NullString
- LogoHeight apitypes.NullString
- LogoWidth apitypes.NullString
- ColorScheme ColorScheme
- CreatedAt time.Time
- GHSource null.Value[GHSource]
- LocalSource null.Value[LocalSource]
+ WorkspaceID WorkspaceID
+ ID ChangelogID
+ Subdomain Subdomain
+ Domain Domain
+ Title apitypes.NullString
+ Subtitle apitypes.NullString
+ LogoSrc apitypes.NullString
+ LogoLink apitypes.NullString
+ LogoAlt apitypes.NullString
+ LogoHeight apitypes.NullString
+ LogoWidth apitypes.NullString
+ ColorScheme ColorScheme
+ HidePoweredBy bool
+ CreatedAt time.Time
+ GHSource null.Value[GHSource]
+ LocalSource null.Value[LocalSource]
}
type Workspace struct {
@@ -48,16 +49,17 @@ type LocalSource struct {
}
type UpdateChangelogArgs struct {
- Title apitypes.NullString
- Subdomain apitypes.NullString
- Domain Domain
- Subtitle apitypes.NullString
- LogoSrc apitypes.NullString
- LogoLink apitypes.NullString
- LogoAlt apitypes.NullString
- LogoHeight apitypes.NullString
- LogoWidth apitypes.NullString
- ColorScheme ColorScheme
+ Title apitypes.NullString
+ Subdomain apitypes.NullString
+ Domain Domain
+ Subtitle apitypes.NullString
+ LogoSrc apitypes.NullString
+ LogoLink apitypes.NullString
+ LogoAlt apitypes.NullString
+ LogoHeight apitypes.NullString
+ LogoWidth apitypes.NullString
+ ColorScheme ColorScheme
+ HidePoweredBy *bool
}
type Store interface {
diff --git a/migrations/20240919193315_changelog_hide_powered_by.sql b/migrations/20240919193315_changelog_hide_powered_by.sql
new file mode 100644
index 0000000..816028e
--- /dev/null
+++ b/migrations/20240919193315_changelog_hide_powered_by.sql
@@ -0,0 +1,9 @@
+-- +goose Up
+-- +goose StatementBegin
+ALTER TABLE changelogs ADD hide_powered_by INTEGER NOT NULL DEFAULT 0 check (hide_powered_by in (0, 1));
+-- +goose StatementEnd
+
+-- +goose Down
+-- +goose StatementBegin
+ALTER TABLE changelogs DROP hide_powered_by;
+-- +goose StatementEnd
diff --git a/openchangelog.example.yml b/openchangelog.example.yml
index 18eccc2..ce18a99 100644
--- a/openchangelog.example.yml
+++ b/openchangelog.example.yml
@@ -15,6 +15,7 @@ page:
title: Changelog
subtitle: The latest product updates from Openchangelog
colorScheme: system
+ hidePoweredBy: false
logo:
src: https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png
width: 70px
diff --git a/render/renderer.go b/render/renderer.go
index 5cb4ca2..1304633 100644
--- a/render/renderer.go
+++ b/render/renderer.go
@@ -104,6 +104,9 @@ func (r *renderer) RenderIndex(ctx context.Context, w io.Writer, args RenderInde
Articles: articles,
NextPageURL: nextPageURL,
},
+ FooterArgs: components.FooterArgs{
+ HidePoweredBy: args.CL.HidePoweredBy,
+ },
}).Render(ctx, w)
}