Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 19 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,27 @@ embedded browser, no C++ toolchain to learn.
```go
package main

import g "github.com/nv404/gova"

type Counter struct{}

func (Counter) Body(s *g.Scope) g.View {
count := g.State(s, 0)
return g.VStack(
g.Text(count.Format("Count: %d")).Font(g.Title),
g.HStack(
g.Button("-", func() { count.Set(count.Get() - 1) }),
g.Button("+", func() { count.Set(count.Get() + 1) }),
).Spacing(g.SpaceMD),
).Padding(g.SpaceLG)
}

func main() {
g.Run("Counter", g.Component(Counter{}))
}
import . "github.com/nv404/gova"

var Counter = Define(func(s *Scope) View {
count := State(s, 0)
return VStack(
Text(count.Format("Count: %d")),
Button("+", func() { count.Update(func(n int) int { return n + 1 }) }),
Button("-", func() { count.Update(func(n int) int { return n - 1 }) }),
)
})

func main() { Run("Counter", Counter) }
```

<img width="505" height="293" alt="Screenshot 2026-04-24 at 2 44 59 PM" src="https://github.com/user-attachments/assets/9e37552b-7689-4be5-8879-b933578c3565" />

<p align="center">
<img
src="docs-site/public/screenshots/counter-example.png"
alt="Counter example window on macOS"
width="640"
/>
</p>

## Why Gova

Expand Down
135 changes: 134 additions & 1 deletion docs-site/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default function HomePage() {
<main style={{ position: 'relative', zIndex: 2 }}>
<Hero />
<Metrics />
<Showcase />
<Features />
<Platforms />
<Toolchain />
Expand Down Expand Up @@ -226,7 +227,7 @@ function HeroCode() {
{' '}<Kw>return</Kw> <Fn>VStack</Fn>(
</>,
<>
{' '}<Fn>Text</Fn>(count.<Fn>Format</Fn>(<Str>&quot;Count: %d&quot;</Str>)).<Fn>Font</Fn>(<Ty>Title</Ty>),
{' '}<Fn>Text</Fn>(count.<Fn>Format</Fn>(<Str>&quot;Count: %d&quot;</Str>)),
</>,
<>
{' '}<Fn>Button</Fn>(<Str>&quot;+&quot;</Str>, <Kw>func</Kw>() {'{'} count.<Fn>Update</Fn>(<Kw>func</Kw>(n <Ty>int</Ty>) <Ty>int</Ty> {'{'} <Kw>return</Kw> n + <Nm>1</Nm> {'}'}) {'}'}),
Expand Down Expand Up @@ -338,6 +339,138 @@ function Metrics() {
);
}

/* ---------- Showcase ---------- */

function Showcase() {
const apps: Array<{
name: string;
src: string;
href: string;
}> = [
{
name: 'counter',
src: '/screenshots/counter-example.png',
href: 'https://github.com/nv404/gova/tree/main/examples/counter',
},
{
name: 'todo',
src: '/screenshots/todo-example.png',
href: 'https://github.com/nv404/gova/tree/main/examples/todo',
},
{
name: 'fancytodo',
src: '/screenshots/fancytodo-example.png',
href: 'https://github.com/nv404/gova/tree/main/examples/fancytodo',
},
];
return (
<Section title="A few examples." width={1200}>
<p style={sectionSub}>
Each one is a single Go file in{' '}
<span style={monoInline}>./examples</span>. Click through to read the
source.
</p>

<div
className="gova-showcase-grid"
style={{
marginTop: '2.5rem',
display: 'grid',
gridTemplateColumns: 'repeat(3, minmax(0, 1fr))',
gap: '1.25rem',
}}
>
{apps.map((a) => (
<Link
key={a.name}
href={a.href}
target="_blank"
rel="noreferrer"
className="gova-showcase-card gova-reveal"
style={{
display: 'flex',
flexDirection: 'column',
gap: '1rem',
padding: '1.25rem 1.25rem 1.4rem',
borderRadius: 14,
border: '1px solid var(--gova-line)',
background:
'linear-gradient(180deg, var(--gova-surface) 0%, var(--gova-ink-2) 100%)',
textDecoration: 'none',
color: 'inherit',
transition:
'border-color 200ms ease, transform 200ms ease, box-shadow 200ms ease',
}}
>
<div
style={{
position: 'relative',
borderRadius: 10,
overflow: 'hidden',
background:
'radial-gradient(120% 100% at 50% 0%, rgba(247,244,229,0.06) 0%, rgba(0,0,0,0) 60%), var(--gova-ink)',
border: '1px solid var(--gova-line)',
aspectRatio: '16 / 11',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: '1.4rem',
}}
>
<img
src={a.src}
alt={`${a.name} example running on macOS`}
loading="lazy"
style={{
maxWidth: '100%',
maxHeight: '100%',
width: 'auto',
height: 'auto',
display: 'block',
filter: 'drop-shadow(0 18px 30px rgba(0,0,0,0.55))',
}}
/>
</div>
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
gap: 10,
}}
>
<h3
style={{
margin: 0,
fontFamily: 'var(--font-mono)',
fontWeight: 500,
fontSize: '0.95rem',
letterSpacing: '-0.005em',
color: 'var(--gova-cream)',
}}
>
{a.name}
</h3>
<span
style={{
display: 'inline-flex',
alignItems: 'center',
gap: 6,
fontFamily: 'var(--font-mono)',
fontSize: '0.72rem',
color: 'var(--gova-cream-faint)',
}}
>
source <Arrow />
</span>
</div>
</Link>
))}
</div>
</Section>
);
}

/* ---------- Features ---------- */

function Features() {
Expand Down
15 changes: 15 additions & 0 deletions docs-site/app/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -281,13 +281,27 @@ body {
background: var(--gova-ink-2);
}

/* Showcase cards — image-led examples grid */
.gova-showcase-card:hover {
border-color: rgba(247, 244, 229, 0.28);
transform: translateY(-2px);
box-shadow: 0 22px 56px -22px rgba(0, 0, 0, 0.7);
}
.gova-showcase-card:hover img {
transform: scale(1.015);
}
.gova-showcase-card img {
transition: transform 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
}

/* Responsive tweaks */
@media (max-width: 960px) {
.gova-hero-grid { grid-template-columns: 1fr !important; }
.gova-value-grid { grid-template-columns: 1fr !important; }
.gova-features-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
.gova-metrics-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; gap: 1.5rem !important; }
.gova-quickstart-row { grid-template-columns: 1fr !important; gap: 1.1rem !important; }
.gova-showcase-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}
@media (max-width: 720px) {
/* Platform-support table: stack into one card per feature with
Expand Down Expand Up @@ -317,6 +331,7 @@ body {
@media (max-width: 600px) {
.gova-features-grid { grid-template-columns: 1fr !important; }
.gova-metrics-grid { grid-template-columns: 1fr !important; }
.gova-showcase-grid { grid-template-columns: 1fr !important; }
}

/* Fumadocs nav title size tweak */
Expand Down
45 changes: 45 additions & 0 deletions docs-site/content/docs/getting-started/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,50 @@ Save the file and run `go run .`. You should see a window with a title, an
input with an Add button, and a scrolling list of todos below. Try adding,
toggling, and deleting. Resize the window to confirm the input grows with it.

<figure style={{ margin: '1.75rem 0 0' }}>
<img
src="/screenshots/todo-example.png"
alt="The Todo example running on macOS, showing two items and an input field"
style={{
width: '100%',
maxWidth: 720,
borderRadius: 12,
border: '1px solid var(--gova-line)',
background: 'var(--gova-ink)',
display: 'block',
margin: '0 auto',
}}
/>
<figcaption style={{
marginTop: '0.6rem',
textAlign: 'center',
fontFamily: 'var(--font-mono)',
fontSize: '0.72rem',
letterSpacing: '0.05em',
color: 'var(--gova-cream-faint)',
}}>
The finished todo app, a single Go file, native window.
</figcaption>
</figure>

Want a richer take on the same idea: categories, filters, custom theme? See
[`examples/fancytodo`](https://github.com/nv404/gova/tree/main/examples/fancytodo).

<figure style={{ margin: '1.5rem 0 0' }}>
<img
src="/screenshots/fancytodo-example.png"
alt="The fancytodo example with categorized items and filter chips"
style={{
width: '100%',
maxWidth: 720,
borderRadius: 12,
border: '1px solid var(--gova-line)',
background: 'var(--gova-ink)',
display: 'block',
margin: '0 auto',
}}
/>
</figure>

Once this is working, continue with [Core concepts](/docs/concepts) to learn
what `View`, `Viewable`, and `Scope` mean precisely.
46 changes: 33 additions & 13 deletions docs-site/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,44 @@ package main

import . "github.com/nv404/gova"

type Counter struct{}

func (Counter) Body(s *Scope) View {
var Counter = Define(func(s *Scope) View {
count := State(s, 0)

return VStack(
Text(count.Format("count: %d")).Font(Title),
Button("Increment", func() {
count.Update(func(n int) int { return n + 1 })
}),
).Spacing(SpaceMD).Padding(SpaceLG)
}
Text(count.Format("Count: %d")),
Button("+", func() { count.Update(func(n int) int { return n + 1 }) }),
Button("-", func() { count.Update(func(n int) int { return n - 1 }) }),
)
})

func main() {
Run("Counter", Component(Counter{}))
}
func main() { Run("Counter", Counter) }
```

<figure style={{ margin: '1.75rem 0 0' }}>
<img
src="/screenshots/counter-example.png"
alt="The counter example running as a native window on macOS"
style={{
width: '100%',
maxWidth: 720,
borderRadius: 12,
border: '1px solid var(--gova-line)',
background: 'var(--gova-ink)',
display: 'block',
margin: '0 auto',
}}
/>
<figcaption style={{
marginTop: '0.6rem',
textAlign: 'center',
fontFamily: 'var(--font-mono)',
fontSize: '0.72rem',
letterSpacing: '0.05em',
color: 'var(--gova-cream-faint)',
}}>
The program above, running on macOS.
</figcaption>
</figure>

The rest of the documentation walks through every concept and every exported
identifier. Start with [Getting started](/docs/getting-started/installation) if
you are new.
Expand Down
Binary file added docs-site/public/screenshots/counter-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs-site/public/screenshots/todo-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 1 addition & 3 deletions examples/fancytodo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ var FancyTodo = g.Define(func(s *g.Scope) g.View {
g.TextField(input).
Placeholder("What needs to be done?").
OnSubmit(func(string) { add() }).
MinHeight(36).
Grow(),
addBtn,
).Spacing(g.SpaceSM)
Expand Down Expand Up @@ -293,7 +292,7 @@ func todoRow(t Todo, alpha float64, onToggle func(int, bool), onDelete func(int)
g.Text(string(t.Category)).Font(g.Caption).Color(g.Secondary),
).Spacing(g.SpaceXS)

body := g.VStack(title, meta).Spacing(g.SpaceXS).Align(g.Leading)
body := g.VStack(title, meta).Spacing(g.SpaceXS).Align(g.Leading).Grow()

deleteBtn := g.HStack(
g.Text("Delete").Font(g.Caption).Color(g.Secondary).Bold(),
Expand All @@ -307,7 +306,6 @@ func todoRow(t Todo, alpha float64, onToggle func(int, bool), onDelete func(int)
return g.HStack(
g.Toggle(t.Done).OnChange(func(done bool) { onToggle(t.ID, done) }),
body,
g.Spacer(),
deleteBtn,
).Spacing(g.SpaceSM).
PaddingH(g.SpaceMD).
Expand Down
Loading
Loading