personal website

Compare changes

Choose any two refs to compare.

+3
.gitignore
··· 23 23 # jetbrains setting folder 24 24 .idea/ 25 25 .vercel 26 + 27 + # Local Netlify folder 28 + .netlify
+1
.netlify/v1/config.json
··· 1 + {"images":{"remote_images":[]},"headers":[{"for":"/_astro/*","values":{"Cache-Control":"public, max-age=31536000, immutable"}}]}
+12 -5
astro.config.mjs
··· 3 3 import icon from "astro-icon"; 4 4 import mdx from "@astrojs/mdx"; 5 5 import svelte from "@astrojs/svelte"; 6 - import tailwind from "@astrojs/tailwind"; 7 - import vercel from "@astrojs/vercel/serverless"; 6 + import tailwindcss from "@tailwindcss/vite"; 7 + 8 + import netlify from "@astrojs/netlify"; 9 + 10 + import og from "astro-og"; 8 11 9 12 // https://astro.build/config 10 13 export default defineConfig({ 11 - integrations: [tailwind(), svelte(), mdx(), icon()], 12 - output: "server", 13 - adapter: vercel({ webAnalytics: { enabled: true }}) 14 + integrations: [svelte(), mdx(), icon(), og()], 15 + output: "static", 16 + adapter: netlify(), 17 + vite: { 18 + plugins: [tailwindcss()], 19 + }, 20 + site: "https://zeu.dev" 14 21 });
bun.lockb

This is a binary file and will not be displayed.

+15 -14
package.json
··· 10 10 "astro": "astro" 11 11 }, 12 12 "dependencies": { 13 - "@astrojs/check": "^0.9.4", 14 - "@astrojs/mdx": "^3.1.8", 15 - "@astrojs/svelte": "^5.7.2", 16 - "@astrojs/tailwind": "^5.1.2", 17 - "@astrojs/vercel": "^7.8.2", 18 - "@iconify-json/tabler": "^1.2.5", 19 - "@sveltejs/vite-plugin-svelte": "^4.0.0-next.6", 20 - "@vercel/analytics": "^1.3.1", 21 - "astro": "^4.16.6", 22 - "astro-icon": "^1.1.1", 23 - "svelte": "^5.0.3", 24 - "tailwindcss": "^3.4.14", 25 - "typescript": "^5.6.3" 13 + "@astrojs/check": "0.9.6", 14 + "@astrojs/mdx": "4.3.12", 15 + "@astrojs/netlify": "6.6.3", 16 + "@astrojs/svelte": "7.2.2", 17 + "@iconify-json/tabler": "^1.2.23", 18 + "@sveltejs/vite-plugin-svelte": "^6.2.1", 19 + "@tailwindcss/vite": "^4.1.17", 20 + "astro": "5.16.4", 21 + "astro-icon": "^1.1.5", 22 + "astro-og": "^0.3.1", 23 + "bits-ui": "^2.14.4", 24 + "svelte": "^5.45.5", 25 + "tailwindcss": "^4.1.17", 26 + "typescript": "^5.9.3" 26 27 }, 27 28 "devDependencies": { 28 - "@tailwindcss/typography": "^0.5.15" 29 + "@tailwindcss/typography": "^0.5.19" 29 30 } 30 31 }
public/opensauced.png

This is a binary file and will not be displayed.

public/pomerium.png

This is a binary file and will not be displayed.

-1
public/src/env.d.ts
··· 1 - /// <reference path="../.astro/types.d.ts" />
public/zuplo.png

This is a binary file and will not be displayed.

+1 -3
src/components/BlogCard.astro
··· 6 6 } 7 7 8 8 const { blog } = Astro.props; 9 - 10 - const directory = blog.collection + "/"; 11 9 --- 12 10 13 - <a href={directory + blog.slug}> 11 + <a href={`/blog/${blog.slug}`}> 14 12 <article 15 13 class="flex flex-row justify-between items-center w-full h-fit px-8 py-4 border-2 text-white rounded-md"> 16 14 <div class="flex flex-col gap-2 !!no-underline ">
+53
src/components/NavigationDialog.svelte
··· 1 + <script lang="ts"> 2 + import { Dialog } from "bits-ui"; 3 + </script> 4 + 5 + <Dialog.Root> 6 + <Dialog.Trigger> 7 + Menu 8 + </Dialog.Trigger> 9 + <Dialog.Portal> 10 + <Dialog.Overlay class="fixed inset-0 z-50 bg-black/80" /> 11 + <Dialog.Content 12 + class="bg-neutral-800 fixed left-[50%] top-[50%] z-50 w-full max-w-[94%] translate-x-[-50%] translate-y-[-50%] rounded-card-lg border bg-background p-5 shadow-popover outline-none sm:max-w-[490px] md:w-full" 13 + > 14 + <nav id="navigation" class="flex flex-col gap-4 w-full md:col-span-1"> 15 + <section class="flex flex-col gap-2 text-white"> 16 + <h3 class="text-yellow-500"> 17 + <a href="/blog" class="after:content-['_->'] before:content-['๐Ÿ“‘_']">blog</a> 18 + </h3> 19 + </section> 20 + 21 + <hr class="border-yellow-500 " /> 22 + 23 + <section class="flex flex-col gap-2 text-white"> 24 + <h3 class="text-yellow-500"> 25 + <a href="/resume" class="after:content-['_->'] before:content-['๐Ÿ’ผ_']">resume</a> 26 + </h3> 27 + <h3 class="text-yellow-500"> 28 + <a href="/open-source" class="after:content-['_->'] before:content-['๐Ÿงฎ_']">open source</a> 29 + </h3> 30 + <h3 class="text-yellow-500"> 31 + <a href="/as-seen-on" class="after:content-['_->'] before:content-['๐ŸŽฅ_']">as seen on</a> 32 + </h3> 33 + </section> 34 + 35 + <hr class="border-yellow-500 " /> 36 + 37 + <section class="flex flex-col gap-2 text-white"> 38 + <h3 class="text-yellow-500">socials</h3> 39 + <a href="https://bsky.app/profile/zeu.dev" target="_blank" class="after:content-['_โ†—'] before:content-['๐Ÿฆ‹_']">bluesky</a> 40 + <a href="https://github.com/zeucapua" target="_blank" class="after:content-['_โ†—'] before:content-['๐Ÿ’ป_']">github</a> 41 + <a href="https://tangled.sh/zeu.dev" target="_blank" class="after:content-['_โ†—'] before:content-['๐Ÿงถ_']">tangled</a> 42 + <a href="https://twitch.tv/zeu_dev" target="_blank" class="after:content-['_โ†—'] before:content-['๐Ÿ‘พ_']">twitch</a> 43 + <a href="https://stream.place/zeu.dev" target="_blank" class="after:content-['_โ†—'] before:content-['๐ŸŸช_']">streamplace</a> 44 + </section> 45 + </nav> 46 + <Dialog.Close 47 + class="absolute right-5 top-5 rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-foreground focus-visible:ring-offset-2 focus-visible:ring-offset-background active:scale-98" 48 + > 49 + x 50 + </Dialog.Close> 51 + </Dialog.Content> 52 + </Dialog.Portal> 53 + </Dialog.Root>
+40 -23
src/components/SiteLayout.astro
··· 1 1 --- 2 - import { ViewTransitions } from "astro:transitions"; 2 + import NavigationDialog from "./NavigationDialog.svelte"; 3 3 const { title } = Astro.props; 4 4 --- 5 5 ··· 7 7 <head> 8 8 <meta charset="utf-8" /> 9 9 <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>๐Ÿ’›</text></svg>"> 10 + <script 11 + defer 12 + is:inline 13 + src="https://assets.onedollarstats.com/tracker.js" 14 + id="stonks" 15 + ></script> 10 16 <meta name="viewport" content="width=device-width" /> 11 17 <meta name="generator" content={Astro.generator} /> 18 + <meta property="og:type" content="website" /> 19 + <meta property="og:url" content="https://www.zeu.dev" /> 20 + <meta property="og:title" content={title ?? "zeu.dev"} /> 21 + <meta property="og:description" content="Personal site of Zeu, a software engineer." /> 22 + <meta property="twitter:card" content="/site_screenshot.png"> 23 + <meta property="og:image" content="/site_screenshot.png"> 24 + <meta property="og:image:alt" content="zeu in lower case ASCII"> 12 25 <title>{ title }</title> 13 - <ViewTransitions /> 14 26 </head> 15 27 <body class="relative font-syne bg-neutral-900 text-yellow-500 grid grid-cols-1 md:grid-cols-5 w-full h-full min-w-screen min-h-screen"> 16 - <aside class="sticky top-0 max-h-screen flex items-center border-yellow-500 justify-between md:border-r-2 w-full md:w-fit md:justify-start md:items-start h-fit md:h-full md:flex-col gap-4 font-medium p-4"> 28 + <aside class="sticky top-0 z-50 bg-neutral-900 max-h-screen flex items-center border-yellow-500 justify-between md:border-r-2 w-full md:w-fit md:justify-start md:items-start h-fit md:h-full md:flex-col gap-4 font-medium p-4"> 17 29 <div class="flex flex-col gap-2 text-xl"> 18 30 <h1> 19 31 <a href="/" class="after:content-['_->']">zeu.dev</a> ··· 21 33 <h2 class="hidden md:flex">all things me!</h2> 22 34 </div> 23 35 24 - <button id="menu_button" class="px-2 py-1 border border-yellow-500 self-end w-fit h-fit md:hidden"> 25 - Menu 26 - </button> 36 + <NavigationDialog client:load /> 27 37 28 38 <nav id="navigation" class="hidden md:flex flex-col gap-4 w-full md:col-span-1" transition:persist> 29 39 <hr class="border-yellow-500 " /> 30 40 31 41 <section class="flex flex-col gap-2 text-white"> 32 - <h3 class="text-yellow-500">socials</h3> 33 - <a href="https://twitter.com/zeu_dev" target="_blank" class="after:content-['_โ†—']">twitter</a> 34 - <a href="https://github.com/zeucapua" target="_blank" class="after:content-['_โ†—']">github</a> 35 - <a href="https://twitch.tv/zeu_dev" target="_blank" class="after:content-['_โ†—']">twitch</a> 42 + <h3 class="text-yellow-500"> 43 + <a href="/blog" class="after:content-['_->'] before:content-['๐Ÿ“‘_']">blog</a> 44 + </h3> 36 45 </section> 37 46 38 47 <hr class="border-yellow-500 " /> 39 48 40 49 <section class="flex flex-col gap-2 text-white"> 41 50 <h3 class="text-yellow-500"> 42 - <a href="/blog" class="after:content-['_->']">blog</a> 51 + <a href="/resume" class="after:content-['_->'] before:content-['๐Ÿ’ผ_']">resume</a> 52 + </h3> 53 + <h3 class="text-yellow-500"> 54 + <a href="/open-source" class="after:content-['_->'] before:content-['๐Ÿงฎ_']">open source</a> 55 + </h3> 56 + <h3 class="text-yellow-500"> 57 + <a href="/as-seen-on" class="after:content-['_->'] before:content-['๐ŸŽฅ_']">as seen on</a> 43 58 </h3> 44 59 </section> 45 60 46 61 <hr class="border-yellow-500 " /> 47 62 48 63 <section class="flex flex-col gap-2 text-white"> 49 - <h3 class="text-yellow-500"> 50 - <a href="/resume" class="after:content-['_->']">resume</a> 51 - </h3> 52 - <h3 class="text-yellow-500"> 53 - <a href="/open-source" class="after:content-['_->']">open source</a> 54 - </h3> 55 - <a href="https://app.opensauced.pizza" target="_blank" class="after:content-['_โ†—']">OpenSauced</a> 56 - <a href="https://easytodo.link" target="_blank" class="after:content-['_โ†—']">easytodo.link</a> 64 + <h3 class="text-yellow-500">socials</h3> 65 + <a href="https://bsky.app/profile/zeu.dev" target="_blank" class="after:content-['_โ†—'] before:content-['๐Ÿฆ‹_']">bluesky</a> 66 + <a href="https://github.com/zeucapua" target="_blank" class="after:content-['_โ†—'] before:content-['๐Ÿ’ป_']">github</a> 67 + <a href="https://tangled.sh/zeu.dev" target="_blank" class="after:content-['_โ†—'] before:content-['๐Ÿงถ_']">tangled</a> 68 + <a href="https://twitch.tv/zeu_dev" target="_blank" class="after:content-['_โ†—'] before:content-['๐Ÿ‘พ_']">twitch</a> 69 + <a href="https://stream.place/zeu.dev" target="_blank" class="after:content-['_โ†—'] before:content-['๐ŸŸช_']">streamplace</a> 57 70 </section> 71 + 58 72 </nav> 59 73 </aside> 60 74 ··· 64 78 </body> 65 79 </html> 66 80 67 - <script> 68 - const menuButton = document.querySelector("#menu_button"); 69 - const navSection = document.querySelector("#navigation"); 70 - </script> 71 81 72 82 <style is:global> 83 + @import "tailwindcss"; 84 + @plugin "@tailwindcss/typography"; 85 + 86 + @theme { 87 + --font-syne: "SyneMono"; 88 + } 89 + 73 90 @font-face { 74 91 font-family: "SyneMono"; 75 92 src: url("/SyneMono-Regular.ttf");
+25
src/content/about/as-seen-on.mdx
··· 1 + --- 2 + updated_at: 12-5-2025 3 + draft: false 4 + --- 5 + 6 + import { Icon } from "astro-icon/components"; 7 + 8 + I've participated in a few community events and video. I stream on [stream.place](https://stream.place/zeu.dev) 9 + and [Twitch](https://twitch.tv/zeu_dev), and post videos sometimes on my [youtube channel](https://www.youtube.com/@zeucapua851). 10 + 11 + ## Web Dev Challenge: Build a multiplayer web app using PartyKit [<Icon name="tabler:brand-youtube" class="inline-block" />](https://youtu.be/DbaBeLDU-oY?si=Y074Vjt9-7BX2NnI) 12 + 13 + - 24k+ views on YouTube 14 + - 18 stars on the typer99 GitHub repository 15 + - Built a type racing game with powerups and obstacles, implementing PartyKit into a SvelteKit application 16 + - Participated alongside Jason Lengstorf (host), Nick Taylor (prev OpenSauced), and Steve Ruiz (tldraw.com) 17 + 18 + ## Web Dev Challenge: What can you build in 4 hours with Google Gemini? [<Icon name="tabler:brand-youtube" class="inline-block" />](https://www.youtube.com/watch?v=pn5Jju4FNG4) 19 + 20 + - 97k+ views on YouTube 21 + - 8 stars on the thankadev GitHub repository 22 + - Built an AI generated thank you note that can be shared on X (formerly Twitter) for each library listed in a given repository's SBOM (software bill of materials) 23 + - Sponsored by Google Gemini AI and is integrated into the project, all of which was built in 4 hours 24 + - Participated alongside Jason Lengstorf (host), Brian Holt (Neon DB), and Sarah aka badcop_ (prev Boot.dev) 25 + - Recorded live in studio by a professional camera and sound crew throughout a 12 hour production day
+21 -4
src/content/about/open-source.mdx
··· 1 1 --- 2 - updated_at: 10-21-2024 2 + updated_at: 01-08-2025 3 3 draft: false 4 4 --- 5 5 6 6 import { Icon } from "astro-icon/components"; 7 7 8 + <hr /> 9 + 10 + # Applications 11 + ## Myb [<Icon name="tabler:brand-github-filled" class="inline-block" />](https://github.com/zeucapua/myb) 12 + - A custom third party Bluesky client with extra features like bookmarks and drafts 13 + - Implemented with SvelteKit, using libraries such as the AT Protocol SDK and TanStack Query 14 + 15 + ## Easytodo [<Icon name="tabler:brand-github-filled" class="inline-block" />](https://github.com/zeucapua/easytodo.link) 16 + - An easy and local first todo list app, with per task stopwatch and other planned features 17 + - Implemented with SvelteKit, using a custom persistent local storage reactive function closure 18 + 19 + ## Gust [<Icon name="tabler:brand-github-filled" class="inline-block" />](https://github.com/zeucapua/gust) 20 + - A time tracker productivity tool with authentication, cloud storage, and full CRUD capabilities 21 + - Implemented features using Astro Partials and Client Islands (Svelte components) that are inline and rendered on demand using HTMX library, a HTML-centered AJAX API 22 + 23 + <hr /> 24 + 25 + # Explorations 8 26 ## Skogz [<Icon name="tabler:brand-github-filled" class="inline-block" />](https://github.com/zeucapua/skogz) 9 27 - An experimental Svelte 5 SSR (server side rendered) router, built on top of the Vite Extra template 10 28 - Implemented custom middleware that can handle loader functions and load the correct components based on a routes configuration object 11 29 12 - ## Gust [<Icon name="tabler:brand-github-filled" class="inline-block" />](https://github.com/zeucapua/gust) 13 - - A time tracker productivity tool with authentication, cloud storage, and full CRUD capabilities 14 - - Implemented features using Astro Partials and Client Islands (Svelte components) that are inline and rendered on demand using HTMX library, a HTML-centered AJAX API 30 + <hr /> 15 31 32 + # Packages 16 33 ## Typew [<Icon name="tabler:brand-github-filled" class="inline-block" />](https://github.com/zeucapua/typew) 17 34 - An animated text component that mimics the typewriter, writing letter by letter 18 35 - Implemented as a no dependency needed Svelte library
+47 -21
src/content/about/resume.mdx
··· 5 5 6 6 import { Icon } from "astro-icon/components"; 7 7 8 - A generalist Software Engineer, specialized in solutions and product engineering, utilizing technologies across the stack and languages like Javascript (Next.js), Python (Django), and GoLang (Cobra). Based in San Bernardino, California USA with 8 months of remote and open source experience. 8 + A Software Engineer making products and solutions, particular in frontend development, 9 + 10 + <hr /> 9 11 10 12 # Experience 13 + ## Software Engineer, Pomerium [<Icon name="tabler:external-link" class="inline-block" />](https://pomerium.com) 14 + _April 2025 - October 2025_ 15 + - Implemented new features and bug fixes on the Layer 7 proxy security dashboards 16 + - Worked on two product offerings for general users and enterprise customers, each with their own monorepo 17 + - Coordinated with backend engineers and management to ensure continuity between UX for more technical users 18 + with the CLI and the frontend web interface 19 + - Technology Stack: React Router, React, Redux, Material UI, PostHog, GoLang 20 + <a href="https://pomerium.com" class="flex gap-2 items-center -my-8 hover:underline" target="_blank"> 21 + <img src="/pomerium.png" alt="Pomerium Logo" class="size-8 rounded" /> 22 + pomerium.com 23 + <Icon name="tabler:external-link" class="inline-block -top-2" /> 24 + </a> 25 + 11 26 ## Software Engineer, OpenSauced [<Icon name="tabler:external-link" class="inline-block" />](https://opensauced.pizza) 12 - _February 2024 - Present_ 27 + _February 2024 - October 2024_ 13 28 - Worked with different technology stacks and products throughout the company 14 29 - Coordinated and collaborated with every department, including marketing, product, and engineering 15 30 - Helped market the brand and features on X (formerly Twitter), resulting in thousands of impressions ··· 17 32 - Reviewed external contributors' issues and pull requests 18 33 19 34 ### The OpenSauced App [<Icon name="tabler:brand-github-filled" class="inline-block" />](https://github.com/open-sauced/app) 20 - - Tech Stack: Next.js, React, TailwindCSS, PostHog, Playwright, Supabase, Storybook, SWR and more 35 + - Technology Stack: Next.js, React, TailwindCSS, PostHog, Playwright, Supabase, Storybook, SWR and more 21 36 - 88 pull requests in the last 6 months, about 20% of all contributions on the application product 22 37 23 38 #### Repo Pages ··· 38 53 - Implemented major features for the CODEOWNERS centered CLI program built on Golang, Cobra CLI framework, and the BubbleTea terminal framework 39 54 - `pizza generate config`: an automatic or interactive terminal command that creates a global available YAML file that keeps track Git attributions 40 55 - `pizza offboard`: removes Git attributions by YAML configuration and CODEOWNERS files 41 - - Tech Stack: GoLang, Cobra CLI, BubbleTea 56 + - Technology Stack: GoLang, Cobra CLI, BubbleTea 42 57 43 58 ### Landing Page & Blog [<Icon name="tabler:brand-github-filled" class="inline-block" />](https://github.com/open-sauced/landing-page) 44 59 - Implemented and managed the Sanity CMS for viewing on the company blog 45 60 - Styled with TailwindCSS and Framer Motion based on Figma designs by the Product Manager 46 61 - Created and updated multiple landing pages for product (the app and Pizza CLI) and various use cases (Teams, Maintainers, Contributors, and Students) 47 - - Tech Stack: Next.js, React, TailwindCSS, PostHog and more 62 + - Technology Stack: Next.js, React, TailwindCSS, PostHog and more 63 + 64 + <a href="https://github.com/open-sauced" class="flex gap-2 items-center -my-8 hover:underline" target="_blank"> 65 + <img src="/opensauced.png" alt="OpenSauced Logo" class="size-8 rounded" /> 66 + github.com/open-sauced 67 + <Icon name="tabler:external-link" class="inline-block -top-2" /> 68 + </a> 69 + 70 + <hr /> 71 + 72 + # Contract Work 73 + 74 + ## Consultant Software Engineer, Zuplo [<Icon name="tabler:external-link" class="inline-block" />](https://zuplo.com) 75 + _November 2025 - December 2025_ 76 + - Implemented a proof of concept for `zudoku schema generate example` CLI command, generates examples for response and request body schemas 77 + without explicit examples given an OpenAPI JSON file 78 + - Technology Stack: Yargs, @clack/prompts, Typescript, Nx 79 + <a href="https://zuplo.com" class="flex gap-2 items-center -my-8 hover:underline" target="_blank"> 80 + <img src="/zuplo.png" alt="Zuplo Logo" class="size-8 rounded" /> 81 + zuplo.com 82 + <Icon name="tabler:external-link" class="inline-block -top-2" /> 83 + </a> 48 84 49 85 ## Full Stack Developer, Buttondown [<Icon name="tabler:external-link" class="inline-block" />](https://buttondown.email) 50 86 _November 2023 - February 2024_ 51 87 - Implemented features and bug fixes to the email platform, supporting thousands of newsletters 52 88 - Managed and updated copy and designs on the platformโ€™s marketing website 53 - - Tech Stack: Django, Vue, Next.js, TailwindCSS and more 89 + - Technology Stack: Django, Vue, Next.js, TailwindCSS and more 54 90 55 91 ## Web Developer, SmartWiz [<Icon name="tabler:external-link" class="inline-block" />](https://smartwiz.io) 56 - _September 2023 - November 2024_ 92 + _September 2023 - November 2023_ 57 93 - Refactored existing Stripe integrations and implemented designs from Figma 58 - - Tech Stack: Remix, React, TailwindCSS, Stripe, and more 94 + - Technology Stack: Remix, React, TailwindCSS, Stripe, and more 95 + 96 + <hr /> 59 97 60 98 ## Volunteer Web Developer, Progressive Victory [<Icon name="tabler:external-link" class="inline-block" />](https://progressivevictory.win) 61 99 _August 2022 - November 2022_ 62 100 - Led the frontend development of the initial organization website, implementing designs in coordination with organizers and backend engineers 63 101 - Implemented Airtable as a CMS to display information about volunteer efforts and political candidatesโ€™ campaigns throughout the United States 64 - - Tech Stack: React, Next.js, Airtable, Storybook, Vercel and more 65 - 66 - # Public Speaking and Community Participation 67 - ## Web Dev Challenge: Build a multiplayer web app using PartyKit 68 - - 24k+ views on YouTube 69 - - 18 stars on the typer99 GitHub repository 70 - - Built a type racing game with powerups and obstacles, implementing PartyKit into a SvelteKit application 71 - 72 - ## Upcoming Web Dev Challenge (Set to release late November as a Thanksgiving episode) 73 - - Built an AI generated thank you note that can be shared on X (formerly Twitter) for each library listed in a given repository's SBOM (software bill of materials) 74 - - Sponsored by Google Gemini AI and is integrated into the project, all of which was built in 4 hours 75 - - Participated alongside Jason Lengstorf (host), Brian Holt (Neon DB), and Sarah aka badcop_ (prev Boot.dev) 76 - - Recorded live in studio by a professional camera and sound crew throughout a 12 hour production day 102 + - Technology Stack: React, Next.js, Airtable, Storybook, Vercel and more
-92
src/content/blog/indexed-1.mdx
··· 1 - --- 2 - title: "This is HTML: Indexed - Web Development Explained" 3 - description: An overview on what HTML is and how to use them while making websites. Part 1 of the Indexed - Web Development Explained series. 4 - date: 01-06-2024 5 - draft: false 6 - --- 7 - import CodePreview from "../../components/CodePreview.astro"; 8 - 9 - ## Elements, Tags, and the Properties Within 10 - 11 - HTML is the programming language used to layout the content inside a webpage. Writing in HTML involves using 12 - elements, also known as tags (throughout the series, I will be using these interchangeably), and putting them in 13 - order for your design. 14 - 15 - Most tags are used in twos, both with angle brackets with the type inside, with the ending tag's type starting 16 - with a slash. Between the two is where we'd put content, which can also include more elements. Some elements, 17 - like `<img />`, are what's called "self-closing tags", denoted with the slash at the end. 18 - 19 - <CodePreview> 20 - <div slot="preview"> 21 - <h2>An error has occurred??</h2> 22 - <img src="https://media.giphy.com/media/ltx2rcXk8sE4OCHnFB/giphy.gif" /> 23 - </div> 24 - <div slot="code"> 25 - ```html 26 - <div> 27 - <h2>An error has occurred??</h2> 28 - <img src="https://media.giphy.com/media/ltx2rcXk8sE4OCHnFB/giphy.gif" /> 29 - </div> 30 - ``` 31 - </div> 32 - </CodePreview> 33 - 34 - We can 35 - configure tags like these with its properties, or "props" for short. For example, to have this image tag to show a 36 - picture, we'll set its `src` property a link, as well as state an alternate text to make it accessible to those 37 - hard of seeing. 38 - 39 - ## So Common You Should Memorize Them 40 - 41 - Mozilla Developer Network (MDN), a definitive web development resource online, has a list of all HTML tags. All in 42 - all, there are 142 elements, 115 of which are functional today with the rest being deprecated. Now you 43 - aren't expected to learn every single tag, but when you make enough websites there will be elements that 44 - comes up often. 45 - 46 - Here's my list of tags I use everyday: 47 - 48 - - `<div>`, `<section>`, `<main>`: containers to label off parts of the page. I use `<main>` for the page's 49 - content, `<section>` when there's a defined part (like the code preview above), and `<div>` when I need 50 - to group elements, but don't need to label them, usually for layout and styling reasons. 51 - - `<h1>`->`<h6>`, `<p>`: headers and paragraph text elements. These come with default styles, 52 - but since I use TailwindCSS, they all look the same. No matter how they look, they do help me 53 - distinguish between a wall of text and something to highlight. 54 - - `<img>`: images (and gifs)! Make sure to use the `alt` prop to describe the image to those who might 55 - need to use screen users. Accessibility is great! 56 - - `<input>`, `<button>`: interactive elements, connect these with a `<form>` or script function to 57 - allow people to use your websites. 58 - - `<a>`: the link tag. Go to another page (either on the same website or another on the internet) by 59 - adding the link as its `href` prop. 60 - 61 - There are plenty more that I'm missing as I rattle these off at the top of my head. I memorize these since 62 - I use these everyday no matter the kind of website I'm creating, but if there's anything I need that I 63 - don't remember (for example `<video>` or `<track>`), MDN and Google are always there for me. 64 - 65 - 66 - ## Just the beginning 67 - 68 - HTML can only get you so far. Over the years, a lot of functionality has been baked into these elements. 69 - A recent example can be seen with the `<dialog>` tag that makes modals native to the browser, a feature 70 - that's been in use for decades before and practically only available in Javascript packages and frameworks. 71 - 72 - With that in mind, dialogs and buttons can't work without some scripting, so in the next part of the 73 - Indexed series, we'll start to take a look at the basics of Javascript ("JS") and how to use them 74 - with HTML. First up is using vanilla JS, before moving onto JS UI frameworks that are popular today, 75 - like React and Svelte. 76 - 77 - ## Thanks for reading 78 - 79 - Indexed is a series to write down all I've learned about web development. Think of this as my notebook 80 - scribbled with tips and lessons about how I think about websites. We'll see if I can make one of these 81 - blogs every week. 82 - 83 - Thatโ€™s in the future though! For now, Iโ€™d like to thank you for reading this blog. 84 - I very much appreciate it, and if you can do me a favor, take a look at the links down below. 85 - Catch you in the next one! 86 - 87 - ## Shameless Plugs 88 - 89 - - If you'd like to look at any of my code, they are all open sourced on my Github [here](https://github.com/zeucapua). 90 - - Most of my projects are made live on my Twitch stream! Code new projects with me weekly on [twitch.tv/zeu_dev](https://twitch.tv/zeu_dev). 91 - - Any comments or questions can reach me on Twitter. Follow me at [twitter.com/zeu_dev](https://twitter.com/zeu_dev). 92 - - Interested on other stuff? Visit my personal website at [zeu.dev](https://zeu.dev) and my other blogs here on [thoughts.zeu.dev](https://thoughts.zeu.dev).
-100
src/content/blog/rash-stack.md
··· 1 - --- 2 - title: "The RASH Stack: React, Astro, Svelte, HTMX" 3 - description: Strap a horse on a rocket and use Astro Partials to stream UI components via HTMX. 4 - date: "2024-09-10" 5 - draft: true 6 - link: https://github.com/zeucapua/ 7 - --- 8 - 9 - ## The Project 10 - 11 - I'm building a Notion-like note taking system that'll (probably) make me more productive with as 12 - little fluff and features as possible. Each block can be added, edited, and deleted freely, with 13 - the full page data is saved locally. 14 - 15 - For the features to demo the RASH stack, we are making: 16 - - Plain text (Astro + HTMX) 17 - - Checkbox (Svelte) 18 - - Whiteboard (React via tldraw library) 19 - 20 - ## What is HTMX? 21 - 22 - The basic idea behind HTMX is that APIs should return HTML that shows the updated part of the page 23 - after a request. For example, let's make a button that adds our feature, simple plain text input: 24 - 25 - ```html 26 - <h1>Hodgepodge App</h1> 27 - <ul id="blocks"> 28 - 29 - </ul> 30 - 31 - <button 32 - hx-post="/addTextBlock" 33 - hx-target="#blocks" 34 - hx-swap="beforeend" 35 - > 36 - Text 37 - </button> 38 - ``` 39 - 40 - The button has a few new attributes to use HTMX: `hx-post` specifies a `POST` API request 41 - at the endpoint `/addTextBlock`; `hx-target` is to determine what element we want to update; 42 - `hx-swap` tells us how we should handle the HTML after the response, in this case adding the 43 - response before the button. Now the endpoint can return HTML like so... 44 - 45 - ```html 46 - <li><textarea /></li> 47 - ``` 48 - 49 - And on the button press, the initial page will now be: 50 - 51 - ```html 52 - <h1>Hodgepodge App</h1> 53 - <ul id="blocks"> 54 - <li><textarea /></li> 55 - </ul> 56 - 57 - <button 58 - hx-post="/addTextBlock" 59 - hx-target="#blocks" 60 - hx-swap="beforeend" 61 - > 62 - Text 63 - </button> 64 - ``` 65 - 66 - While we will be using more attributes during the rest of the blog, there are plenty more 67 - I can't possibly go over. To find more information on the list of attributes and HTMX in 68 - general, go to [htmx.org](https://htmx.org) or read their book 69 - [Hypermedia Systems](https://hypermedia.systems) which is free online, but you can be cool 70 - like me and get the physical book: 71 - 72 - # TODO: ADD PHOTO OF HYPERMEDIA SYSTEMS 73 - 74 - ## Astro Partials 75 - 76 - Since we are using Astro as our meta framework, we can use its feature **Astro Partials** in 77 - conjunction with HTMX for a smooth developer experience. It allows Astro components inside the 78 - `/src/pages` directory to be easily called via its endpoint and returned as HTML. 79 - 80 - For the example above, the only thing needed is for the Lemon to be in the 81 - `/src/pages/addTextBlock.astro` file with one extra line in the *Component Script* (the code 82 - inside the frontmatter like section ran on the server): 83 - 84 - ```astro 85 - --- 86 - export const partial = true; 87 - --- 88 - <li><textarea /></li> 89 - ``` 90 - 91 - Now we can use this page via HTMX under the `/revealSecret` endpoint, like the example above! 92 - 93 - ## Forms and Values via Astro Partials 94 - 95 - Swapping HTML is all fine and dandy, but if we want to do more, we can leverage existing 96 - hypermedia controls to extend functionality like the `<form>` and `<input>` elements. 97 - 98 - ## Streaming in Client Components as Astro Islands 99 - 100 - ## Using the HTMX Javascript API
+21
src/pages/as-seen-on.astro
··· 1 + --- 2 + import { render } from "astro:content"; 3 + import SiteLayout from "../components/SiteLayout.astro"; 4 + import { getEntry } from "astro:content"; 5 + 6 + const entry = await getEntry("about", "as-seen-on"); 7 + if (!entry) { 8 + throw new Error("Could not find ../content/about/as-seen-on.mdx"); 9 + } 10 + const { Content } = await render(entry); 11 + --- 12 + 13 + <SiteLayout title="zeu.dev"> 14 + <main class="flex flex-col gap-4 px-4 py-8 text-white text-lg"> 15 + <h1 class="text-5xl text-yellow-500 font-bold">As seen on</h1> 16 + 17 + <span class="prose prose-invert prose-yellow lg:prose-xl prose-headings:text-yellow-500"> 18 + <Content /> 19 + </span> 20 + </main> 21 + </SiteLayout>
+3 -3
src/pages/blog/[...slug].astro
··· 7 7 blog : CollectionEntry<'blog'> 8 8 } 9 9 10 + export const prerender = true; 10 11 export const getStaticPaths = (async () => { 11 12 const blogs = await getCollection("blog"); 12 13 return blogs.map((blog: CollectionEntry<"blog">) => { ··· 17 18 }) satisfies GetStaticPaths; 18 19 19 20 const { blog } = Astro.props; 20 - 21 21 const { Content } = await blog.render(); 22 22 --- 23 23 24 - <SiteLayout> 25 - <main class="flex flex-col gap-4 w-full py-8"> 24 + <SiteLayout title={blog.data.title}> 25 + <main class="flex flex-col gap-4 w-full py-8 px-4"> 26 26 <article class="prose prose-invert w-full max-w-6xl prose-code:text-purple-400"> 27 27 <h1 class="text-yellow-500">{blog.data.title}</h1> 28 28 <p class="text-yellow-500">{blog.data.description}</p>
+1 -1
src/pages/blog/index.astro
··· 11 11 12 12 <SiteLayout title="Blogs | zeu.dev"> 13 13 <main class="flex flex-col gap-8 py-8 max-w-3xl"> 14 - <h1 class="text-5xl text-white font-bold">Blog Posts</h1> 14 + <h1 class="text-5xl text-yellow-500 font-bold">Blog Posts</h1> 15 15 16 16 { // @ts-ignore 17 17 blogs.map((blog: any) => <BlogCard {blog} />)
+1 -14
src/pages/index.astro
··· 23 23 </pre> 24 24 <div class="flex flex-col gap-4"> 25 25 <h1 class="text-5xl font-bold text-yellow-500">hey hi hello!</h1> 26 - <h2 class="text-yellow-500 font-medium text-2xl">welcome to my site!</h2> 27 - 28 - <p> 29 - I have plenty of ideas and projects I want to talk to you guys about 30 - and so I made this site to showcase all I've been doing. 31 - </p> 32 - 33 - <p> 34 - updates and showcases will be hosted here, alongside my own thoughts. 35 - </p> 36 - 37 - 38 - <p class="text-yellow-500">- @zeu_dev</p> 39 26 </div> 40 27 41 28 <section class="flex flex-col lg:flex-row gap-8 my-8"> ··· 46 33 47 34 <a href="/resume" class="border-2 rounded-lg w-fit p-4"> 48 35 <h3 class="text-xl text-yellow-500 font-bold">Resume</h3> 49 - <p>Notable professional works</p> 36 + <p>Career and professional work</p> 50 37 </a> 51 38 </section> 52 39 </main>
+4 -1
src/pages/open-source.astro
··· 1 1 --- 2 2 import SiteLayout from "../components/SiteLayout.astro"; 3 3 import { getEntry } from "astro:content"; 4 + 4 5 const entry = await getEntry("about", "open-source"); 5 - 6 + if (!entry) { 7 + throw new Error("Could not find ../content/about/open-source.mdx"); 8 + } 6 9 const { Content } = await entry.render(); 7 10 --- 8 11
+4 -1
src/pages/resume.astro
··· 1 1 --- 2 2 import SiteLayout from "../components/SiteLayout.astro"; 3 3 import { getEntry } from "astro:content"; 4 + 4 5 const entry = await getEntry("about", "resume"); 5 - 6 + if (!entry) { 7 + throw new Error("Could not find ../content/about/resume.mdx"); 8 + } 6 9 const { Content } = await entry.render(); 7 10 --- 8 11
-12
tailwind.config.mjs
··· 1 - /** @type {import('tailwindcss').Config} */ 2 - export default { 3 - content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], 4 - theme: { 5 - extend: { 6 - fontFamily: { 7 - syne: ["SyneMono"] 8 - } 9 - }, 10 - }, 11 - plugins: [require("@tailwindcss/typography")] 12 - }