diff --git a/astro.config.mjs b/astro.config.mjs index 6bcb407..2d6f9c1 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -47,6 +47,9 @@ export default defineConfig({ "clock-outline", "apple", "google-play", + "code-braces", + "circle", + "open-in-new", ], "simple-icons": [ "gitea", diff --git a/src/components/PostCard.astro b/src/components/PostCard.astro deleted file mode 100644 index 654adbb..0000000 --- a/src/components/PostCard.astro +++ /dev/null @@ -1,65 +0,0 @@ ---- -import type { CollectionEntry } from "astro:content"; -import { Icon } from "astro-icon/components"; -export interface Props { - post: CollectionEntry<"posts">; -} - -const { post } = Astro.props; -const { title, description: blurb, pubDate } = post.data; -const { slug } = post; ---- - -
-
-

- {title} -

- -

- {blurb || "No description available."} -

- -
- - - { - new Date(pubDate).toLocaleDateString("en-us", { - month: "long", - day: "numeric", - year: "numeric", - }) - } - -
- - { - post.data.tags && post.data.tags.length > 0 && ( -
- {post.data.tags.map((tag: string) => ( -
- - {tag} -
- ))} -
- ) - } - -
- - - -
-
-
diff --git a/src/components/ProjectCard.astro b/src/components/ProjectCard.astro deleted file mode 100644 index 1700e78..0000000 --- a/src/components/ProjectCard.astro +++ /dev/null @@ -1,137 +0,0 @@ ---- -import { Icon } from "astro-icon/components"; -import type { Project } from "../types"; -import { formatRelativeTime } from "../utils/gitea"; - -interface Props { - project: Project; -} - -const { project } = Astro.props; ---- - -
-
-

- {project.name} -

- -

- {project.description} -

- - { - project.giteaInfo && - (project.giteaInfo.languages.length > 0 || - project.giteaInfo.updatedAt) && ( - <> -
-
- {project.giteaInfo.languages.map( - (language: string) => ( -
- - {language} -
- ), - )} - {project.giteaInfo.updatedAt && ( -
- - {formatRelativeTime( - project.giteaInfo.updatedAt, - )} -
- )} -
- - ) - } - - { - project.giteaInfo?.topics && - project.giteaInfo.topics.length > 0 && ( - <> -
-
- {project.giteaInfo.topics.map((tag: string) => ( -
- - {tag} -
- ))} -
- - ) - } - -
- { - project.webLink && ( - - - Website - - ) - } - { - project.gitLink && ( - - - Source - - ) - } - { - project.iosLink && ( - - - iOS - - ) - } - { - project.androidLink && ( - - - Android - - ) - } -
-
-
diff --git a/src/components/ProjectsIsland.astro b/src/components/ProjectsIsland.astro index b52aa86..faa1b71 100644 --- a/src/components/ProjectsIsland.astro +++ b/src/components/ProjectsIsland.astro @@ -1,7 +1,7 @@ --- -import ProjectCard from "./ProjectCard.astro"; +import { Icon } from "astro-icon/components"; import { config } from "../config"; -import { fetchGiteaInfoFromUrl } from "../utils/gitea"; +import { fetchGiteaInfoFromUrl, formatRelativeTime } from "../utils/gitea"; import type { Project } from "../types"; Astro.response.headers.set( @@ -48,27 +48,92 @@ const sortedProjects = projectsWithGiteaInfo.sort((a, b) => { }); --- -
+
    { sortedProjects.map((project) => ( -
    - -
    +
  • + {/* Project icon/avatar */} +
    +
    + +
    +
    + + {/* Main content */} +
    +
    +

    {project.name}

    + {project.giteaInfo?.updatedAt && ( + + {formatRelativeTime(project.giteaInfo.updatedAt)} + + )} +
    + +

    {project.description}

    + + {/* Languages & Topics */} +
    + {project.giteaInfo?.languages?.slice(0, 3).map((lang: string) => ( + {lang} + ))} + {project.giteaInfo?.topics?.slice(0, 4).map((topic: string) => ( + {topic} + ))} +
    +
    + + {/* Action buttons */} +
    + {project.webLink && ( + + + + )} + {project.gitLink && ( + + + + )} + {project.iosLink && ( + + + + )} + {project.androidLink && ( + + + + )} +
    +
  • )) } -
+ { sortedProjects.length === 0 && ( diff --git a/src/components/ProjectsLoader.astro b/src/components/ProjectsLoader.astro index fab146d..fd8844c 100644 --- a/src/components/ProjectsLoader.astro +++ b/src/components/ProjectsLoader.astro @@ -1,46 +1,7 @@ --- -const skeletonCount = 6; ---- -
- { - Array.from({ length: skeletonCount }).map((_, i) => ( -
-
-
+--- -
-
-
-
- -
- -
-
-
-
- -
-
-
-
- -
- -
-
-
-
-
- -
-
-
-
-
- )) - } +
+
diff --git a/src/components/TalkCard.astro b/src/components/TalkCard.astro deleted file mode 100644 index 3c4e0fd..0000000 --- a/src/components/TalkCard.astro +++ /dev/null @@ -1,49 +0,0 @@ ---- -import { Icon } from "astro-icon/components"; -import type { Talk } from "../types"; - -interface Props { - talk: Talk; -} - -const { talk } = Astro.props; ---- - -
-
-

- {talk.name} -

- -

- {talk.description} -

- -
- { - talk.date && ( -
- Date: - {talk.date} -
- ) - } -
- -
- - - -
-
-
diff --git a/src/pages/posts.astro b/src/pages/posts.astro index 789edda..ec36a5b 100644 --- a/src/pages/posts.astro +++ b/src/pages/posts.astro @@ -1,7 +1,7 @@ --- import Layout from "../layouts/Layout.astro"; import { getCollection, type CollectionEntry } from "astro:content"; -import PostCard from "../components/PostCard.astro"; +import { Icon } from "astro-icon/components"; // Get all posts from the content collection const posts = await getCollection("posts"); @@ -11,6 +11,14 @@ const sortedPosts = posts.sort( (a: CollectionEntry<"posts">, b: CollectionEntry<"posts">) => new Date(b.data.pubDate).valueOf() - new Date(a.data.pubDate).valueOf(), ); + +function formatDate(date: Date): string { + return date.toLocaleDateString("en-us", { + month: "short", + day: "numeric", + year: "numeric", + }); +} --- @@ -20,27 +28,98 @@ const sortedPosts = posts.sort( > Posts -
+ + {/* Mobile: One-sided compact timeline */} +
+ + + {/* Desktop: Dual-sided alternating timeline */} + { sortedPosts.length === 0 && ( diff --git a/src/pages/talks.astro b/src/pages/talks.astro index 5f595e5..b0bc3ed 100644 --- a/src/pages/talks.astro +++ b/src/pages/talks.astro @@ -1,7 +1,21 @@ --- import Layout from "../layouts/Layout.astro"; -import TalkCard from "../components/TalkCard.astro"; +import { Icon } from "astro-icon/components"; import { config } from "../config"; + +// Sort talks by date, newest first +const sortedTalks = [...config.talks].sort((a, b) => { + if (!a.date || !b.date) return 0; + return new Date(b.date).valueOf() - new Date(a.date).valueOf(); +}); + +function formatDate(dateStr: string): string { + return new Date(dateStr).toLocaleDateString("en-us", { + month: "short", + day: "numeric", + year: "numeric", + }); +} --- @@ -11,30 +25,130 @@ import { config } from "../config"; > Talks -
- { - config.talks.map((talk) => ( -
+
+ {sortedTalks[0].date && ( + + )} + + - -
- )) - } -
+

+ {sortedTalks[0].name} +

+ +

+ {sortedTalks[0].description} +

+ + + + View talk + +
+
+
+ )} + + {/* Multiple talks: Mobile one-sided compact timeline */} + {sortedTalks.length > 1 && ( + + )} + + {/* Multiple talks: Desktop dual-sided alternating timeline */} + {sortedTalks.length > 1 && ( + + )} { - config.talks.length === 0 && ( + sortedTalks.length === 0 && (

No talks available yet. Check back soon!