diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/app.d.ts | 13 | ||||
| -rw-r--r-- | src/app.html | 17 | ||||
| -rw-r--r-- | src/lib/assets/favicon.svg | 1 | ||||
| -rw-r--r-- | src/lib/components/Footer.svelte | 9 | ||||
| -rw-r--r-- | src/lib/components/Giscus.svelte | 27 | ||||
| -rw-r--r-- | src/lib/components/Header.svelte | 27 | ||||
| -rw-r--r-- | src/lib/components/PostCard.svelte | 27 | ||||
| -rw-r--r-- | src/lib/components/ThemeToggle.svelte | 78 | ||||
| -rw-r--r-- | src/lib/index.ts | 1 | ||||
| -rw-r--r-- | src/lib/styles/global.css | 206 | ||||
| -rw-r--r-- | src/lib/utils/posts.ts | 51 | ||||
| -rw-r--r-- | src/posts/first-post.svx | 16 | ||||
| -rw-r--r-- | src/routes/+layout.svelte | 20 | ||||
| -rw-r--r-- | src/routes/+layout.ts | 1 | ||||
| -rw-r--r-- | src/routes/+page.svelte | 24 | ||||
| -rw-r--r-- | src/routes/+page.ts | 1 | ||||
| -rw-r--r-- | src/routes/about/+page.svelte | 40 | ||||
| -rw-r--r-- | src/routes/apps/+page.svelte | 3 | ||||
| -rw-r--r-- | src/routes/posts/[slug]/+page.svelte | 36 | ||||
| -rw-r--r-- | src/routes/posts/[slug]/+page.ts | 26 |
20 files changed, 624 insertions, 0 deletions
diff --git a/src/app.d.ts b/src/app.d.ts new file mode 100644 index 0000000..da08e6d --- /dev/null +++ b/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://svelte.dev/docs/kit/types#app.d.ts +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/src/app.html b/src/app.html new file mode 100644 index 0000000..bde5c47 --- /dev/null +++ b/src/app.html @@ -0,0 +1,17 @@ +<!doctype html> +<html lang="en"> + +<head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> + %sveltekit.head% +</head> + +<body data-sveltekit-preload-data="hover"> + <div style="display: contents">%sveltekit.body%</div> +</body> + +</html>
\ No newline at end of file diff --git a/src/lib/assets/favicon.svg b/src/lib/assets/favicon.svg new file mode 100644 index 0000000..cc5dc66 --- /dev/null +++ b/src/lib/assets/favicon.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.157 22.819c-10.4-14.885-30.94-19.297-45.792-9.835L22.282 29.608A29.92 29.92 0 0 0 8.764 49.65a31.5 31.5 0 0 0 3.108 20.231 30 30 0 0 0-4.477 11.183 31.9 31.9 0 0 0 5.448 24.116c10.402 14.887 30.942 19.297 45.791 9.835l26.083-16.624A29.92 29.92 0 0 0 98.235 78.35a31.53 31.53 0 0 0-3.105-20.232 30 30 0 0 0 4.474-11.182 31.88 31.88 0 0 0-5.447-24.116" style="fill:#ff3e00"/><path d="M45.817 106.582a20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.503 18 18 0 0 1 .624-2.435l.49-1.498 1.337.981a33.6 33.6 0 0 0 10.203 5.098l.97.294-.09.968a5.85 5.85 0 0 0 1.052 3.878 6.24 6.24 0 0 0 6.695 2.485 5.8 5.8 0 0 0 1.603-.704L69.27 76.28a5.43 5.43 0 0 0 2.45-3.631 5.8 5.8 0 0 0-.987-4.371 6.24 6.24 0 0 0-6.698-2.487 5.7 5.7 0 0 0-1.6.704l-9.953 6.345a19 19 0 0 1-5.296 2.326 20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.502 17.99 17.99 0 0 1 8.13-12.052l26.081-16.623a19 19 0 0 1 5.3-2.329 20.72 20.72 0 0 1 22.237 8.243 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-.624 2.435l-.49 1.498-1.337-.98a33.6 33.6 0 0 0-10.203-5.1l-.97-.294.09-.968a5.86 5.86 0 0 0-1.052-3.878 6.24 6.24 0 0 0-6.696-2.485 5.8 5.8 0 0 0-1.602.704L37.73 51.72a5.42 5.42 0 0 0-2.449 3.63 5.79 5.79 0 0 0 .986 4.372 6.24 6.24 0 0 0 6.698 2.486 5.8 5.8 0 0 0 1.602-.704l9.952-6.342a19 19 0 0 1 5.295-2.328 20.72 20.72 0 0 1 22.237 8.242 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-8.13 12.053l-26.081 16.622a19 19 0 0 1-5.3 2.328" style="fill:#fff"/></svg>
\ No newline at end of file diff --git a/src/lib/components/Footer.svelte b/src/lib/components/Footer.svelte new file mode 100644 index 0000000..f06e5a6 --- /dev/null +++ b/src/lib/components/Footer.svelte @@ -0,0 +1,9 @@ +<footer class="container"> + <hr /> + <p> + <small + >{new Date().getFullYear()} + <a href="https://svelte.dev">SvelteKit</a></small + > + </p> +</footer> diff --git a/src/lib/components/Giscus.svelte b/src/lib/components/Giscus.svelte new file mode 100644 index 0000000..96be4a4 --- /dev/null +++ b/src/lib/components/Giscus.svelte @@ -0,0 +1,27 @@ +<script lang="ts"> + import { onMount } from "svelte"; + + let container: HTMLDivElement; + + onMount(() => { + const script = document.createElement("script"); + script.src = "https://giscus.app/client.js"; + script.setAttribute("data-repo", "wenekar/giscus"); + script.setAttribute("data-repo-id", "R_kgDOREZgEQ"); + script.setAttribute("data-category", "Announcements"); + script.setAttribute("data-category-id", "DIC_kwDOREZgEc4C1nRY"); + script.setAttribute("data-mapping", "pathname"); + script.setAttribute("data-strict", "0"); + script.setAttribute("data-reactions-enabled", "1"); + script.setAttribute("data-emit-metadata", "0"); + script.setAttribute("data-input-position", "bottom"); + script.setAttribute("data-theme", "preferred_color_scheme"); + script.setAttribute("data-lang", "en"); + script.setAttribute("data-loading", "lazy"); + script.crossOrigin = "anonymous"; + script.async = true; + container.appendChild(script); + }); +</script> + +<div class="giscus-container" bind:this={container}></div> diff --git a/src/lib/components/Header.svelte b/src/lib/components/Header.svelte new file mode 100644 index 0000000..804497e --- /dev/null +++ b/src/lib/components/Header.svelte @@ -0,0 +1,27 @@ +<script lang="ts"> + import ThemeToggle from "./ThemeToggle.svelte"; + + interface Props { + title?: string; + description?: string; + } + + let { title = "My Blog", description = "Super. Good. Code." }: Props = + $props(); +</script> + +<div class="wrapper-masthead"> + <header class="container masthead"> + <div class="site-info"> + <h1><a href="/">{title}</a></h1> + <p class="site-description">{description}</p> + </div> + + <nav> + <a href="/">Blog</a> + <a href="/apps">Apps</a> + <a href="/about">About</a> + <ThemeToggle /> + </nav> + </header> +</div> diff --git a/src/lib/components/PostCard.svelte b/src/lib/components/PostCard.svelte new file mode 100644 index 0000000..7fb9361 --- /dev/null +++ b/src/lib/components/PostCard.svelte @@ -0,0 +1,27 @@ +<script lang="ts"> + import type { Post } from "$lib/utils/posts"; + + interface Props { + post: Post; + } + + let { post }: Props = $props(); + + function formatDate(dateStr: string): string { + return new Date(dateStr).toLocaleDateString("en-US", { + year: "numeric", + month: "long", + day: "numeric", + }); + } +</script> + +<article> + <header> + <a href="/posts/{post.slug}"> + <h1 style="text-decoration: none;">{post.title}</h1> + </a> + <small><time datetime={post.date}>{formatDate(post.date)}</time></small> + </header> + <p>{post.description}</p> +</article> diff --git a/src/lib/components/ThemeToggle.svelte b/src/lib/components/ThemeToggle.svelte new file mode 100644 index 0000000..f136246 --- /dev/null +++ b/src/lib/components/ThemeToggle.svelte @@ -0,0 +1,78 @@ +<script lang="ts"> + import { browser } from "$app/environment"; + + function getInitialTheme(): "light" | "dark" { + if (browser) { + const stored = localStorage.getItem("theme"); + if (stored === "light" || stored === "dark") return stored; + return window.matchMedia("(prefers-color-scheme: dark)").matches + ? "dark" + : "light"; + } + return "light"; + } + + let theme = $state<"light" | "dark">(getInitialTheme()); + + function applyTheme(newTheme: "light" | "dark") { + if (browser) { + document.documentElement.setAttribute("data-theme", newTheme); + localStorage.setItem("theme", newTheme); + } + } + + $effect(() => { + applyTheme(theme); + }); + + function toggleTheme() { + theme = theme === "light" ? "dark" : "light"; + } +</script> + +<button + class="theme-toggle" + onclick={toggleTheme} + aria-label={theme === "light" + ? "Switch to dark mode" + : "Switch to light mode"} + title={theme === "light" ? "Switch to dark mode" : "Switch to light mode"} +> + {#if theme === "light"} + <svg + xmlns="http://www.w3.org/2000/svg" + width="20" + height="20" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + > + <path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path> + </svg> + {:else} + <svg + xmlns="http://www.w3.org/2000/svg" + width="20" + height="20" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + > + <circle cx="12" cy="12" r="5"></circle> + <line x1="12" y1="1" x2="12" y2="3"></line> + <line x1="12" y1="21" x2="12" y2="23"></line> + <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> + <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> + <line x1="1" y1="12" x2="3" y2="12"></line> + <line x1="21" y1="12" x2="23" y2="12"></line> + <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> + <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> + </svg> + {/if} +</button> diff --git a/src/lib/index.ts b/src/lib/index.ts new file mode 100644 index 0000000..856f2b6 --- /dev/null +++ b/src/lib/index.ts @@ -0,0 +1 @@ +// place files you want to import through the `$lib` alias in this folder. diff --git a/src/lib/styles/global.css b/src/lib/styles/global.css new file mode 100644 index 0000000..8ec94fc --- /dev/null +++ b/src/lib/styles/global.css @@ -0,0 +1,206 @@ +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +:root { + --bg: #fff; + --text: #333; + --muted: #666; + --link: #888; + --link-hover: #000; + --border: #eee; + --code-bg: #f5f5f5; + --font: "Inter", sans-serif; + --mono: "Bitstream Vera Sans Mono", "Courier New", monospace; +} + +[data-theme="dark"] { + --bg: #1a1a1a; + --text: #e0e0e0; + --muted: #999; + --link-hover: #fff; + --border: #333; + --code-bg: #2a2a2a; +} + +html { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +body { + font: 18px/1.4 var(--font); + color: var(--text); + background: var(--bg); + transition: background 0.2s, color 0.2s; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin-bottom: 2rem; +} + +.container { + max-width: 900px; + margin: 0 auto; + padding: 0 2rem; +} + +p { + margin-bottom: 1rem; +} + +a { + color: var(--link); + text-decoration: none; + transition: color 0.2s; +} + +a:hover { + color: var(--link-hover); +} + +ul, +ol { + margin-bottom: 1rem; + padding-left: 1.5rem; +} + +li { + margin-bottom: 0.25rem; +} + +blockquote { + border-left: 2px solid var(--muted); + padding-left: 1em; + margin: 1.5rem 0; + font-style: italic; +} + +code { + font-family: var(--mono); + font-size: 0.9em; + background: var(--code-bg); + padding: 0.2em 0.4em; + border-radius: 3px; +} + +pre { + font-family: var(--mono); + background: var(--code-bg); + padding: 1rem; + border-radius: 4px; + overflow-x: auto; + margin: 1.5rem 0; + box-shadow: 3px 3px rgba(0, 0, 0, 0.1); +} + +pre code { + background: none; + padding: 0; +} + +img { + max-width: 100%; + height: auto; +} + +hr { + border: none; + border-top: 1px solid var(--border); + margin: 2rem 0; +} + +small, +time { + font-size: 15px; + color: var(--muted); +} + +/* Layout */ +.wrapper-masthead { + margin: 0 2rem 3rem; +} + +.masthead { + padding: 1.25rem 0; + border-bottom: 1px solid var(--border); + display: flex; + justify-content: space-between; + align-items: center; +} + +.site-info { + display: flex; + flex-direction: column; + margin-left: 2rem; +} + +.site-info h1 { + margin: 0; + font-size: 1.75rem; + font-weight: 300; + letter-spacing: 1px; +} + +.site-description { + margin: -0.25rem 0 0 0; + color: var(--muted); + font-size: 1rem; +} + +header nav { + display: flex; + align-items: center; + gap: 1.25rem; + font-size: 18px; +} + +footer { + margin-top: 4rem; + text-align: center; +} + +article { + margin-bottom: 2rem; +} + +.theme-toggle { + background: transparent; + border: none; + padding: 0.5rem; + cursor: pointer; + color: var(--muted); + display: flex; + align-items: center; + justify-content: center; + transition: color 0.2s; +} + +.theme-toggle:hover { + color: var(--link-hover); +} + +.giscus-container { + margin-top: 3rem; +} + +@media (max-width: 640px) { + .masthead { + flex-direction: column; + text-align: center; + gap: 1rem; + } + + header nav { + gap: 0.75rem; + } +}
\ No newline at end of file diff --git a/src/lib/utils/posts.ts b/src/lib/utils/posts.ts new file mode 100644 index 0000000..cc05c83 --- /dev/null +++ b/src/lib/utils/posts.ts @@ -0,0 +1,51 @@ +import type { Component } from 'svelte'; + +export interface PostMetadata { + title: string; + date: string; + description: string; + tags?: string[]; +} + +export interface Post extends PostMetadata { + slug: string; +} + +export interface PostModule { + default: Component; + metadata: PostMetadata; +} + +// Use Vite's glob import to get all .svx files from posts directory +const postFiles = import.meta.glob<PostModule>('/src/posts/*.svx', { eager: true }); + +/** + * Get all posts, sorted by date (newest first) + */ +export function getPosts(): Post[] { + const posts: Post[] = []; + + for (const path in postFiles) { + const file = postFiles[path]; + // Extract slug from path: /src/posts/hello-world.svx -> hello-world + const slug = path.split('/').pop()?.replace('.svx', '') ?? ''; + + if (file.metadata) { + posts.push({ + ...file.metadata, + slug + }); + } + } + + // Sort by date, newest first + return posts.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); +} + +/** + * Get a single post by slug + */ +export function getPost(slug: string): PostModule | undefined { + const path = `/src/posts/${slug}.svx`; + return postFiles[path]; +} diff --git a/src/posts/first-post.svx b/src/posts/first-post.svx new file mode 100644 index 0000000..5526b24 --- /dev/null +++ b/src/posts/first-post.svx @@ -0,0 +1,16 @@ +--- +title: First Post +date: "2026-01-30" +description: new beningings. +--- + +# new beningings. + +What a time to be alive and get into software. + +Hello, and welcome, to my weird lil mindscape where I thought it would be a *great* idea to share my thoughts on the vast wide open internet. + +I am not sure why the idea that *I need a blog* stuck to my brain like a tumor for long enough that I pulled the trigger and got a VPS for it, but ig im kinda glad. + +Hope you like what you see here, and hope I get enough time and energy to pour my thoughts into words. + diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte new file mode 100644 index 0000000..ac15a2e --- /dev/null +++ b/src/routes/+layout.svelte @@ -0,0 +1,20 @@ +<script lang="ts"> + import Header from "$lib/components/Header.svelte"; + import Footer from "$lib/components/Footer.svelte"; + import favicon from "$lib/assets/favicon.svg"; + import "$lib/styles/global.css"; + + let { children } = $props(); +</script> + +<svelte:head> + <link rel="icon" href={favicon} /> +</svelte:head> + +<Header title="Berke Güzel" description="Super. Bad. Code." /> + +<main class="container"> + {@render children()} +</main> + +<Footer /> diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts new file mode 100644 index 0000000..189f71e --- /dev/null +++ b/src/routes/+layout.ts @@ -0,0 +1 @@ +export const prerender = true; diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte new file mode 100644 index 0000000..e304a68 --- /dev/null +++ b/src/routes/+page.svelte @@ -0,0 +1,24 @@ +<script lang="ts"> + import PostCard from "$lib/components/PostCard.svelte"; + import { getPosts } from "$lib/utils/posts"; + + const posts = getPosts(); +</script> + +<svelte:head> + <title>wenekar sucks at programming</title> + <meta + name="description" + content="A personal blog built with SvelteKit and MDsveX" + /> +</svelte:head> + +<section> + {#if posts.length === 0} + <p>No posts.</p> + {:else} + {#each posts as post} + <PostCard {post} /> + {/each} + {/if} +</section> diff --git a/src/routes/+page.ts b/src/routes/+page.ts new file mode 100644 index 0000000..176ae64 --- /dev/null +++ b/src/routes/+page.ts @@ -0,0 +1 @@ +export const prerender = true diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte new file mode 100644 index 0000000..3f47736 --- /dev/null +++ b/src/routes/about/+page.svelte @@ -0,0 +1,40 @@ +<h1>About</h1> + +<p> + My name is Berke Güzel and I am a huge fan of + <a href="https://supergoodcode.com">Super. Good. Code.</a> +</p> + +<p> + I do not do code good. I am aiming to use this page as a means of publicly + sharing my thoughts, and + <i>maybe</i> projects. And who knows, maybe one day, this will grow into something + bigger than I could ever imagine. +</p> + +<p> + Currently I'm employed as a software "developer", working on projects that + use Django/rest_framework stack. +</p> + +<h2>More about me</h2> + +<p> + At present I work for a media company, they write news, also publish videos + on YouTube. This blog shall not contain anything about the place I work at, + or the future companies that I may get hired at. +</p> + +<p> + I try avoiding social media platforms (like Facebook, Instagram etc.) like a + plague. If anyone seems to act like me on those platforms, be certain that + it is not me, and maybe report them to the platform but I doubt they would + do anything anyway. +</p> + +<h2>Even more!</h2> + +<p><i>add text later</i></p> + +<h3>Links!</h3> +<p><a href="https://github.com/wenekar/">GitHub</a></p> diff --git a/src/routes/apps/+page.svelte b/src/routes/apps/+page.svelte new file mode 100644 index 0000000..890fc31 --- /dev/null +++ b/src/routes/apps/+page.svelte @@ -0,0 +1,3 @@ +<h1>Apps</h1> + +<p><i>Coming soon...</i></p> diff --git a/src/routes/posts/[slug]/+page.svelte b/src/routes/posts/[slug]/+page.svelte new file mode 100644 index 0000000..2a57168 --- /dev/null +++ b/src/routes/posts/[slug]/+page.svelte @@ -0,0 +1,36 @@ +<script lang="ts"> + import type { PageData } from "./$types"; + import Giscus from "$lib/components/Giscus.svelte"; + + let { data }: { data: PageData } = $props(); + + function formatDate(dateStr: string): string { + return new Date(dateStr).toLocaleDateString("en-US", { + year: "numeric", + month: "long", + day: "numeric", + }); + } +</script> + +<svelte:head> + <title>{data.metadata.title} | My Blog</title> + <meta name="description" content={data.metadata.description} /> +</svelte:head> + +<article> + <header> + <h1>{data.metadata.title}</h1> + <p> + <time datetime={data.metadata.date} + >{formatDate(data.metadata.date)}</time + > + </p> + </header> + + <data.content /> +</article> + +<Giscus /> + +<a href="/">← Back to all posts</a> diff --git a/src/routes/posts/[slug]/+page.ts b/src/routes/posts/[slug]/+page.ts new file mode 100644 index 0000000..d0776db --- /dev/null +++ b/src/routes/posts/[slug]/+page.ts @@ -0,0 +1,26 @@ +import { getPost, getPosts } from '$lib/utils/posts'; +import { error } from '@sveltejs/kit'; +import type { PageLoad } from './$types'; + +export const prerender = true; + +// Generate all post routes at build time +export function entries() { + const posts = getPosts(); + return posts.map((post) => ({ slug: post.slug })); +} + +export const load: PageLoad = async ({ params }) => { + const slug = params.slug; + const post = getPost(slug); + + if (!post) { + error(404, `Post not found: ${slug}`); + } + + return { + content: post.default, + metadata: post.metadata, + slug + }; +}; |
