summaryrefslogtreecommitdiff
path: root/website.templ
diff options
context:
space:
mode:
Diffstat (limited to 'website.templ')
-rw-r--r--website.templ352
1 files changed, 342 insertions, 10 deletions
diff --git a/website.templ b/website.templ
index face9f9..1f4f636 100644
--- a/website.templ
+++ b/website.templ
@@ -19,18 +19,97 @@ templ HeadComponent(title string, description string) {
<meta property="og:image" content="https://kyren.codes/image.png"/>
<meta property="og:image:alt" content="a cyan sphere with a dark background"/>
<meta property="og:site_name" content="Kyren's Website"/>
+ <script src="/public/copy.js" defer></script>
<script src="/public/theme.js" defer></script>
+ <script src="/public/scrollbar.js" defer></script>
+ <script src="/public/my_uptime.js" defer></script>
<link rel="stylesheet" href="/public/style.css"/>
{ children... }
</head>
}
+templ BlogItem(header string, blog Blog, extra string) {
+ @TerminalBorder(header, blog.Date.Format("January 2, 2006"), extra) {
+ <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">
+ { blog.Title }
+ </h1>
+ <p class="text-(--secondary)">{ blog.Desc }</p>
+ </a>
+ </span>
+ }
+}
+
+templ Link(href string, newTab bool) {
+ <a
+ href={ templ.SafeURL(href) }
+ if newTab {
+ target="_blank"
+ rel="noopener noreferrer"
+ }
+ >
+ { children... }
+ </a>
+}
+
+templ TerminalStack(joined bool, extra string) {
+ <div class={ "flex flex-col min-h-0", templ.KV("[&>*+*]:mt-[-0.1rem]", joined), templ.KV("gap-4", !joined), extra }>
+ { children... }
+ </div>
+}
+
+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] 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() {
+ <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-copy preview-icon"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path></svg>
+}
+
+templ TerminalBorderWithCopy(header string, footer string, extra string, text string, href string, showLabel bool) {
+ @TerminalBorder(header, footer, extra) {
+ <div data-copy-scope class="group/copy flex w-full items-center justify-between gap-4">
+ if href != "" {
+ <a href={ templ.SafeURL(href) } class="wrap-anywhere">
+ { children... }
+ </a>
+ } else {
+ <span data-copy={ text } class="cursor-pointer wrap-anywhere">
+ { children... }
+ </span>
+ }
+ <span class="relative shrink-0">
+ if showLabel {
+ <span class="hidden group-data-copied/copy:block absolute right-full top-1/2 -translate-y-1/2 mr-2 px-[0.4rem] whitespace-nowrap bg-(--background) text-(--primary)">copied</span>
+ }
+ <button type="button" data-copy={ text } aria-label="copy" class="block p-[0.4rem] rounded-[0.4rem] cursor-pointer transition-colors hover:bg-(--alt)/25 group-data-copied/copy:bg-(--primary)/25!">
+ @CopyIcon()
+ </button>
+ </span>
+ </div>
+ }
+}
+
+templ CopyPre(text string, preClass string) {
+ <button type="button" data-copy={ text } class="group relative shrink-0 cursor-pointer text-left rounded-[0.4rem] p-[0.4rem] -m-[0.4rem] transition-colors hover:bg-(--alt)/25 data-copied:bg-(--primary)/25! data-copied:animate-[bump_0.25s]">
+ <pre class={ preClass }>
+ { children... }
+ </pre>
+ <span class="hidden group-data-copied:block absolute right-[0.6rem] top-[0.6rem] px-[0.4rem] bg-(--background) text-(--primary) text-[0.8rem]">copied</span>
+ </button>
+}
+
templ NavLink(href string, label string) {
<a href={ templ.SafeURL(href) } class="text-(--primary) hover:text-(--accent)">{ label }</a>
}
-templ NavComponent(path string) {
- <nav class="flex justify-between gap-10 p-4 mb-[1.5625rem] border-2 border-(--alt) text-[1.375rem]">
+templ Nav(path string) {
+ <nav class="flex justify-between gap-10 p-4 mb-6 border-[0.125rem] border-(--alt) text-[1.375rem]">
<span>{ path }</span>
<span class="flex gap-[1ch]">
@NavLink("/", "home")
@@ -49,27 +128,109 @@ templ TerminalLayout(style Style, path string) {
<link rel="stylesheet" href="/public/styles/terminal.css"/>
}
<body>
- <main class="w-[75rem] h-[40rem] p-8 border-[0.2rem] border-(--text) overflow-hidden text-[1.125rem]">
- @NavComponent(path)
+ <main class="flex flex-col w-[75rem] h-[40rem] p-8 border-[0.2rem] border-(--text) overflow-hidden text-[1.125rem]">
+ @Nav(path)
{ children... }
</main>
</body>
</html>
}
-templ HomePage(style Style) {
+const fingerprint = `+--[ED25519 256]--+
+| +. .. +.B|
+| + o..o . BB|
+| ..o oo.o =+E|
+| ... oo. + o.|
+| . S . = |
+| . . + o |
+| o o o . |
+| oo .o+ + |
+| ++ooo+= |
++----[SHA256]-----+`
+const sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO7P9K9D5RkBk+JCRRS6AtHuTAc6cRpXfRfRMg/Kyren"
+
+templ HomePage(style Style, latestBlog *Blog) {
@TerminalLayout(style, "/home/kyren/") {
- <div id="content" class="w-0 h-0 invisible sm:w-full sm:h-full sm:visible">
- <h1>Home</h1>
- <p>Go server running with Templ templates and Air hot-reloading.</p>
+ <div class={ "grid grid-cols-[29%_1fr] gap-x-8 flex-1 min-h-0", templ.KV("gap-y-4", !false) }>
+ <div class="flex flex-col min-h-0 [--border-py:0.75rem]">
+ @TerminalStack(true, "") {
+ @TerminalBorder("Profile", "", "[--border-py:0.875rem]") {
+ <div class="flex items-center gap-4 h-38">
+ <img src="/public/favicon.svg" alt="picture" class="h-full object-cover"/>
+ @CopyPre(sshKey, "shrink-0 text-[0.675rem] leading-[normal]") {
+ { fingerprint }
+ }
+ </div>
+ }
+ @TerminalBorderWithCopy("Email", "", "", "contact@kyren.codes", "mailto:contact@kyren.codes", false) {
+ contact@kyren.codes
+ }
+ @TerminalBorder("Git Repos (main)", "", "") {
+ @Link("https://git.kyren.codes", true) {
+ git.kyren.codes
+ }
+ }
+ @TerminalBorder("GitHub (secondary)", "", "") {
+ @Link("https://github.com/kyren223", true) {
+ github.com/Kyren223
+ }
+ }
+ @TerminalBorder("Discord", "", "") {
+ @Link("https://discord.com/users/481884415090229258", true) {
+ Kyren223
+ }
+ }
+ }
+ </div>
+ <div class="flex flex-col gap-10 min-h-0 select-text">
+ @TerminalBorder("Status", "", "") {
+ <div class="flex gap-[1ch] text-[1rem]">
+ <span>Working on</span>
+ <span>
+ @Link("/projects/krypton", false) {
+ Krypton
+ }
+ </span>
+ <span>|</span>
+ <span>Learning Langdev & Compiler Design</span>
+ <span>|</span>
+ <span>Available for hire</span>
+ </div>
+ }
+ @TerminalBorder("About Me", "", "") {
+ Hi! I'm Kyren, a softwarea engineer and game developer.
+ I love working with low level languages and learning things deeply.
+ I am also a terminal nerd and Linux enthusiast who uses NVIM btw.
+ And when I am not coding, I am most likely playing video games,
+ watching Anime, or solving Rubik's cubes fast.
+ }
+ @BlogItem("Latest Blog Post", *latestBlog, "")
+ </div>
+ @TerminalBorderWithCopy("SSH Key", "", footerClass(false), sshKey, "", true) {
+ { sshKey }
+ }
</div>
}
}
+func footerClass(connected bool) string {
+ style := "col-span-2 select-text [--border-py:0.5rem]"
+ if connected {
+ style += " mb-[0.30rem]"
+ }
+ return style
+}
+
templ SkillsPage(style Style) {
@TerminalLayout(style, "/home/kyren/skills.md") {
- <h1 class="text-3xl font-bold">About</h1>
- <p>Single-binary web app using Go's standard library net/http.</p>
+ @TerminalStack(false, "") {
+ @TerminalBorder("Setup", "", "") {
+ <span>
+ $ fastfetch
+ @Fastfetch(fetchRows)
+ </span>
+ }
+ }
}
}
@@ -86,3 +247,174 @@ templ ProjectsPage(style Style, projects []Project) {
</div>
}
}
+
+templ NotFoundPage(style Style, path string) {
+ @TerminalLayout(style, "404") {
+ @TerminalStack(true, "") {
+ @TerminalBorder("Shell", "", "") {
+ <span>
+ <p>$ cd ~{ path }</p>
+ <p class="pt-3">"{ path[1:] }": No such file or directory (os error 2) </p>
+ </span>
+ }
+ @TerminalBorder("", "", "") {
+ <div class="gap-[1ch]">
+ <span>{ ">" }</span>
+ <span class="text-(--secondary)">
+ @Link("/", false) {
+ { "cd $HOME" }
+ }
+ </span>
+ </div>
+ }
+ }
+ }
+}
+
+templ ScrollBox(extra string) {
+ <div data-scrollbox class={ "flex flex-1 min-h-0", extra }>
+ <div data-scroll-area class="flex-1 min-w-0 overflow-y-auto border-[0.1rem] border-solid border-(--alt) p-[1rem] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
+ { children... }
+ </div>
+ <div data-scroll-track class="relative w-8 -ml-[0.1rem] border-[0.1rem] border-solid border-(--alt)">
+ <div data-scroll-thumb class="absolute inset-x-[0.3rem] bg-(--secondary) cursor-grab touch-none"></div>
+ </div>
+ </div>
+}
+
+templ BlogsPage(style Style, blogs []Blog) {
+ @TerminalLayout(style, "blogs") {
+ @TerminalBorder("Shell", "", "mb-[1rem]") {
+ $ ls -lh ~/blogs
+ }
+ @ScrollBox("") {
+ @TerminalStack(false, "mt-[0.5rem]") {
+ for i := 0; i < 1; i++ {
+ for _, blog := range blogs {
+ @BlogItem("", blog, "mb-[1rem]")
+ }
+ }
+ }
+ }
+ }
+}
+
+type FetchRow struct {
+ Icon templ.Component
+ Color string // tailwind text color class, used for the icon and label
+ Label string
+ Value string
+}
+
+templ IconMonitor(color string) {
+ @Icon(color) {
+ <rect width="20" height="14" x="2" y="3" rx="2"></rect>
+ <line x1="8" x2="16" y1="21" y2="21"></line>
+ <line x1="12" x2="12" y1="17" y2="21"></line>
+ }
+}
+
+templ IconTerminal(color string) {
+ @Icon(color) {
+ <polyline points="4 17 10 11 4 5"></polyline>
+ <line x1="12" x2="20" y1="19" y2="19"></line>
+ }
+}
+
+templ IconCode(color string) {
+ @Icon(color) {
+ <polyline points="16 18 22 12 16 6"></polyline>
+ <polyline points="8 6 2 12 8 18"></polyline>
+ }
+}
+
+templ IconCpu(color string) {
+ @Icon(color) {
+ <rect width="16" height="16" x="4" y="4" rx="2"></rect>
+ <rect width="6" height="6" x="9" y="9" rx="1"></rect>
+ <path d="M15 2v2M15 20v2M2 15h2M2 9h2M20 15h2M20 9h2M9 2v2M9 20v2"></path>
+ }
+}
+
+templ IconScriptLang(color string) {
+ @Icon(color) {
+ <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-file-terminal preview-icon"><path d="M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z"></path><path d="M14 2v5a1 1 0 0 0 1 1h5"></path><path d="m8 16 2-2-2-2"></path><path d="M12 18h4"></path></svg>
+ }
+}
+
+templ IconEditor(color string) {
+ @Icon(color) {
+ <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-square-pen preview-icon"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z"></path></svg>
+ }
+}
+
+templ IconDebugger(color string) {
+ @Icon(color) {
+ <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-bug-off preview-icon"><path d="M12 20v-8"></path><path d="M12.656 7H14a4 4 0 0 1 4 4v1.344"></path><path d="M14.12 3.88 16 2"></path><path d="M17.123 17.123A6 6 0 0 1 6 14v-3a4 4 0 0 1 1.72-3.287"></path><path d="m2 2 20 20"></path><path d="M21 5a4 4 0 0 1-3.55 3.97"></path><path d="M22 13h-3.344"></path><path d="M3 21a4 4 0 0 1 3.81-4"></path><path d="M3 5a4 4 0 0 0 3.55 3.97"></path><path d="M6 13H2"></path><path d="m8 2 1.88 1.88"></path><path d="M9.712 4.06A3 3 0 0 1 15 6v1.13"></path></svg>
+ }
+}
+
+templ IconKeyboard(color string) {
+ @Icon(color) {
+ <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-keyboard preview-icon"><path d="M10 8h.01"></path><path d="M12 12h.01"></path><path d="M14 8h.01"></path><path d="M16 12h.01"></path><path d="M18 8h.01"></path><path d="M6 8h.01"></path><path d="M7 16h10"></path><path d="M8 12h.01"></path><rect width="20" height="16" x="2" y="4" rx="2"></rect></svg>
+ }
+}
+
+templ IconUptime(color string) {
+ @Icon(color) {
+ <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-clock preview-icon"><circle cx="12" cy="12" r="10"></circle><path d="M12 6v6l4 2"></path></svg>
+ }
+}
+
+func row(icon func(color string) templ.Component, color, label, value string) FetchRow {
+ return FetchRow{Icon: icon(color), Color: color, Label: label, Value: value}
+}
+
+var fetchRows = []FetchRow{
+ // row(IconTerminal, "text-(--secondary)", "Terminal", "Ghostty & Zsh"),
+ row(IconCode, "text-(--accent)", "Main Language", "C"),
+ row(IconScriptLang, "text-(--accent)", "Scripting Langs", "Go and Python"),
+ row(IconDebugger, "text-[#F16265]", "Debugger", "Raddebugger"),
+ row(IconMonitor, "text-[#54D7A9]", "Operating System", "Fedora KDE Linux"),
+ row(IconEditor, "text-[#54D7A9]", "Text Editor", "Neovim"),
+ row(IconUptime, "text-[#D8C44B]", "Uptime", GetMyUptime()),
+ // row(IconCpu, "text-(--extra)", "Hardware", "..."),
+}
+
+func branch(i, n int) string {
+ switch {
+ case n == 1:
+ return "─"
+ case i == 0:
+ return "┌"
+ case i == n-1:
+ return "└"
+ default:
+ return "├"
+ }
+}
+
+templ Fastfetch(rows []FetchRow) {
+ <div
+ style="
+ display: grid;
+ grid-template-columns: auto auto auto 1fr;
+ align-items: center;
+ column-gap: 1ch;
+ line-height: normal;
+ "
+ >
+ for i, row := range rows {
+ <span class="text-(--alt)">{ branch(i, len(rows)) }</span>
+ @row.Icon
+ <span class={ row.Color, "font-bold" }>{ row.Label }</span>
+ <span id={ row.Label }>{ row.Value }</span>
+ }
+ </div>
+}
+
+templ Icon(color string) {
+ <svg width="1.1em" height="1.1em" class={ "shrink-0", color } viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
+ { children... }
+ </svg>
+}