Files for my website bwc9876.dev
at main 230 lines 5.2 kB view raw
1--- 2import { Image, getImage } from "astro:assets"; 3 4import defaultOg from "@assets/default-og.webp"; 5import cow from "@assets/cow.webp"; 6import Socials from "@components/Socials.astro"; 7import IconLink from "@components/IconLink.astro"; 8import "@styles/style.css"; 9import type { ImageMetadata } from "astro"; 10 11export interface Props { 12 title: string; 13 appendTitle?: boolean; 14 description?: string; 15 keywords?: string[]; 16 og?: { 17 src: ImageMetadata; 18 alt: string; 19 }; 20} 21 22const { title, appendTitle, description: oldDescription, keywords, og: oldOg } = Astro.props; 23 24const og = { 25 src: ( 26 await getImage({ 27 src: oldOg?.src ?? defaultOg, 28 format: "webp" 29 }) 30 ).src, 31 alt: oldOg?.alt ?? "Ben C's Profile Picture" 32}; 33 34og.src = `${Astro.url.origin}${og.src}`; 35 36const description = oldDescription ?? "Ben C's software development portfolio"; 37const fullTitle = (appendTitle ?? true) ? `${title} | Ben C` : title; 38const canonical = Astro.url.toString(); 39--- 40 41<!doctype html> 42<html lang="en"> 43 <head> 44 <title>{fullTitle}</title> 45 <meta charset="UTF-8" /> 46 <meta http-equiv="X-UA-Compatible" content="IE=edge" /> 47 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 48 <meta name="description" content={description} /> 49 <meta name="keywords" content={["portfolio"].concat(keywords ?? []).join(", ")} /> 50 <meta name="generator" content={Astro.generator} /> 51 <meta property="og:type" content="website" /> 52 <meta property="og:title" content={fullTitle} /> 53 <meta property="og:description" content={description} /> 54 <meta property="og:url" content={canonical} /> 55 <meta property="og:image" content={og.src} /> 56 <meta property="og:image:alt" content={og.alt} /> 57 <meta name="twitter:title" content={fullTitle} /> 58 <meta name="twitter:description" content={description} /> 59 <meta name="twitter:image" content={og.src} /> 60 <link rel="canonical" href={canonical} /> 61 <link rel="icon" href="/favicon.ico" /> 62 <link 63 rel="alternate" 64 type="application/rss+xml" 65 title="Ben C's Blog" 66 href={new URL("feed.xml", Astro.site)} 67 /> 68 <style is:global> 69 @view-transition { 70 navigation: auto; 71 } 72 </style> 73 </head> 74 <body id="top"> 75 <header class="container"> 76 <nav aria-label="Main navigation"> 77 <a href="/" 78 ><Image 79 class="nav-icon" 80 width={150} 81 height={150} 82 transition:name="pfp" 83 transition:persist 84 format="webp" 85 alt="Ben C's Avatar" 86 src={cow} 87 /> 88 <span style="color: var(--text);"><span class="gradient-text">Bwc9876</span>.dev</span> 89 </a> 90 <span> 91 <a href="/projects">Projects</a> 92 <a href="/blog">Blog</a> 93 <a href="/uses">Uses</a> 94 </span> 95 <Socials labelPlacement="bottom" /> 96 </nav> 97 </header> 98 <main transition:name="main" class="container"> 99 <slot /> 100 </main> 101 <footer transition:name="footer" class="container"> 102 <p> 103 <IconLink 104 label="Back To Top" 105 placement="top" 106 icon="arrow-bar-up" 107 data-tooltip="Back To Top" 108 href="#top" 109 /> 110 </p> 111 <p class="copyright">© Ben C 2026</p> 112 <Socials labelPlacement="top" /> 113 </footer> 114 </body> 115</html> 116 117<style> 118 body { 119 background-color: var(--background); 120 margin: 0; 121 padding: 0; 122 display: flex; 123 flex-direction: column; 124 min-height: 100vh; 125 width: 100vw; 126 overflow-x: hidden; 127 } 128 129 header { 130 border-bottom: var(--section-border); 131 } 132 133 nav { 134 display: flex; 135 gap: var(--1); 136 flex-direction: column; 137 align-items: center; 138 padding: var(--2) 0; 139 } 140 141 nav > :nth-child(3) { 142 display: none; 143 } 144 145 @media (width >= 1050px) { 146 nav { 147 flex-direction: row; 148 } 149 150 nav > :nth-child(3) { 151 display: flex; 152 } 153 } 154 155 nav a { 156 text-decoration: none; 157 158 &:hover { 159 text-decoration: underline; 160 } 161 } 162 163 nav > a:first-child { 164 font-size: var(--2); 165 display: flex; 166 gap: 5px; 167 flex-direction: row; 168 align-items: center; 169 justify-content: center; 170 background-color: var(--secondary); 171 padding: 5px 7px; 172 border-radius: 5px; 173 174 & > span > span { 175 transform: translateY(-2px); 176 } 177 } 178 179 nav > span { 180 display: flex; 181 flex-direction: row; 182 gap: var(--2); 183 } 184 185 nav > span:nth-child(2) { 186 flex-grow: 1; 187 } 188 189 .nav-icon { 190 width: var(--4); 191 height: var(--4); 192 border-radius: 100%; 193 transition: transform 800ms 194 linear( 195 0, 196 0.36 6.7%, 197 0.635 13.9%, 198 0.832 21.8%, 199 0.904 26.1%, 200 0.958 30.6%, 201 1.015 38.6%, 202 1.036 48.1%, 203 1.034 56.4%, 204 1.005 81.2%, 205 1 206 ); 207 208 @starting-style { 209 transform: translateX(calc(-1 * 50vw - var(--5))) rotate(-300deg); 210 } 211 } 212 213 main { 214 flex-grow: 1; 215 } 216 217 footer > p { 218 margin: var(--1); 219 } 220 221 footer { 222 border-top: var(--section-border); 223 margin-top: var(--4); 224 display: flex; 225 flex-direction: column; 226 align-items: center; 227 justify-content: center; 228 padding: var(--2) 0; 229 } 230</style>