summaryrefslogtreecommitdiff
path: root/website.templ
diff options
context:
space:
mode:
Diffstat (limited to 'website.templ')
-rw-r--r--website.templ396
1 files changed, 363 insertions, 33 deletions
diff --git a/website.templ b/website.templ
index 88b8c40..bec1453 100644
--- a/website.templ
+++ b/website.templ
@@ -1,5 +1,7 @@
package main
+import "flag"
+
templ HeadComponent(title string, description string) {
<head>
<meta charset="UTF-8"/>
@@ -28,8 +30,16 @@ templ HeadComponent(title string, description string) {
</head>
}
+func Choose(chooseA bool, a string, b string) string {
+ if chooseA {
+ return a
+ } else {
+ return b
+ }
+}
+
templ BlogItem(header string, blog Blog, extra string) {
- @TerminalBorder(header, blog.Date.Format("January 2, 2006"), "bg-black/20 hover:bg-white/5 transition-colors duration-150 "+extra) {
+ @TerminalBorderForBlog(header, blog.Date.Format("January 2, 2006"), Choose(header == "", "bg-black/20 hover:bg-white/5 transition-colors duration-150", "")+" "+extra, header == "") {
<span class="cursor-pointer group block">
<a href={ templ.SafeURL("/blogs/" + blog.Slug) } class="no-underline hover:no-underline">
<h1 class="text-[130%] font-bold text-(--accent) group-hover:underline">
@@ -59,17 +69,31 @@ templ TerminalStack(joined bool, extra string) {
</div>
}
+templ TerminalBorderForBlog(header string, footer string, extra string, enable bool) {
+ if enable {
+ <div class={ "relative flex px-3.5 py-(--ypad) pt-[calc(var(--ypad)+0.0625rem)] [--ypad:var(--border-py,0.875rem)] border-[0.1rem] border-solid border-[color:var(--alt)]", extra }>
+ <span class="absolute px-[0.625rem] text-[1rem] left-[0.625rem] top-[-0.75rem] bg-[var(--text)] text-[color:var(--alt)]">{ header }</span>
+ <span class="absolute px-[0.625rem] text-[0.6rem] left-[0.625rem] bottom-[-0.55rem] bg-[var(--background)] border-[0.05rem] text-(--alt)">{ footer }</span>
+ { children... }
+ </div>
+ } else {
+ @TerminalBorder(header, footer, extra) {
+ { children... }
+ }
+ }
+}
+
templ TerminalBorder(header string, footer string, extra string) {
- <div class={ "relative flex px-3.5 py-(--ypad) pt-[calc(var(--ypad)+0.0625rem)] [--ypad:var(--border-py,0.875rem)] border-[0.1rem] border-solid border-[color:var(--alt)]", extra }>
- <span class="absolute px-[0.625rem] text-[1rem] left-[0.625rem] top-[-0.75rem] text-[color:var(--alt)] bg-[linear-gradient(to_bottom,var(--background),var(--cmp-bg,transparent))]">{ header }</span>
- <span class="absolute px-[0.625rem] text-[1rem] left-[0.625rem] bottom-[-0.75rem] text-[color:var(--alt)] bg-[linear-gradient(to_bottom,#181825,var(--background))]">{ footer }</span>
- { children... }
- </div>
// <div class={ "relative flex px-3.5 py-(--ypad) pt-[calc(var(--ypad)+0.0625rem)] [--ypad:var(--border-py,0.875rem)] border-[0.1rem] border-solid border-[color:var(--alt)]", extra }>
- // <span class="bg-transparent absolute px-[0.625rem] text-[1rem] left-[0.625rem] top-[-0.75rem] bg-[var(--background)] text-[color:var(--alt)]">{ header }</span>
- // <span class="bg-transparent absolute px-[0.625rem] text-[1rem] left-[0.625rem] bottom-[-0.75rem] bg-[var(--background)] text-[color:var(--alt)]">{ footer }</span>
+ // <span class="absolute px-[0.625rem] text-[1rem] left-[0.625rem] top-[-0.75rem] text-[color:var(--alt)] bg-[linear-gradient(to_bottom,var(--background),var(--cmp-bg,transparent))]">{ header }</span>
+ // <span class="absolute px-[0.625rem] text-[1rem] left-[0.625rem] bottom-[-0.75rem] text-[color:var(--alt)] bg-[linear-gradient(to_bottom,#181825,var(--background))]">{ footer }</span>
// { children... }
// </div>
+ <div class={ "relative flex px-3.5 py-(--ypad) pt-[calc(var(--ypad)+0.0625rem)] [--ypad:var(--border-py,0.875rem)] border-[0.1rem] border-solid border-(--alt)", extra }>
+ <span class="absolute px-[0.625rem] text-[1rem] left-[0.625rem] top-[-0.75rem] bg-[var(--background)] text-[color:var(--alt)]">{ header }</span>
+ <span class="absolute px-[0.625rem] text-[1rem] left-[0.625rem] bottom-[-0.75rem] bg-[var(--background)] text-[color:var(--alt)]">{ footer }</span>
+ { children... }
+ </div>
}
templ CopyIcon() {
@@ -240,17 +264,15 @@ templ SkillsPage(style Style) {
}
type Project struct {
- Slug string // e.g. "my-game"
- Title string // e.g. "MyGame"
- Category string // e.g. "Game written in Zig"
- Desc string // 1-2 line description/pitch
- Tags []ProjectTag // ["Zig", "OpenGL", "Linux"]
- Status string
- Icon templ.Component
- CgitURL string // e.g. "https://cgit.yourdomain.com/my-game"
- GithubURL string // Fallback mirror link
- IsFlagship bool
- IsPinned bool
+ Slug string // e.g. "my-game"
+ Title string // e.g. "MyGame"
+ Category string // e.g. "Game written in Zig"
+ Desc string // 1-2 line description/pitch
+ Tags []ProjectTag // ["Zig", "OpenGL", "Linux"]
+ Status string
+ Icon templ.Component
+ CgitURL string // e.g. "https://cgit.yourdomain.com/my-game"
+ GithubURL string // Fallback mirror link
}
type ProjectTag struct {
@@ -258,18 +280,37 @@ type ProjectTag struct {
Color string
}
-type ProjectFLink struct {
+type ProjectLink struct {
URL string
Icon templ.Component
}
+type FlagshipInfo struct {
+ Downloads []Download
+ Version string
+ Stats []Stat
+ Snippet string
+}
+
+type Download struct {
+ Label string // "Linux", "Windows"
+ URL string
+ Size string // "42 MB"
+}
+
+type Stat struct {
+ Label string
+ Value string
+}
+
var p Project = Project{
Slug: "krypton",
Title: "Krypton",
Category: "Programming Language Compiler",
Desc: "A modern Minecraft creator event. As a developer, I helped with minor improvements to the cosmetics system. ",
Icon: IconCpu("text-[#F5A670] self-center"),
- Status: "ON",
+ // Icon: IconKrypton(),
+ Status: "ON",
Tags: []ProjectTag{
// {"Programming Language", Color("--extra")},
// {"Compiler", Color("--extra")},
@@ -277,13 +318,297 @@ var p Project = Project{
{"LLVM", Color("text-[#FFFFFF]")},
// {"Java", Color("#F5A670")},
},
- CgitURL: "https://whatever",
- GithubURL: "",
- IsFlagship: true,
- IsPinned: false,
+ CgitURL: "https://whatever",
+ GithubURL: "",
+}
+
+var flagship FlagshipInfo = FlagshipInfo{
+ Version: "Sprout.0 2026-08-13",
+ Downloads: []Download{
+ {"linux-amd64", "https://foobar", "23 MB"},
+ // {"linux-arm64", "https://foobar", "52 MB"},
+ // {"macos-arm64", "https://fooshit", "47 MB"},
+ {"windows-amd64", "https://fooshit", "65.7 MB"},
+ },
+ // Stats: []Stat{{"lines of code", "18.7k"}},
+ Snippet: `
+io :: import "core/io";
+
+main :: proc() {
+ io.printf("Hello, %s", "world");
+}
+`,
+}
+
+var versionBeforeDownloads = false
+
+const flagshipClasses = "[--border-py:1.25rem] border-(--accent)! bg-white/[0.03] shadow-[0_0_1.5rem_color-mix(in_srgb,var(--accent)_25%,transparent)]"
+
+templ FlagshipProject(project Project, extra string) {
+ @TerminalBorder("", "", flagshipClasses+" "+extra) {
+ <div class="flex gap-8 w-full">
+ <div class="flex flex-col gap-4 flex-1 min-w-0">
+ <div class="flex flex-wrap items-baseline gap-x-[1ch] gap-y-[0.4rem]">
+ @project.Icon
+ <a href={ templ.SafeURL("/projects/" + project.Slug) } class="text-[170%] font-bold text-(--accent) hover:underline">{ project.Title }</a>
+ <span class="text-[85%] text-(--primary)">{ project.Category }</span>
+ for _, tag := range project.Tags {
+ <code class={ "text-[75%] px-[0.4rem] inline-block rounded-[0.3rem] border-[0.01rem] bg-(--alt)/25" + " " + tag.Color }>{ tag.Name }</code>
+ }
+ <span class="ml-auto flex items-center self-center">
+ @IconLink("https://git.example.com/foo", "git", "") {
+ @IconGit("text-(--primary)")
+ }
+ @IconLink("https://github.com/foo", "github", "") {
+ @IconGithub("text-(--secondary)")
+ }
+ @IconLink("https://example.com", "website", "") {
+ @IconExternal("text-(--accent)")
+ }
+ </span>
+ </div>
+ <p class="leading-relaxed max-w-3xl">{ project.Desc }</p>
+ if len(flagship.Downloads) > 0 || flagship.Version != "" {
+ <div class="flex flex-wrap items-center gap-x-4 gap-y-2">
+ if versionBeforeDownloads {
+ @VersionTag(project)
+ }
+ for _, d := range flagship.Downloads {
+ @DownloadButton(d)
+ }
+ if !versionBeforeDownloads {
+ @VersionTag(project)
+ }
+ </div>
+ }
+ if len(flagship.Stats) > 0 {
+ <div class="flex flex-wrap gap-x-[2rem] gap-y-[0.4rem] text-[85%]">
+ for _, stat := range flagship.Stats {
+ <span class="flex gap-[1ch]">
+ <span class="font-bold text-(--primary)">{ stat.Value }</span>
+ <span class="text-(--alt)">{ stat.Label }</span>
+ </span>
+ }
+ </div>
+ }
+ </div>
+ if flagship.Snippet != "" {
+ <div class="shrink-0 self-start flex flex-col gap-[0.5rem] p-[1rem] rounded-[0.4rem] bg-black/30">
+ <span class="text-[75%] text-(--alt)">example</span>
+ @CopyPre(flagship.Snippet, "text-[80%] leading-[normal]") {
+ { flagship.Snippet }
+ }
+ </div>
+ }
+ </div>
+ }
+}
+
+templ VersionTag(project Project) {
+ if flagship.Version != "" {
+ <span class="flex items-baseline gap-[1ch] text-[85%]">
+ <code class="text-[#46d46c]">{ flagship.Version }</code>
+ // <a href={ templ.SafeURL("/projects/" + project.Slug + "#changelog") } class="text-(--alt) hover:underline">changelog</a>
+ </span>
+ }
+}
+
+templ DownloadButton(d Download) {
+ <a href={ templ.SafeURL(d.URL) } class="no-underline inline-flex items-center gap-[1ch] px-[0.6rem] py-[0.1rem] rounded-[0.4rem] border-[0.1rem] border-solid border-(--secondary)/60 text-[85%] text-(--secondary) transition-colors hover:bg-(--secondary)/15">
+ @IconArchive("text-(--secondary)")
+ <span>{ d.Label }</span>
+ if d.Size != "" {
+ <span class="text-(--alt)">{ d.Size }</span>
+ }
+ </a>
+}
+
+templ IconArchive(color string) {
+ @Icon(color) {
+ <rect width="20" height="5" x="2" y="3" rx="1"></rect>
+ <path d="M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8"></path>
+ <path d="M10 12h4"></path>
+ }
+}
+
+const flagshipClassesV4 = "[--border-py:1.25rem] border-(--accent)! bg-white/[0.03] shadow-[0_0_1.5rem_color-mix(in_srgb,var(--accent)_25%,transparent)]"
+
+templ FlagshipProjectV4(project Project, extra string) {
+ @TerminalBorder("", "", flagshipClasses+" "+extra) {
+ <div class="flex gap-[2rem] w-full">
+ <div class="flex flex-col gap-[1rem] flex-1 min-w-0">
+ <div class="flex flex-wrap items-baseline gap-x-[1ch] gap-y-[0.4rem]">
+ @project.Icon
+ <a href={ templ.SafeURL("/projects/" + project.Slug) } class="text-[170%] font-bold text-(--accent) hover:underline">{ project.Title }</a>
+ <span class="text-[85%] text-(--primary)">{ project.Category }</span>
+ for _, tag := range project.Tags {
+ <code class={ "text-[75%] px-[0.4rem] inline-block rounded-[0.3rem] border-[0.01rem] bg-(--alt)/25" + " " + tag.Color }>{ tag.Name }</code>
+ }
+ <span class="ml-auto flex items-center self-center">
+ @IconLink("https://git.example.com/foo", "git", "") {
+ @IconGit("text-(--primary)")
+ }
+ @IconLink("https://github.com/foo", "github", "") {
+ @IconGithub("text-(--secondary)")
+ }
+ @IconLink("https://example.com", "website", "") {
+ @IconExternal("text-(--accent)")
+ }
+ </span>
+ </div>
+ <p class="leading-relaxed max-w-3xl">{ project.Desc }</p>
+ if len(project.Downloads) > 0 || project.Version != "" {
+ <div class="flex flex-wrap items-center gap-x-[1rem] gap-y-[0.5rem]">
+ for _, d := range project.Downloads {
+ @DownloadButton(d)
+ }
+ if project.Version != "" {
+ <code class="text-[85%] text-(--alt)">{ project.Version }</code>
+ }
+ </div>
+ }
+ if len(project.Stats) > 0 {
+ <div class="flex flex-wrap gap-x-[2rem] gap-y-[0.4rem] text-[85%]">
+ for _, stat := range project.Stats {
+ <span class="flex gap-[1ch]">
+ <span class="font-bold text-(--primary)">{ stat.Value }</span>
+ <span class="text-(--alt)">{ stat.Label }</span>
+ </span>
+ }
+ </div>
+ }
+ </div>
+ if project.Snippet != "" {
+ <div class="shrink-0 self-start flex flex-col gap-[0.5rem] p-[1rem] rounded-[0.4rem] bg-black/30">
+ <span class="text-[75%] text-(--alt)">example</span>
+ @CopyPre(project.Snippet, "text-[80%] leading-[normal]") {
+ { project.Snippet }
+ }
+ </div>
+ }
+ </div>
+ }
}
-templ FlagshipProject(project Project) {
+templ DownloadButtonV4(d Download) {
+ <a href={ templ.SafeURL(d.URL) } class="inline-flex items-center gap-[1ch] px-[0.8rem] py-[0.3rem] rounded-[0.4rem] border-[0.1rem] border-solid border-(--alt) text-(--primary) transition-colors hover:bg-(--alt)/25">
+ @IconDownload("text-(--primary)")
+ { d.Label }
+ </a>
+}
+
+templ IconDownload(color string) {
+ @Icon(color) {
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
+ <polyline points="7 10 12 15 17 10"></polyline>
+ <line x1="12" x2="12" y1="15" y2="3"></line>
+ }
+}
+
+const flagshipClassesV3 = "[--border-py:1.25rem] border-(--primary)! bg-white/[0.03] shadow-[0_0_1.5rem_color-mix(in_srgb,var(--primary)_25%,transparent)]"
+
+templ FlagshipProjectV3(project Project, extra string) {
+ @TerminalBorder("", "", flagshipClasses+" "+extra) {
+ <div class="flex gap-[2rem] w-full">
+ <div class="flex flex-col gap-[1rem] flex-1 min-w-0">
+ <div class="flex flex-wrap items-baseline gap-x-[1ch] gap-y-[0.4rem]">
+ @project.Icon
+ <a href={ templ.SafeURL("/projects/" + project.Slug) } class="text-[170%] font-bold text-(--accent) hover:underline">{ project.Title }</a>
+ <code class="px-[0.5rem] rounded-[0.3rem] border-[0.1rem] border-(--accent)/50 text-[85%] text-(--accent)">{ project.Version }</code>
+ <span class="text-[85%] text-(--primary)">{ project.Category }</span>
+ for _, tag := range project.Tags {
+ <code class={ "text-[75%] px-[0.4rem] inline-block rounded-[0.3rem] border-[0.01rem] bg-(--alt)/25" + " " + tag.Color }>{ tag.Name }</code>
+ }
+ <span class="ml-auto flex items-center self-center">
+ @IconLink("https://git.example.com/foo", "git", "") {
+ @IconGit("text-(--primary)")
+ }
+ @IconLink("https://github.com/foo", "github", "") {
+ @IconGithub("text-(--secondary)")
+ }
+ @IconLink("https://example.com", "website", "") {
+ @IconExternal("text-(--accent)")
+ }
+ </span>
+ </div>
+ <p class="leading-relaxed max-w-3xl">{ project.Desc }</p>
+ if project.Install != "" {
+ @CopyPre(project.Install, "text-[85%] leading-[normal]") {
+ { "$ " + project.Install }
+ }
+ }
+ if project.Devlog != nil {
+ <a href={ templ.SafeURL("/blogs/" + project.Devlog.Slug) } class="text-[85%] text-(--secondary) hover:underline">
+ { "latest devlog: " + project.Devlog.Title }
+ </a>
+ }
+ </div>
+ if project.Snippet != "" {
+ <div class="shrink-0 self-start flex flex-col gap-[0.5rem] p-[1rem] rounded-[0.4rem] bg-black/30">
+ <span class="text-[75%] text-(--alt)">example</span>
+ @CopyPre(project.Snippet, "text-[80%] leading-[normal]") {
+ { project.Snippet }
+ }
+ </div>
+ }
+ </div>
+ }
+}
+
+templ FlagshipProjectV2(project Project, extra string) {
+ @TerminalBorder(project.Version, "", flagshipClasses+" "+extra) {
+ <div class="flex gap-[2rem] w-full">
+ <div class="flex flex-col gap-[1rem] flex-1 min-w-0">
+ <div class="flex flex-wrap items-baseline gap-x-[1ch] gap-y-[0.4rem]">
+ @project.Icon
+ <a href={ templ.SafeURL("/projects/" + project.Slug) } class="text-[170%] font-bold text-(--primary) hover:underline">{ project.Title }</a>
+ <span class="text-[85%] text-(--secondary)">{ project.Category }</span>
+ for _, tag := range project.Tags {
+ <code class={ "text-[75%] px-[0.4rem] inline-block rounded-[0.3rem] border-[0.01rem] bg-(--alt)/25" + " " + tag.Color }>{ tag.Name }</code>
+ }
+ <span class="ml-auto flex items-center self-center">
+ @IconLink("https://git.example.com/foo", "git", "") {
+ @IconGit("text-(--primary)")
+ }
+ @IconLink("https://github.com/foo", "github", "") {
+ @IconGithub("text-(--secondary)")
+ }
+ @IconLink("https://example.com", "website", "") {
+ @IconExternal("text-(--accent)")
+ }
+ </span>
+ </div>
+ <p class="leading-relaxed max-w-3xl">{ project.Desc }</p>
+ <div class="flex flex-wrap items-center gap-[0.5ch] pt-[1rem] border-t border-white/10 text-[85%]">
+ for i, stage := range project.Pipeline {
+ if i > 0 {
+ <span class="text-(--alt)">→</span>
+ }
+ <code class="px-[0.4rem] rounded-[0.3rem] bg-(--alt)/25 text-(--accent)">{ stage }</code>
+ }
+ </div>
+ <div class="flex flex-wrap gap-x-[2.5rem] gap-y-[0.75rem]">
+ for _, stat := range project.Stats {
+ <div class="flex flex-col">
+ <span class="text-[150%] font-bold text-(--primary)">{ stat.Value }</span>
+ <span class="text-[75%] text-(--alt)">{ stat.Label }</span>
+ </div>
+ }
+ </div>
+ </div>
+ if project.Snippet != "" {
+ <div class="shrink-0 self-start flex flex-col gap-[0.5rem] p-[1rem] rounded-[0.4rem] bg-black/30">
+ <span class="text-[75%] text-(--alt)">example</span>
+ @CopyPre(project.Snippet, "text-[80%] leading-[normal]") {
+ { project.Snippet }
+ }
+ </div>
+ }
+ </div>
+ }
+}
+
+templ FlagshipProjectV1(project Project) {
<div class="relative border border-[var(--primary)]/40 rounded bg-white/[0.03] p-6 mb-10 shadow-[0_0_15px_rgba(0,0,0,0.3)]">
<!-- Header Bar -->
<div class="flex items-center justify-between pb-3 mb-4 border-b border-white/10 font-mono text-xs">
@@ -401,6 +726,13 @@ templ IconExternal(color string) {
}
}
+templ IconKrypton() {
+ @Icon("text-[#00f1ff]") {
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-circle-dot preview-icon"><circle cx="12" cy="12" r="1"></circle><circle cx="12" cy="12" r="10"></circle></svg>
+ }
+ // { "\uf192" }
+}
+
templ ProjectItem(project Project, extra string) {
<div>
@TerminalBorder("", "", "[--border-py:0.25rem] py-2 text-[80%] bg-black/20 hover:bg-white/5 transition-colors duration-150"+" "+extra) {
@@ -438,17 +770,15 @@ func DoubleProject(project Project) Project {
return project
}
-templ ProjectsPage(style Style, projects []Project) {
+templ ProjectsPage(style Style, projects []Project, pinned int) {
@TerminalLayout(style, "/home/kyren/projects") {
- @FlagshipProject(p)
- // @PinnedGrid(projects)
- // All projects
+ @FlagshipProject(projects[0], "mb-[1.5rem]")
@ScrollBox("") {
@TerminalStack(false, "mt-[0.5rem]") {
for i := 0; i < 1; i++ {
- for i, project := range projects {
- if i % 2 == 0 {
- @ProjectItem(DoubleProject(project), "my-[-0.15rem]")
+ for i, project := range projects[1:] {
+ if i < pinned {
+ @ProjectItem(project, "my-[-0.15rem] border-(--text)")
} else {
@ProjectItem(project, "my-[-0.15rem]")
}