feat: new website
This commit is contained in:
commit
50c1c47e2b
64 changed files with 2908 additions and 0 deletions
18
src/ui/Layout/Head.ts
Normal file
18
src/ui/Layout/Head.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
const DEFAULT_TITLE = "Dan Finch"
|
||||
|
||||
export default function Head(props: { title: string }, ...contents: Content[]) {
|
||||
return head(
|
||||
meta({ charset: "utf-8" }),
|
||||
meta({
|
||||
name: "viewport",
|
||||
content: "width=device-width, initial-scale=1.0",
|
||||
}),
|
||||
link({
|
||||
rel: "shortcut icon",
|
||||
type: "image/png",
|
||||
href: "/favicon.png",
|
||||
}),
|
||||
title(props.title || DEFAULT_TITLE),
|
||||
contents,
|
||||
)
|
||||
}
|
||||
50
src/ui/Layout/Layout.ts
Normal file
50
src/ui/Layout/Layout.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import Head from "./Head"
|
||||
import background from "assets/background.js?raw"
|
||||
import css98 from "98se.css?url"
|
||||
import Taskbar from "ui/Layout/Taskbar"
|
||||
import Theme from "ui/Layout/Theme"
|
||||
|
||||
export default function Layout(
|
||||
props: { title: string, url: string },
|
||||
...contents: Content[]
|
||||
) {
|
||||
return [
|
||||
doctype.html5,
|
||||
html(
|
||||
Head(props, [
|
||||
link({ rel: "stylesheet", href: css98 }),
|
||||
style(Theme()),
|
||||
]),
|
||||
body(
|
||||
backgroundColor.black,
|
||||
canvas(
|
||||
{ id: "background" },
|
||||
display.block,
|
||||
position.fixed,
|
||||
width("100%"),
|
||||
height("100%"),
|
||||
left(0),
|
||||
top(0),
|
||||
zIndex(-1),
|
||||
),
|
||||
div(
|
||||
display.flex,
|
||||
flexDirection.column,
|
||||
height("100dvh"),
|
||||
nav(
|
||||
height.maxContent,
|
||||
Taskbar({ url: props.url }),
|
||||
),
|
||||
main(
|
||||
flex(1),
|
||||
overflowY.hidden,
|
||||
display.flex,
|
||||
justifyContent.center,
|
||||
contents,
|
||||
)
|
||||
)
|
||||
),
|
||||
script(raw(background)),
|
||||
),
|
||||
]
|
||||
}
|
||||
14
src/ui/Layout/Reset.ts
Normal file
14
src/ui/Layout/Reset.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
export default function Reset() {
|
||||
return [
|
||||
rule("*, *::before, *::after", [boxSizing.borderBox]),
|
||||
rule("*:not(dialog)", [margin(0)]),
|
||||
rule(
|
||||
"input, button, textarea, select",
|
||||
font("inherit"),
|
||||
),
|
||||
rule(
|
||||
"p, h1, h2, h3, h4, h5, h6",
|
||||
overflowWrap.breakWord,
|
||||
),
|
||||
]
|
||||
}
|
||||
101
src/ui/Layout/Taskbar.ts
Normal file
101
src/ui/Layout/Taskbar.ts
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import favicon from "public/favicon.png?url"
|
||||
import linkedin from "public/icons/linkedin.svg?raw"
|
||||
import github from "public/icons/github.svg?raw"
|
||||
import aboutIcon from "public/icons/about.png?url"
|
||||
import experienceIcon from "public/icons/experience.png?url"
|
||||
import projectsIcon from "public/icons/projects.png?url"
|
||||
import techIcon from "public/icons/tech.png?url"
|
||||
|
||||
const vr = hr(height("20px"), margin("0px 2px"))
|
||||
|
||||
export default function Taskbar({ url }: { url: string }) {
|
||||
return div.taskbar.window(
|
||||
textWrapMode.nowrap,
|
||||
overflowX.hidden,
|
||||
margin("10px"),
|
||||
div(
|
||||
display.flex,
|
||||
alignItems.center,
|
||||
gap("2px"),
|
||||
div(
|
||||
display.flex,
|
||||
paddingLeft("4px"),
|
||||
img(
|
||||
{ src: favicon },
|
||||
width("12px"),
|
||||
height("12px"),
|
||||
marginRight("4px"),
|
||||
),
|
||||
div(fontWeight.bold, "Dan Finch"),
|
||||
),
|
||||
vr,
|
||||
a(
|
||||
{ title: "LinkedIn" },
|
||||
{ href: "https://www.linkedin.com/in/danfinch/" },
|
||||
raw(linkedin),
|
||||
),
|
||||
a(
|
||||
{ title: "GitHub" },
|
||||
{ href: "https://github.com/errilaz" },
|
||||
raw(github),
|
||||
),
|
||||
vr,
|
||||
Task({
|
||||
icon: aboutIcon,
|
||||
title: "About",
|
||||
href: "/",
|
||||
active: url === "/",
|
||||
}),
|
||||
Task({
|
||||
icon: projectsIcon,
|
||||
title: "Projects",
|
||||
href: "/projects",
|
||||
active: url === "/projects",
|
||||
}),
|
||||
Task({
|
||||
icon: experienceIcon,
|
||||
title: "Experience",
|
||||
href: "/experience",
|
||||
active: url === "/experience",
|
||||
}),
|
||||
Task({
|
||||
icon: techIcon,
|
||||
title: "Tech",
|
||||
href: "/tech",
|
||||
active: url === "/tech",
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
function Task({
|
||||
icon,
|
||||
title,
|
||||
href,
|
||||
active,
|
||||
}: {
|
||||
icon: string
|
||||
title: Content
|
||||
href?: string
|
||||
active?: boolean
|
||||
}) {
|
||||
return a.button(
|
||||
{ href },
|
||||
active && className("active"),
|
||||
padding("0 4px"),
|
||||
textAlign.left,
|
||||
div(
|
||||
width("100%"),
|
||||
gap("4px"),
|
||||
display.flex,
|
||||
justifyContent.flexStart,
|
||||
img(
|
||||
{ src: icon },
|
||||
width("12px"),
|
||||
height("12px"),
|
||||
marginRight("4px"),
|
||||
),
|
||||
span(title),
|
||||
),
|
||||
)
|
||||
}
|
||||
39
src/ui/Layout/Theme.ts
Normal file
39
src/ui/Layout/Theme.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import Reset from "./Reset"
|
||||
|
||||
export default function Theme() {
|
||||
return [
|
||||
Reset(),
|
||||
$media(
|
||||
"(max-width: 468px)",
|
||||
rule(
|
||||
".taskbar .button",
|
||||
minWidth("unset"),
|
||||
rule("img", display.none),
|
||||
),
|
||||
),
|
||||
rule("a.button", [
|
||||
textDecoration.none,
|
||||
cursor._default,
|
||||
display.flex,
|
||||
alignItems.center,
|
||||
]),
|
||||
rule(h1, fontSize("20px")),
|
||||
rule(h2, fontSize("16px")),
|
||||
rule(ul, paddingInlineStart("30px")),
|
||||
rule.content(
|
||||
textAlign.justify,
|
||||
fontFamily("Arial"),
|
||||
fontSize("14px"),
|
||||
rule(h1, fontSize("28px")),
|
||||
rule(h2, fontSize("20px")),
|
||||
rule(h3, fontSize("14px"),paddingLeft("30px")),
|
||||
rule(aside,
|
||||
float.right,
|
||||
marginLeft("20px"),
|
||||
paddingBottom(0),
|
||||
),
|
||||
rule("p, h1, h2, h3, ul", margin("12px 0")),
|
||||
),
|
||||
rule(iframe, border(0)),
|
||||
]
|
||||
}
|
||||
32
src/ui/Layout/Window.ts
Normal file
32
src/ui/Layout/Window.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
const DEFAULT_WIDTH = "770px"
|
||||
|
||||
export default function Window(
|
||||
props: { title: Content; width?: Content; flat?: boolean },
|
||||
...contents: Content[]
|
||||
) {
|
||||
return article.window(
|
||||
opacity(0.9),
|
||||
marginTop("16px"),
|
||||
marginBottom("24px"),
|
||||
marginLeft("10px"),
|
||||
marginRight("10px"),
|
||||
width(props.width ?? DEFAULT_WIDTH),
|
||||
maxWidth(props.width ?? DEFAULT_WIDTH),
|
||||
display.flex,
|
||||
flexDirection.column,
|
||||
div.titleBar(
|
||||
div.titleBarText(props.title),
|
||||
div.titleBarControls(
|
||||
button({ "aria-label": "Minimize" }),
|
||||
button({ "aria-label": "Maximize" }),
|
||||
button({ "aria-label": "Close" }),
|
||||
),
|
||||
),
|
||||
div.windowBody(
|
||||
props.flat ? null : className("field-border"),
|
||||
flex(1),
|
||||
overflowY.auto,
|
||||
contents,
|
||||
),
|
||||
)
|
||||
}
|
||||
1
src/ui/Layout/index.ts
Normal file
1
src/ui/Layout/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from "./Layout"
|
||||
Loading…
Add table
Add a link
Reference in a new issue