Compare commits
5 Commits
54db411930
...
v1.0.0
Author | SHA1 | Date | |
---|---|---|---|
25a38d2f0e
|
|||
e1c3ae7d87
|
|||
22cdc634f9
|
|||
1b3c6c629e
|
|||
ff2f65bf59
|
23
TODO.md
23
TODO.md
@ -1,21 +1,31 @@
|
||||
# TODO
|
||||
|
||||
## Code
|
||||
- [ ] Temporal API or day.js for dates
|
||||
- [ ] day.js for dates
|
||||
- [ ] Nix Shell
|
||||
|
||||
## SSE
|
||||
- [x] Correct Sitemap.xml
|
||||
- [x] Correct robots.txt
|
||||
- [x] Correct security.txt
|
||||
|
||||
## Layout
|
||||
- [ ] Show current page in navbar
|
||||
- [x] Show current page
|
||||
- [x] Correct bg colour on entire page
|
||||
- [x] Hamburger menu on mobile
|
||||
- [ ] Dark mode toggle
|
||||
- [ ] Navigate using pathname / breadcrumbs
|
||||
|
||||
## Accessibility
|
||||
- [ ] Fix colours on buttons
|
||||
- [ ] Correct contrast
|
||||
- [x] Fix colours on buttons
|
||||
- [x] Correct contrast
|
||||
- [ ] All interactable elements have labels
|
||||
- [ ] Colour links, also in MDX posts
|
||||
- [x] Colour links, also in MDX posts
|
||||
|
||||
## ~/
|
||||
- [ ] About me description
|
||||
- [ ] Non-cat image
|
||||
- [x] Latest projects
|
||||
- [x] Non-cat image
|
||||
|
||||
## ~/about
|
||||
- [ ] About me
|
||||
@ -23,6 +33,7 @@
|
||||
## ~/links
|
||||
- [ ] Add Bluesky link
|
||||
- [ ] Add MusicBrainz link
|
||||
- [ ] Add Archidekt link
|
||||
|
||||
## ~/slashes
|
||||
- [ ] List of all slashes
|
||||
|
@ -10,13 +10,13 @@ import icon from "astro-icon"
|
||||
|
||||
import { loadEnv } from "vite"
|
||||
|
||||
const { url } = process.env.URL
|
||||
? loadEnv(process.env.URL, process.cwd(), "")
|
||||
: { url: "http://localhost:3000" }
|
||||
const { URL } = process.env.NODE_ENV
|
||||
? loadEnv(process.env.NODE_ENV, process.cwd(), "")
|
||||
: { URL: "http://localhost:3000" }
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: url,
|
||||
site: URL,
|
||||
output: "server",
|
||||
i18n: {
|
||||
defaultLocale: "nb",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"$schema": "https://inlang.com/schema/inlang-message-format",
|
||||
"hiIm": "Hei, jeg er",
|
||||
"position": "Programvareutvikler",
|
||||
"aboutMe": "Engasjert utvikler som for tiden jobber hos Capgemini Bergen",
|
||||
"aboutMe": "Engasjert utvikler som for tiden jobber hos Capgemini Bergen.",
|
||||
"home": "Hjem",
|
||||
"contactMe": "Kontakt meg",
|
||||
"myLinks": "Mine lenker",
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "martials-no-v2",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
|
@ -4,8 +4,9 @@ import * as m from "@/paraglide/messages.js"
|
||||
// TODO self-host email server
|
||||
---
|
||||
|
||||
<div class="max-w-[500px] mx-auto">
|
||||
<form
|
||||
class="flex flex-col gap-2 max-w-[500px] mx-auto"
|
||||
class="flex flex-col gap-2 w-full"
|
||||
method="post"
|
||||
action="https://formspree.io/f/mknykgbn"
|
||||
>
|
||||
@ -16,8 +17,15 @@ import * as m from "@/paraglide/messages.js"
|
||||
<input name="_gotcha" type="text" class={"hidden"} />
|
||||
<label class="flex flex-col">
|
||||
{m.message()}
|
||||
<textarea name="message" class="textarea textarea-bordered w-full" required
|
||||
></textarea>
|
||||
<textarea
|
||||
name="message"
|
||||
class="textarea textarea-bordered w-full bg-cat-base"
|
||||
required></textarea>
|
||||
</label>
|
||||
</form>
|
||||
<button type="submit" class="btn mt-2" title={m.send()}>{m.send()}</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn mt-2 bg-cat-base border-cat-surface0"
|
||||
title={m.send()}>{m.send()}</button
|
||||
>
|
||||
</div>
|
||||
|
@ -11,11 +11,15 @@ const giteaLink = `${GIT_URL}/martials/martials.no`
|
||||
|
||||
<div class="divider bg-inherit"></div>
|
||||
<div
|
||||
class="py-5 flex flex-row gap-1 justify-around w-full items-center bg-inherit"
|
||||
class="max-w-[1000px] sm:min-w-[500px] mx-auto py-5 flex flex-row flex-wrap gap-5 justify-around items-center bg-inherit px-5"
|
||||
>
|
||||
<div>
|
||||
<GiteaLink href={giteaLink} />
|
||||
<ExternalLink href={STATUS_URL} class="flex items-center" title="Status">
|
||||
<GiteaLink href={giteaLink} class="!text-cat-text" />
|
||||
<ExternalLink
|
||||
href={STATUS_URL}
|
||||
class="flex items-center !text-cat-text"
|
||||
title="Status"
|
||||
>
|
||||
<PajamasIcon
|
||||
name="pajamas:status-health"
|
||||
class="w-6 h-6 mr-2"
|
||||
|
@ -16,10 +16,10 @@ const {
|
||||
} = Astro.props
|
||||
---
|
||||
|
||||
<label class="flex flex-col">
|
||||
<label class="flex flex-col w-full">
|
||||
{label}
|
||||
<input
|
||||
class="input input-bordered w-full"
|
||||
class="input input-bordered w-full bg-cat-base"
|
||||
type={type}
|
||||
name={name}
|
||||
required={required}
|
||||
|
@ -2,14 +2,26 @@
|
||||
import LocaleLink from "./links/LocaleLink.astro"
|
||||
import { type NavLink, resolvePathname } from "@/utils/linking"
|
||||
|
||||
const currentPath = resolvePathname(Astro.url.pathname)
|
||||
const pathname = Astro.url.pathname
|
||||
const currentPath = resolvePathname(pathname)
|
||||
const isEnglish = pathname.startsWith("/en")
|
||||
---
|
||||
|
||||
<div class="join">
|
||||
<LocaleLink to={currentPath as NavLink} lang="nb" class="btn join-item"
|
||||
>Norsk</LocaleLink
|
||||
<LocaleLink
|
||||
to={currentPath as NavLink}
|
||||
lang="nb"
|
||||
class:list={[
|
||||
"btn join-item !text-cat-text border-cat-surface0",
|
||||
!isEnglish ? "bg-cat-mantle" : "bg-cat-base",
|
||||
]}>Norsk</LocaleLink
|
||||
>
|
||||
<LocaleLink to={currentPath as NavLink} lang="en" class="btn join-item"
|
||||
>English</LocaleLink
|
||||
<LocaleLink
|
||||
to={currentPath as NavLink}
|
||||
lang="en"
|
||||
class:list={[
|
||||
"btn join-item !text-cat-text border-cat-surface0",
|
||||
isEnglish ? "bg-cat-mantle" : "bg-cat-base",
|
||||
]}>English</LocaleLink
|
||||
>
|
||||
</div>
|
||||
|
@ -1,5 +1,4 @@
|
||||
---
|
||||
import Select from "./Select.svelte"
|
||||
import * as m from "@/paraglide/messages"
|
||||
import CollapseList from "@/components/collapse/CollapseList.svelte"
|
||||
import type { CollectionEntry } from "astro:content"
|
||||
|
@ -7,6 +7,6 @@ interface Props {
|
||||
const { tags } = Astro.props
|
||||
---
|
||||
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<div class="flex flex-wrap gap-1 py-0.5">
|
||||
{tags.map((tag) => <Badge tag={tag} />)}
|
||||
</div>
|
||||
|
17
src/components/header/HamburgerMenuButton.astro
Normal file
17
src/components/header/HamburgerMenuButton.astro
Normal file
@ -0,0 +1,17 @@
|
||||
---
|
||||
import PajamasIcon from "@/components/icons/PajamasIcon.astro"
|
||||
|
||||
interface Props {
|
||||
id: string
|
||||
}
|
||||
|
||||
const { id } = Astro.props
|
||||
---
|
||||
|
||||
<label for={id} aria-label="open sidebar" class="btn btn-square btn-ghost">
|
||||
<PajamasIcon
|
||||
name="pajamas:hamburger"
|
||||
class="w-6 h-6"
|
||||
aria-label="Hamburger menu"
|
||||
/>
|
||||
</label>
|
@ -1,7 +1,38 @@
|
||||
---
|
||||
import Navbar from "./Navbar.astro"
|
||||
import NavbarDrawer from "./NavbarDrawer.astro"
|
||||
import HamburgerMenuButton from "./HamburgerMenuButton.astro"
|
||||
import { resolvePathname } from "@/utils/linking"
|
||||
|
||||
const currentPath = `~${resolvePathname(Astro.originPathname)}`
|
||||
---
|
||||
|
||||
<div class="m-auto">
|
||||
<div class="sm:m-auto">
|
||||
<div class="drawer drawer-end">
|
||||
<input id="my-drawer-3" type="checkbox" class="drawer-toggle" />
|
||||
<div class="drawer-content flex flex-col">
|
||||
<!-- Navbar -->
|
||||
<div class="navbar w-full justify-end">
|
||||
<div class="flex justify-between items-center w-full h-full sm:hidden">
|
||||
<h1 class="!text-2xl h-5">
|
||||
{currentPath}
|
||||
</h1>
|
||||
<HamburgerMenuButton id="my-drawer-3" />
|
||||
</div>
|
||||
<div class="hidden flex-none sm:block">
|
||||
<Navbar />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="drawer-side z-50">
|
||||
<label for="my-drawer-3" aria-label="close sidebar" class="drawer-overlay"
|
||||
></label>
|
||||
<ul class="menu bg-cat-base min-h-full w-80 p-4">
|
||||
<li class="text-xl font-bold my-5">
|
||||
{currentPath}
|
||||
</li>
|
||||
<NavbarDrawer />
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -8,7 +8,7 @@ import Links from "@/links"
|
||||
Links.map(({ to, label }) => (
|
||||
<LocaleLink
|
||||
to={to}
|
||||
class={"m-2 hover:text-cat-mauve font-bold font-mono"}
|
||||
class={"m-2 not-hover:!text-cat-text font-bold font-mono"}
|
||||
>
|
||||
~/{label()}
|
||||
</LocaleLink>
|
||||
|
12
src/components/header/NavbarDrawer.astro
Normal file
12
src/components/header/NavbarDrawer.astro
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
import Links from "../../links"
|
||||
import LocaleLink from "../links/LocaleLink.astro"
|
||||
---
|
||||
|
||||
{
|
||||
Links.map((link) => (
|
||||
<li>
|
||||
<LocaleLink to={link.to}>{link.label}</LocaleLink>
|
||||
</li>
|
||||
))
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
import { Image } from "astro:assets"
|
||||
import me from "@/images/polite-cat.jpg"
|
||||
import me from "@/images/me.jpg"
|
||||
import * as m from "@/paraglide/messages.js"
|
||||
import "@/styles/global.css"
|
||||
---
|
||||
@ -18,10 +18,10 @@ import "@/styles/global.css"
|
||||
</div>
|
||||
<Image
|
||||
src={me}
|
||||
alt="Me on a hike"
|
||||
alt="Me on a stand in front of a poster that says 'anbudsassistent'"
|
||||
width="400"
|
||||
height="400"
|
||||
class="p-5 mx-auto"
|
||||
class="p-5 mx-auto rounded-full"
|
||||
loading={"eager"}
|
||||
/>
|
||||
</div>
|
7
src/components/landing/IndexPage.astro
Normal file
7
src/components/landing/IndexPage.astro
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
import Greeting from "./Greeting.astro"
|
||||
import LatestProjects from "./LatestProjects.astro"
|
||||
---
|
||||
|
||||
<Greeting />
|
||||
<LatestProjects />
|
10
src/components/landing/LatestProjects.astro
Normal file
10
src/components/landing/LatestProjects.astro
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
import { getCollection } from "astro:content"
|
||||
import ProjectGrid from "@/components/projects/ProjectGrid.astro"
|
||||
|
||||
const projects = await getCollection("projects")
|
||||
---
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<ProjectGrid projects={projects} />
|
@ -9,11 +9,10 @@ interface Props extends MyLink {
|
||||
|
||||
const { title, message, url, icon, class: clazz } = Astro.props
|
||||
const iconStyle = "w-6 h-6"
|
||||
console.log(icon)
|
||||
---
|
||||
|
||||
<ExternalLink href={url} noStyle>
|
||||
<div class:list={["card bg-base-300", clazz]}>
|
||||
<div class:list={["card bg-cat-mantle text-cat-text", clazz]}>
|
||||
<div class="card-body p-5 flex flex-row items-center">
|
||||
{
|
||||
icon ? (
|
||||
|
@ -1,33 +1,12 @@
|
||||
---
|
||||
import ProjectCard from "./ProjectCard.astro"
|
||||
import * as m from "@/paraglide/messages"
|
||||
import ProjectGrid from "./ProjectGrid.astro"
|
||||
import { type CollectionEntry } from "astro:content"
|
||||
import { type NavLink } from "@/utils/linking"
|
||||
|
||||
interface Props {
|
||||
projects: CollectionEntry<"projects">[]
|
||||
}
|
||||
|
||||
const { projects } = Astro.props
|
||||
|
||||
const baseUrl: NavLink = "/projects"
|
||||
---
|
||||
|
||||
<div class="flex flex-wrap justify-around">
|
||||
{
|
||||
projects.map(
|
||||
({ data: { title, description, tags, heroImage, heroImageAlt }, id }) => (
|
||||
<div class="my-5 px-2">
|
||||
<ProjectCard
|
||||
title={title}
|
||||
linkTo={`${baseUrl}/${id}`}
|
||||
description={description}
|
||||
tags={tags}
|
||||
image={heroImage}
|
||||
imageAlt={heroImageAlt}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<ProjectGrid projects={projects} />
|
||||
|
@ -19,12 +19,13 @@ const { title, description, tags, image, imageAlt, linkTo } = Astro.props
|
||||
|
||||
<LocaleLink
|
||||
to={linkTo}
|
||||
class="card bg-cat-base max-w-96 shadow-xl hover:scale-105 transition"
|
||||
class="card bg-cat-base max-w-96 shadow-xl hover:scale-105 transition border border-cat-surface0"
|
||||
>
|
||||
<figure>
|
||||
<Image src={image} alt={imageAlt} />
|
||||
<figcaption class="sr-only">{imageAlt}</figcaption>
|
||||
</figure>
|
||||
<div class="card-body">
|
||||
<div class="card-body text-cat-text">
|
||||
<h2 class="card-title">
|
||||
{title}
|
||||
</h2>
|
||||
|
32
src/components/projects/ProjectGrid.astro
Normal file
32
src/components/projects/ProjectGrid.astro
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
import type { Project } from "@/types/types"
|
||||
import type { NavLink } from "@/utils/linking"
|
||||
import ProjectCard from "./ProjectCard.astro"
|
||||
|
||||
interface Props {
|
||||
projects: ReadonlyArray<Project>
|
||||
}
|
||||
|
||||
const { projects } = Astro.props
|
||||
|
||||
const baseUrl: NavLink = "/projects"
|
||||
---
|
||||
|
||||
<div class="flex flex-wrap justify-around">
|
||||
{
|
||||
projects.map(
|
||||
({ data: { title, description, tags, heroImage, heroImageAlt }, id }) => (
|
||||
<div class="my-5 px-2">
|
||||
<ProjectCard
|
||||
title={title}
|
||||
linkTo={`${baseUrl}/${id}`}
|
||||
description={description}
|
||||
tags={tags}
|
||||
image={heroImage}
|
||||
imageAlt={heroImageAlt}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
)
|
||||
}
|
||||
</div>
|
@ -1,11 +1,11 @@
|
||||
---
|
||||
import Layout from "@/layouts/Layout.astro"
|
||||
import { Image } from "astro:assets"
|
||||
import { getEntry, render } from "astro:content"
|
||||
import BadgeList from "@/components/badge/BadgeList.astro"
|
||||
import * as m from "@/paraglide/messages"
|
||||
import { languageTag } from "@/paraglide/runtime"
|
||||
import GiteaLink from "@/components/links/GiteaLink.astro"
|
||||
import { languageTag } from "@/paraglide/runtime"
|
||||
import { getEntry, render } from "astro:content"
|
||||
import { Image } from "astro:assets"
|
||||
import * as m from "@/paraglide/messages"
|
||||
import "@/styles/global.css"
|
||||
|
||||
interface Props {
|
||||
@ -32,7 +32,7 @@ const {
|
||||
<Layout title={title} class="mx-auto max-w-[750px]">
|
||||
<div class="flex justify-between my-2">
|
||||
<div>
|
||||
<h1>{title}</h1>
|
||||
<h2>{title}</h2>
|
||||
<BadgeList tags={tags} />
|
||||
</div>
|
||||
<div class="flex flex-col items-end">
|
||||
@ -46,7 +46,7 @@ const {
|
||||
</div>
|
||||
<Image src={heroImage} alt={heroImageAlt} class="m-auto" />
|
||||
|
||||
<GiteaLink href={source} class="text-cat-mauve my-2" />
|
||||
<GiteaLink href={source} class="my-2" />
|
||||
|
||||
<p class="my-2">{description}</p>
|
||||
<Content />
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: "Hjemmeside"
|
||||
title: "Welcome"
|
||||
description: "Welcome to my homepage / portfolio"
|
||||
heroImage: "assets/recursive-meme.png"
|
||||
heroImageAlt: "A recursive meme that says: Self-reference, recursive meme is self-referential"
|
||||
|
BIN
src/images/me.jpg
Normal file
BIN
src/images/me.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 KiB |
@ -9,7 +9,8 @@ interface Props {
|
||||
class?: string
|
||||
}
|
||||
const { title, class: clazz } = Astro.props
|
||||
const mainClass = "grow max-w-[1000px] m-auto sm:min-w-[500px] mt-5"
|
||||
const mainClass =
|
||||
"grow max-w-[1000px] m-auto sm:min-w-[500px] not-sm:w-full px-5"
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
@ -26,8 +27,12 @@ const mainClass = "grow max-w-[1000px] m-auto sm:min-w-[500px] mt-5"
|
||||
<body class="flex flex-col min-h-screen bg-cat-base text-cat-text">
|
||||
<Header />
|
||||
<main class:list={[mainClass, clazz]}>
|
||||
<h1 class="text-center">~{resolvePathname(Astro.originPathname)}</h1>
|
||||
<h1 class="text-center not-sm:hidden">
|
||||
~{resolvePathname(Astro.originPathname)}
|
||||
</h1>
|
||||
<div class="my-5">
|
||||
<slot />
|
||||
</div>
|
||||
</main>
|
||||
<Footer />
|
||||
</body>
|
||||
|
@ -1,9 +1,9 @@
|
||||
---
|
||||
import OnePager from "../../components/Greeting.astro"
|
||||
import Layout from "../../layouts/Layout.astro"
|
||||
import IndexPage from "@/components/landing/IndexPage.astro"
|
||||
import Layout from "@/layouts/Layout.astro"
|
||||
import "@/styles/global.css"
|
||||
---
|
||||
|
||||
<Layout title="Welcome">
|
||||
<OnePager />
|
||||
<IndexPage />
|
||||
</Layout>
|
||||
|
@ -7,11 +7,7 @@ import "@/styles/global.css"
|
||||
export const prerender = true
|
||||
|
||||
export function getStaticPaths(): GetStaticPathsResult {
|
||||
return [
|
||||
{ params: { project: "hvl-ics-simplifier" } },
|
||||
{ params: { project: "homepage" } },
|
||||
{ params: { project: "simplify-truths" } },
|
||||
]
|
||||
return [{ params: { project: "homepage" } }]
|
||||
}
|
||||
|
||||
const { project } = Astro.params
|
||||
|
@ -1,10 +1,9 @@
|
||||
---
|
||||
import IndexPage from "@/components/landing/IndexPage.astro"
|
||||
import Layout from "@/layouts/Layout.astro"
|
||||
import Greeting from "@/components/Greeting.astro"
|
||||
|
||||
// https://slashpages.net/
|
||||
import "@/styles/global.css"
|
||||
---
|
||||
|
||||
<Layout title="Velkommen">
|
||||
<Greeting />
|
||||
<IndexPage />
|
||||
</Layout>
|
||||
|
@ -7,11 +7,7 @@ import "@/styles/global.css"
|
||||
export const prerender = true
|
||||
|
||||
export function getStaticPaths(): GetStaticPathsResult {
|
||||
return [
|
||||
{ params: { project: "hvl-ics-simplifier" } },
|
||||
{ params: { project: "homepage" } },
|
||||
{ params: { project: "simplify-truths" } },
|
||||
]
|
||||
return [{ params: { project: "homepage" } }]
|
||||
}
|
||||
|
||||
const { project } = Astro.params
|
||||
|
@ -48,6 +48,6 @@ h3 {
|
||||
|
||||
/* TODO change default style*/
|
||||
a {
|
||||
@apply link;
|
||||
@apply link text-cat-mauve;
|
||||
text-decoration-line: none;
|
||||
}
|
||||
|
@ -9,5 +9,6 @@ export type Icon =
|
||||
| "linkedin"
|
||||
| "link"
|
||||
| "status-health"
|
||||
| "hamburger"
|
||||
|
||||
export type PajamasIcon = `pajamas:${Icon}`
|
||||
|
Reference in New Issue
Block a user