Website update. #1
17 changed files with 411 additions and 39 deletions
21
README.md
21
README.md
|
@ -4,23 +4,6 @@
|
|||
|
||||
To view my portfolio **[click here](https://toastiet0ast.com)**
|
||||
|
||||
## Features
|
||||
|
||||
- Modern and Minimal bento-like, sleek UI Design
|
||||
- All in one page (almost)
|
||||
- Fully Responsive
|
||||
- Performances and SEO optimizations
|
||||
- Blog
|
||||
- RSS support (your-domain/rss.xml)
|
||||
- Cool 3d globe
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- [Astro](https://astro.build)
|
||||
- [unocss](https://unocss.dev/)
|
||||
- [motion](https://motion.dev/)
|
||||
- [d3](https://d3js.org/)
|
||||
|
||||
# Steps ▶️
|
||||
|
||||
```bash
|
||||
|
@ -46,7 +29,3 @@ $ pnpm run dev
|
|||
or
|
||||
$ npm run dev
|
||||
```
|
||||
|
||||
# Configuration
|
||||
|
||||
remember to replace the `site` and other properties with your data in `astro.config.mjs`
|
||||
|
|
56
src/components/BlogHero.astro
Normal file
56
src/components/BlogHero.astro
Normal file
|
@ -0,0 +1,56 @@
|
|||
---
|
||||
interface Props {
|
||||
title: string;
|
||||
tagline?: string;
|
||||
author?: string;
|
||||
align?: 'start' | 'center';
|
||||
}
|
||||
|
||||
const { align = 'center', tagline, title, author } = Astro.props;
|
||||
---
|
||||
|
||||
<div class:list={['hero stack gap-4', align]}>
|
||||
<div class="stack gap-2">
|
||||
<h1 class="title">{title}</h1>
|
||||
<p class="author">{author}</p>
|
||||
{tagline && <p class="tagline">{tagline}</p>}
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hero {
|
||||
font-size: var(--text-lg);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title,
|
||||
.tagline {
|
||||
max-width: 37ch;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: var(--text-3xl);
|
||||
color: var(--gray-0);
|
||||
}
|
||||
|
||||
@media (min-width: 50em) {
|
||||
.hero {
|
||||
font-size: var(--text-xl);
|
||||
}
|
||||
|
||||
.start {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.start .title,
|
||||
.start .tagline {
|
||||
margin-inline: unset;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: var(--text-5xl);
|
||||
}
|
||||
}
|
||||
</style>
|
63
src/components/BlogPreview.astro
Normal file
63
src/components/BlogPreview.astro
Normal file
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
import type { CollectionEntry } from 'astro:content';
|
||||
|
||||
interface Props {
|
||||
blog: CollectionEntry<'blog'>;
|
||||
}
|
||||
|
||||
const { data, id } = Astro.props.blog;
|
||||
---
|
||||
|
||||
<a class="card" href={`/blog/${id}`}>
|
||||
<span class="title">{data.title}</span>
|
||||
</a>
|
||||
|
||||
<style>
|
||||
.card {
|
||||
display: grid;
|
||||
grid-template: auto 1fr / auto 1fr;
|
||||
height: 11rem;
|
||||
background: var(--gradient-subtle);
|
||||
border: 1px solid var(--gray-800);
|
||||
border-radius: 0.75rem;
|
||||
overflow: hidden;
|
||||
box-shadow: var(--shadow-sm);
|
||||
text-decoration: none;
|
||||
font-family: var(--font-brand);
|
||||
font-size: var(--text-lg);
|
||||
font-weight: 500;
|
||||
transition: box-shadow var(--theme-transition);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.title {
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
z-index: 1;
|
||||
margin: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--gray-999);
|
||||
color: var(--gray-200);
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
img {
|
||||
grid-area: 1 / 1 / 3 / 3;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
@media (min-width: 50em) {
|
||||
.card {
|
||||
height: 22rem;
|
||||
border-radius: 1.5rem;
|
||||
}
|
||||
|
||||
.title {
|
||||
border-radius: 0.9375rem;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -6,7 +6,8 @@ import type { iconPaths } from './IconPaths';
|
|||
/** Main menu items */
|
||||
const textLinks: { label: string; href: string }[] = [
|
||||
{ label: 'Home', href: '/' },
|
||||
{ label: 'Work', href: '/work/' },
|
||||
{ label: 'Projects', href: '/projects/' },
|
||||
{ label: 'Blog', href: "/blog/" },
|
||||
{ label: 'About', href: '/about/' },
|
||||
];
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
import type { CollectionEntry } from 'astro:content';
|
||||
|
||||
interface Props {
|
||||
project: CollectionEntry<'work'>;
|
||||
project: CollectionEntry<'projects'>;
|
||||
}
|
||||
|
||||
const { data, id } = Astro.props.project;
|
||||
---
|
||||
|
||||
<a class="card" href={`/work/${id}`}>
|
||||
<a class="card" href={`/projects/${id}`}>
|
||||
<span class="title">{data.title}</span>
|
||||
<img src={data.img} alt={data.img_alt || ''} loading="lazy" decoding="async" />
|
||||
</a>
|
||||
|
|
|
@ -2,9 +2,9 @@ import { glob } from 'astro/loaders';
|
|||
import { defineCollection, z } from 'astro:content';
|
||||
|
||||
export const collections = {
|
||||
work: defineCollection({
|
||||
// Load Markdown files in the src/content/work directory.
|
||||
loader: glob({ base: './src/content/work', pattern: '**/*.md', }),
|
||||
projects: defineCollection({
|
||||
// Load Markdown files in the src/content/projects directory.
|
||||
loader: glob({ base: './src/content/projects', pattern: '**/*.md', }),
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
description: z.string(),
|
||||
|
@ -14,4 +14,17 @@ export const collections = {
|
|||
img_alt: z.string().optional(),
|
||||
}),
|
||||
}),
|
||||
|
||||
blog: defineCollection({
|
||||
loader: glob({ base: './src/content/blog', pattern: '**/*.md', }),
|
||||
schema: z.object({
|
||||
author: z.string(),
|
||||
publishDate: z.date(),
|
||||
title: z.string(),
|
||||
postSlug: z.string().optional(),
|
||||
tags: z.array(z.string()).default(["others"]),
|
||||
description: z.string(),
|
||||
canonicalURL: z.string().optional(),
|
||||
}),
|
||||
}),
|
||||
};
|
40
src/content/blog/new-things.md
Normal file
40
src/content/blog/new-things.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
---
|
||||
author: Toastie
|
||||
publishDate: 2023-12-09
|
||||
title: New projects
|
||||
description: The projects I have started.
|
||||
tags:
|
||||
- project-update
|
||||
---
|
||||
|
||||
Hi there, it has been a while.
|
||||
|
||||
I am back to let you all know how life has been treating me so far as well as share the projects I have been working on.
|
||||
|
||||
### First up is Valkyriecoms,
|
||||
|
||||
Valkyriecoms is a social site I have been working on since December last year and just got things fully up, below is a screenshot of the site.
|
||||
|
||||
![](https://cdn.discordapp.com/attachments/1138770664342441984/1182117160609386650/image.png)
|
||||
|
||||
### Next up is Dragon's child hosting
|
||||
|
||||
Dragon's child hosting is a small server hosting service I started under the Dragon's child studios name right now we are just starting out on our journey.
|
||||
|
||||
Below is a screenshot of our panel (there is a new one which will replace this in the works)
|
||||
|
||||
![](https://cdn.discordapp.com/attachments/881396607218753607/1182651077384994816/dashboard.png)
|
||||
|
||||
### Last up is Toastielab
|
||||
|
||||
Toastielab is a small git platform that I operate wit the help of Dragon's child studios which is where I host all my projects (even the one which this site is located at)
|
||||
|
||||
I am going to include a screenshot of Toastielab below (our icons a little bit bugged right now so it is currently showing the default Forgejo icons)
|
||||
|
||||
![](https://cdn.discordapp.com/attachments/881396607218753607/1182653249480835163/image.png)
|
||||
|
||||
### Here is a list of links for the projects listed above
|
||||
|
||||
- https://valkyriecoms.com
|
||||
- https://dragonschildhosting.net
|
||||
- https://toastielab.dev
|
16
src/content/blog/where-i-have-been.md
Normal file
16
src/content/blog/where-i-have-been.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
---
|
||||
author: Toastie
|
||||
publishDate: 2023-06-21
|
||||
title: Update on things
|
||||
description: Where I have been among other things.
|
||||
tags:
|
||||
- update
|
||||
---
|
||||
|
||||
Hey guys it has been a while and I have not streamed in a little while and I want to update you on why this has happened, First of all I have been having somputer issues as well as some IRL stuff taking over a lot, Secondly I have started some major projects, one with a friend and another to support me first project. These projects are as follows [Valkyriecoms](https://valkyriecoms.com), [Toastielab](https://toastielab.dev) and last but not least a small group stared by me and a good friend who you may know by Elearu called [Dragon's Child Studios](https://dragonschildstudios.com).
|
||||
|
||||
As you can see I have been quite busy but I hope I will be able to return to streaming once everything starts to quiet down a little.
|
||||
|
||||
Thanks for taking the time to read this,
|
||||
|
||||
Toastie_t0ast
|
13
src/content/projects/toastielab.md
Normal file
13
src/content/projects/toastielab.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
---
|
||||
title: Toastielab
|
||||
publishDate: 2024-12-01 00:00:00
|
||||
img: /assets/toastielab.png
|
||||
img_alt: A picture of my the Toastielab cover logo.
|
||||
description: |
|
||||
A small git hosting site.
|
||||
tags:
|
||||
- Development
|
||||
- Services
|
||||
---
|
||||
|
||||
Toastielab is a small git platform that I operate wit the help of Dragon’s child studios which is where I host all my projects (even the one which this site is located at)
|
39
src/pages/blog.astro
Normal file
39
src/pages/blog.astro
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
|
||||
import ContactCTA from '../components/ContactCTA.astro';
|
||||
import BlogPreview from '../components/BlogPreview.astro';
|
||||
import Hero from '../components/Hero.astro';
|
||||
import Grid from '../components/Grid.astro';
|
||||
|
||||
const blog = (await getCollection('blog')).sort(
|
||||
(a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf(),
|
||||
);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="My Blog | Toastie_t0ast"
|
||||
description="Learn about what Toastie_t0ast is up to."
|
||||
>
|
||||
<div class="stack gap-20">
|
||||
<main class="wrapper stack gap-8">
|
||||
<Hero
|
||||
title="Blog"
|
||||
tagline="Here are some posts that I have made."
|
||||
align="start"
|
||||
/>
|
||||
<Grid variant="offset">
|
||||
{
|
||||
blog.map((blog) => (
|
||||
<li>
|
||||
<BlogPreview blog={blog} />
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</Grid>
|
||||
</main>
|
||||
<ContactCTA />
|
||||
</div>
|
||||
</BaseLayout>
|
152
src/pages/blog/[...slug].astro
Normal file
152
src/pages/blog/[...slug].astro
Normal file
|
@ -0,0 +1,152 @@
|
|||
---
|
||||
import { type CollectionEntry, getCollection } from 'astro:content';
|
||||
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
|
||||
import ContactCTA from '../../components/ContactCTA.astro';
|
||||
import BlogHero from '../../components/BlogHero.astro';
|
||||
import Icon from '../../components/Icon.astro';
|
||||
import Pill from '../../components/Pill.astro';
|
||||
import { render } from 'astro:content';
|
||||
|
||||
interface Props {
|
||||
entry: CollectionEntry<'blog'>;
|
||||
}
|
||||
|
||||
// This is a dynamic route that generates a page for every Markdown file in src/content/
|
||||
// Read more about dynamic routes and this `getStaticPaths` function in the Astro docs:
|
||||
// https://docs.astro.build/en/core-concepts/routing/#dynamic-routes
|
||||
export async function getStaticPaths() {
|
||||
const blog = await getCollection('blog');
|
||||
return blog.map((entry) => ({
|
||||
params: { slug: entry.id },
|
||||
props: { entry },
|
||||
}));
|
||||
}
|
||||
|
||||
const { entry } = Astro.props;
|
||||
const { Content } = await render(entry);
|
||||
---
|
||||
|
||||
<BaseLayout title={entry.data.title} description={entry.data.description}>
|
||||
<div class="stack gap-20">
|
||||
<div class="stack gap-15">
|
||||
<header>
|
||||
<div class="wrapper stack gap-2">
|
||||
<a class="back-link" href="/blog/"><Icon icon="arrow-left" /> blog</a>
|
||||
<BlogHero title={entry.data.title} align="start">
|
||||
<p>Author: {entry.data.author}</p>
|
||||
<div class="details">
|
||||
<div class="tags">
|
||||
{entry.data.tags.map((t) => <Pill>{t}</Pill>)}
|
||||
</div>
|
||||
<p class="description">{entry.data.description}</p>
|
||||
</div>
|
||||
</BlogHero>
|
||||
</div>
|
||||
</header>
|
||||
<main class="wrapper">
|
||||
<div class="stack gap-10 content">
|
||||
<div class="content">
|
||||
<Content />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<ContactCTA />
|
||||
</div>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
header {
|
||||
padding-bottom: 2.5rem;
|
||||
border-bottom: 1px solid var(--gray-800);
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.5rem;
|
||||
gap: 1.5rem;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tags {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: var(--text-lg);
|
||||
max-width: 54ch;
|
||||
}
|
||||
|
||||
.content {
|
||||
max-width: 65ch;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.content > :global(* + *) {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.content :global(h1),
|
||||
.content :global(h2),
|
||||
.content :global(h3),
|
||||
.content :global(h4),
|
||||
.content :global(h5) {
|
||||
margin: 1.5rem 0;
|
||||
}
|
||||
|
||||
.content :global(img) {
|
||||
border-radius: 1.5rem;
|
||||
box-shadow: var(--shadow-sm);
|
||||
background: var(--gradient-subtle);
|
||||
border: 1px solid var(--gray-800);
|
||||
}
|
||||
|
||||
.content :global(blockquote) {
|
||||
font-size: var(--text-lg);
|
||||
font-family: var(--font-brand);
|
||||
font-weight: 600;
|
||||
line-height: 1.1;
|
||||
padding-inline-start: 1.5rem;
|
||||
border-inline-start: 0.25rem solid var(--accent-dark);
|
||||
color: var(--gray-0);
|
||||
}
|
||||
|
||||
.back-link,
|
||||
.content :global(a) {
|
||||
text-decoration: 1px solid underline transparent;
|
||||
text-underline-offset: 0.25em;
|
||||
transition: text-decoration-color var(--theme-transition);
|
||||
}
|
||||
|
||||
.back-link:hover,
|
||||
.back-link:focus,
|
||||
.content :global(a:hover),
|
||||
.content :global(a:focus) {
|
||||
text-decoration-color: currentColor;
|
||||
}
|
||||
|
||||
@media (min-width: 50em) {
|
||||
.back-link {
|
||||
display: block;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.details {
|
||||
flex-direction: row;
|
||||
gap: 2.5rem;
|
||||
}
|
||||
|
||||
.content :global(blockquote) {
|
||||
font-size: var(--text-2xl);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -16,8 +16,8 @@ import PortfolioPreview from '../components/PortfolioPreview.astro';
|
|||
import ContactCTA from '../components/ContactCTA.astro';
|
||||
import Skills from '../components/Skills.astro';
|
||||
|
||||
// Content Fetching: List four most recent work projects
|
||||
const projects = (await getCollection('work'))
|
||||
// Content Fetching: List four most recent projects
|
||||
const projects = (await getCollection('projects'))
|
||||
.sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf())
|
||||
.slice(0, 4);
|
||||
|
||||
|
@ -46,8 +46,8 @@ const projects = (await getCollection('work'))
|
|||
<main class="wrapper stack gap-20 lg:gap-48">
|
||||
<section class="section with-background with-cta">
|
||||
<header class="section-header stack gap-2 lg:gap-4">
|
||||
<h3>Selected Work</h3>
|
||||
<p>Take a look below at some of the work I have worked on over the past few years.</p>
|
||||
<h3>Selected Projects</h3>
|
||||
<p>Take a look below at some of the projects I have worked on over the past few years.</p>
|
||||
</header>
|
||||
|
||||
<div class="gallery">
|
||||
|
@ -63,7 +63,7 @@ const projects = (await getCollection('work'))
|
|||
</div>
|
||||
|
||||
<div class="cta">
|
||||
<CallToAction href="/work/">
|
||||
<CallToAction href="/projects/">
|
||||
View All
|
||||
<Icon icon="arrow-right" size="1.2em" />
|
||||
</CallToAction>
|
||||
|
|
|
@ -8,19 +8,19 @@ import PortfolioPreview from '../components/PortfolioPreview.astro';
|
|||
import Hero from '../components/Hero.astro';
|
||||
import Grid from '../components/Grid.astro';
|
||||
|
||||
const projects = (await getCollection('work')).sort(
|
||||
const projects = (await getCollection('projects')).sort(
|
||||
(a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf(),
|
||||
);
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="My Work | Toastie_t0ast"
|
||||
title="My Projects | Toastie_t0ast"
|
||||
description="Learn about Toastie_t0ast's most recent projects"
|
||||
>
|
||||
<div class="stack gap-20">
|
||||
<main class="wrapper stack gap-8">
|
||||
<Hero
|
||||
title="My Work"
|
||||
title="My Projects"
|
||||
tagline="See my most recent projects below to get an idea of my past experience."
|
||||
align="start"
|
||||
/>
|
|
@ -10,15 +10,15 @@ import Pill from '../../components/Pill.astro';
|
|||
import { render } from 'astro:content';
|
||||
|
||||
interface Props {
|
||||
entry: CollectionEntry<'work'>;
|
||||
entry: CollectionEntry<'projects'>;
|
||||
}
|
||||
|
||||
// This is a dynamic route that generates a page for every Markdown file in src/content/
|
||||
// Read more about dynamic routes and this `getStaticPaths` function in the Astro docs:
|
||||
// https://docs.astro.build/en/core-concepts/routing/#dynamic-routes
|
||||
export async function getStaticPaths() {
|
||||
const work = await getCollection('work');
|
||||
return work.map((entry) => ({
|
||||
const projects = await getCollection('projects');
|
||||
return projects.map((entry) => ({
|
||||
params: { slug: entry.id },
|
||||
props: { entry },
|
||||
}));
|
||||
|
@ -33,7 +33,7 @@ const { Content } = await render(entry);
|
|||
<div class="stack gap-15">
|
||||
<header>
|
||||
<div class="wrapper stack gap-2">
|
||||
<a class="back-link" href="/work/"><Icon icon="arrow-left" /> Work</a>
|
||||
<a class="back-link" href="/projects/"><Icon icon="arrow-left" /> projects</a>
|
||||
<Hero title={entry.data.title} align="start">
|
||||
<div class="details">
|
||||
<div class="tags">
|
Loading…
Reference in a new issue