Major redesign and rewrite

This commit is contained in:
Firq 2024-07-19 22:52:15 +02:00
parent 9cb6ff6ed7
commit 0dca43eb19
Signed by: Firq
GPG key ID: 3ACC61C8CEC83C20
41 changed files with 3863 additions and 4889 deletions

5
.astro/settings.json Normal file
View file

@ -0,0 +1,5 @@
{
"_variables": {
"lastUpdateCheck": 1721418667135
}
}

199
.astro/types.d.ts vendored Normal file
View file

@ -0,0 +1,199 @@
declare module 'astro:content' {
interface Render {
'.mdx': Promise<{
Content: import('astro').MarkdownInstance<{}>['Content'];
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}>;
}
}
declare module 'astro:content' {
interface Render {
'.md': Promise<{
Content: import('astro').MarkdownInstance<{}>['Content'];
headings: import('astro').MarkdownHeading[];
remarkPluginFrontmatter: Record<string, any>;
}>;
}
}
declare module 'astro:content' {
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
export type CollectionKey = keyof AnyEntryMap;
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
export type ContentCollectionKey = keyof ContentEntryMap;
export type DataCollectionKey = keyof DataEntryMap;
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
ContentEntryMap[C]
>['slug'];
export function getEntryBySlug<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
// Note that this has to accept a regular string too, for SSR
entrySlug: E
): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
collection: C,
entryId: E
): Promise<CollectionEntry<C>>;
export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
collection: C,
filter?: (entry: CollectionEntry<C>) => entry is E
): Promise<E[]>;
export function getCollection<C extends keyof AnyEntryMap>(
collection: C,
filter?: (entry: CollectionEntry<C>) => unknown
): Promise<CollectionEntry<C>[]>;
export function getEntry<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(entry: {
collection: C;
slug: E;
}): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
E extends keyof DataEntryMap[C] | (string & {}),
>(entry: {
collection: C;
id: E;
}): E extends keyof DataEntryMap[C]
? Promise<DataEntryMap[C][E]>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof ContentEntryMap,
E extends ValidContentEntrySlug<C> | (string & {}),
>(
collection: C,
slug: E
): E extends ValidContentEntrySlug<C>
? Promise<CollectionEntry<C>>
: Promise<CollectionEntry<C> | undefined>;
export function getEntry<
C extends keyof DataEntryMap,
E extends keyof DataEntryMap[C] | (string & {}),
>(
collection: C,
id: E
): E extends keyof DataEntryMap[C]
? Promise<DataEntryMap[C][E]>
: Promise<CollectionEntry<C> | undefined>;
/** Resolve an array of entry references from the same collection */
export function getEntries<C extends keyof ContentEntryMap>(
entries: {
collection: C;
slug: ValidContentEntrySlug<C>;
}[]
): Promise<CollectionEntry<C>[]>;
export function getEntries<C extends keyof DataEntryMap>(
entries: {
collection: C;
id: keyof DataEntryMap[C];
}[]
): Promise<CollectionEntry<C>[]>;
export function reference<C extends keyof AnyEntryMap>(
collection: C
): import('astro/zod').ZodEffects<
import('astro/zod').ZodString,
C extends keyof ContentEntryMap
? {
collection: C;
slug: ValidContentEntrySlug<C>;
}
: {
collection: C;
id: keyof DataEntryMap[C];
}
>;
// Allow generic `string` to avoid excessive type errors in the config
// if `dev` is not running to update as you edit.
// Invalid collection names will be caught at build time.
export function reference<C extends string>(
collection: C
): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
>;
type ContentEntryMap = {
"blog": {
"astro-usage.md": {
id: "astro-usage.md";
slug: "astro-usage";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"cernunnos-with-requiem.mdx": {
id: "cernunnos-with-requiem.mdx";
slug: "cernunnos-with-requiem";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".mdx"] };
"deploying-this-round-2.md": {
id: "deploying-this-round-2.md";
slug: "deploying-this-round-2";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"deploying-this.md": {
id: "deploying-this.md";
slug: "deploying-this";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"fgo-ta.md": {
id: "fgo-ta.md";
slug: "fgo-ta";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"hello-world.md": {
id: "hello-world.md";
slug: "hello-world";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".md"] };
"instant-death.mdx": {
id: "instant-death.mdx";
slug: "instant-death";
body: string;
collection: "blog";
data: InferEntrySchema<"blog">
} & { render(): Render[".mdx"] };
};
};
type DataEntryMap = {
};
type AnyEntryMap = ContentEntryMap & DataEntryMap;
export type ContentConfig = typeof import("./../src/content/config.js");
}

View file

@ -4,38 +4,54 @@ on:
- '[0-9]+\.[0-9]+\.[0-9]+-pre\.[0-9]+'
jobs:
checking:
check-tag:
runs-on: docker
container: node:lts
steps:
- name: Checking Out Repository Code
uses: https://code.forgejo.org/actions/checkout@v3
- name: Check if Version in package.json matches Tag
run: |
VERSION=$(cat package.json | grep "version" | sed 's/.*://' | tr -d , | tr -d \" | tr -d " " )
if test $VERSION != "${{ github.ref_name }}"; then
echo "Expected Version is: '${{ github.ref_name }}' actual Version is: '$VERSION'";
exit 1
else
echo "Version is: '$VERSION'";
fi
checking:
needs: [ check-tag ]
runs-on: docker
container: forgejo.neshweb.net/ci-docker-images/node-alpine-git:latest
steps:
- name: Checkout source code
uses: https://code.forgejo.org/actions/checkout@v3
- name: Install packages
run: npm install
run: npm i
- name: Run astro check (linting + static analysis)
run: npm run astro check
build-site:
needs: [checking]
needs: [ checking ]
if: success()
runs-on: dind
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
- name: Log into Docker Package Registry
uses: docker/login-action@v3
with:
registry: forgejo.neshweb.net
username: ${{ secrets.FORGEJO_USERNAME }}
password: ${{ secrets.FORGEJO_TOKEN }}
- name: Push to Package Registry
- name: Build and push to Docker Package Registry
uses: docker/build-push-action@v5
with:
push: true
tags: forgejo.neshweb.net/firq/firq-dev-website:${{ github.ref_name }}, forgejo.neshweb.net/firq/firq-dev-website:preview
publish:
needs: [build-site]
create-release:
needs: [ build-site ]
if: success()
runs-on: docker
steps:

View file

@ -4,38 +4,54 @@ on:
- '[0-9]+\.[0-9]+\.[0-9]+'
jobs:
checking:
check-tag:
runs-on: docker
container: node:lts
steps:
- name: Checking Out Repository Code
uses: https://code.forgejo.org/actions/checkout@v3
- name: Check if Version in package.json matches Tag
run: |
VERSION=$(cat package.json | grep "version" | sed 's/.*://' | tr -d , | tr -d \" | tr -d " " )
if test $VERSION != "${{ github.ref_name }}"; then
echo "Expected Version is: '${{ github.ref_name }}' actual Version is: '$VERSION'";
exit 1
else
echo "Version is: '$VERSION'";
fi
checking:
needs: [ check-tag ]
runs-on: docker
container: forgejo.neshweb.net/ci-docker-images/node-alpine-git:latest
steps:
- name: Checkout source code
uses: https://code.forgejo.org/actions/checkout@v3
- name: Install packages
run: npm install
run: npm i
- name: Run astro check (linting + static analysis)
run: npm run astro check
build-site:
needs: [checking]
needs: [ checking ]
if: success()
runs-on: dind
steps:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
- name: Log into Docker Package Registry
uses: docker/login-action@v3
with:
registry: forgejo.neshweb.net
username: ${{ secrets.FORGEJO_USERNAME }}
password: ${{ secrets.FORGEJO_TOKEN }}
- name: Push to Package Registry
- name: Build and push to Docker Package Registry
uses: docker/build-push-action@v5
with:
push: true
tags: forgejo.neshweb.net/firq/firq-dev-website:${{ github.ref_name }}, forgejo.neshweb.net/firq/firq-dev-website:latest
release:
needs: [build-site]
create-release:
needs: [ build-site ]
if: success()
runs-on: docker
steps:

View file

@ -1,16 +1,16 @@
on:
push:
branches:
- "**"
- '**'
jobs:
checking:
astro-check:
runs-on: docker
container: node:lts
container: forgejo.neshweb.net/ci-docker-images/node-alpine-git:latest
steps:
- name: Checkout source code
uses: https://code.forgejo.org/actions/checkout@v3
- name: Install packages
run: npm install
run: npm i
- name: Run astro check (linting + static analysis)
run: npm run astro check

View file

@ -11,7 +11,7 @@ jobs:
- name: Checkout repository
uses: https://code.forgejo.org/actions/checkout@v3
- name: Run unlighthouse
run: unlighthouse-ci --site "https://preview.firq.dev/"
run: unlighthouse-ci --site "https://preview.firq.dev/" --disable-dynamic-sampling
- name: Prepare artifacts
run: cp serve.json unlighthouse-reports
- name: Upload reports

7714
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,15 +11,17 @@
"astro": "astro"
},
"dependencies": {
"@astro-community/astro-embed-youtube": "^0.4.3",
"@astrojs/check": "^0.3.3",
"@astrojs/mdx": "^2.0.3",
"@astrojs/sitemap": "^3.0.3",
"astro": "^4.2.1",
"autoprefixer": "^10.4.16",
"iconoir": "^7.2.0",
"postcss-preset-env": "^9.3.0",
"typescript": "^5.3.3"
"@astro-community/astro-embed-youtube": "^0.5.2",
"@astrojs/check": "^0.8.1",
"@astrojs/mdx": "^3.1.3",
"@astrojs/sitemap": "^3.1.6",
"@fontsource/work-sans": "^5.0.18",
"astro": "^4.11.5",
"astro-meta-tags": "^0.3.0",
"autoprefixer": "^10.4.19",
"iconoir": "^7.7.0",
"postcss-preset-env": "^9.6.0",
"typescript": "^5.5.3"
},
"browserslist": [
"last 2 versions",

View file

@ -1,8 +1,9 @@
---
export interface Props {
url: string | undefined
url: string
slug: string
title: string
pubdate: string
pubdate: Date
description: string
author: string
}
@ -12,11 +13,11 @@ const options_date: Intl.DateTimeFormatOptions = {
month: 'long',
day: '2-digit',
}
const { author, description, pubdate, url, title } = Astro.props
const { author, description, pubdate, url, title, slug } = Astro.props
const date = new Date(pubdate).toLocaleDateString('en-GB', options_date)
---
<a href={url} rel="noopener noreferrer">
<a href={`${url}/${slug}`} rel="noopener noreferrer">
<div class="circle"></div>
<article>
<h2>{title}</h2>
@ -29,38 +30,14 @@ const date = new Date(pubdate).toLocaleDateString('en-GB', options_date)
.circle {
display: none;
}
@media (min-width: 900px) {
.circle {
margin: 1rem 1rem 1rem 0rem;
position: relative;
display: flex;
visibility: visible;
height: 1.5rem;
width: 1.5rem;
border-radius: 40%;
background-color: var(--c-darkpurple);
transition: transform var(--speed) var(--ease);
}
a:hover > .circle {
height: 1.75rem;
width: 1.75rem;
translate: -0.125rem;
margin-right: 0.825rem;
}
article {
margin-left: 0.5rem;
}
}
a {
align-items: center;
justify-content: center;
display: flex;
text-decoration: none;
height: auto;
margin: 0.5rem;
height: fit-content;
margin: 0px 0.5rem;
width: 100%;
}
p {
@ -88,8 +65,8 @@ const date = new Date(pubdate).toLocaleDateString('en-GB', options_date)
flex: 1;
flex-wrap: wrap;
flex-direction: column;
align-items: flex-start;
align-content: flex-start;
align-items: center;
align-content: center;
justify-content: center;
background-color: var(--c-darkergray);
padding: 10px;
@ -98,7 +75,47 @@ const date = new Date(pubdate).toLocaleDateString('en-GB', options_date)
min-height: 100%;
border-radius: 1.25rem;
}
a:hover > article {
transform: scaleY(102.5%) scaleX(101%);
transition: transform var(--speed) var(--ease);
}
@media (min-width: 900px) {
.circle {
margin: 1rem 0.5rem 1rem 0.5rem;
position: relative;
display: flex;
visibility: visible;
height: 1rem;
width: 1rem;
background-color: var(--c-darkpurple);
border-style: solid;
border-width: 0.25rem;
border-color: var(--c-lightgray);
border-radius: 40%;
transition: transform var(--speed) var(--ease);
}
a:hover > .circle {
height: 1.25rem;
width: 1.25rem;
translate: -0.125rem;
margin-right: 4px;
}
a:hover article {
border-color: var(--c-darkpurple);
transform: none;
}
article {
border-style: solid;
border-width: 2px;
border-color: var(--c-darkergray);
align-items: flex-start;
align-content: flex-start;
margin-left: 0.5rem;
}
}
</style>

View file

@ -1,8 +1,8 @@
---
import { Image } from 'astro:assets'
import mlb_ce from '../assets/ce/mlb.webp'
import type { GlobImage } from '../types/generic'
import { plsLoadImage } from '../utils/tools'
import mlb_ce from '../../assets/ce/mlb.webp'
import type { GlobImage } from '../../types/generic'
import { plsLoadImage } from '../../utils/tools'
export interface Props {
name: string

View file

@ -1,7 +1,7 @@
---
import { Image } from 'astro:assets'
import type { GlobImage } from '../types/generic'
import { plsLoadImage } from '../utils/tools'
import type { GlobImage } from '../../types/generic'
import { plsLoadImage } from '../../utils/tools'
export interface Props {
site: string

View file

@ -1,7 +1,7 @@
---
import { Image } from 'astro:assets'
import type { GlobImage } from '../types/generic'
import { plsLoadImage } from '../utils/tools'
import type { GlobImage } from '../../types/generic'
import { plsLoadImage } from '../../utils/tools'
export interface Props {
name: string

View file

@ -1,7 +1,7 @@
---
import { Image } from 'astro:assets';
import type { GlobImage } from '../types/generic'
import { plsLoadImage } from '../utils/tools'
import type { GlobImage } from '../../types/generic'
import { plsLoadImage } from '../../utils/tools'
export interface Props {
name: string

View file

@ -1,7 +1,7 @@
---
import { Image } from 'astro:assets'
import type { GlobImage } from '../types/generic'
import { plsLoadImage } from '../utils/tools'
import type { GlobImage } from '../../types/generic'
import { plsLoadImage } from '../../utils/tools'
export interface Props {
date: string

View file

@ -1,7 +1,7 @@
---
import { Image } from 'astro:assets'
import type { GlobImage } from '../types/generic'
import { plsLoadImage } from '../utils/tools'
import type { GlobImage } from '../../types/generic'
import { plsLoadImage } from '../../utils/tools'
export interface Props {
title: string

View file

@ -1,4 +1,9 @@
---
export interface Props {
fadeout?: boolean
}
const { fadeout } = Astro.props
const display = fadeout ? "": "display: none"
---
<div>
@ -6,22 +11,33 @@
I am currently working on a site to catalogue past and future TAs.<br/>
Check it out at <a href="https://fgo-ta.com">fgo-ta.com</a>
</span>
<div class="fade" style={display}></div>
</div>
<style>
div {
display: flex;
width: 100%;
height: 5em;
background-color: var(--c-gray);
flex-wrap: nowrap;
flex-flow: column;
background-color: var(--c-darkergray);
text-align: center;
align-items: center;
justify-content: center;
color: white;
font-size: 1.5em;
padding: 2rem 0rem 0rem 0rem;
}
a {
color: var(--c-darkpurple);
text-align: center;
text-decoration: none;
color: var(--c-darkpurple);
}
.fade {
margin-top: 3rem;
background: linear-gradient(to bottom, transparent, var(--c-lightgray));
height: 2.5rem;
width: 100%;
}
</style>

View file

@ -1,21 +1,27 @@
---
import { Image } from 'astro:assets';
import logo from '../assets/logo.svg'
import { Image } from 'astro:assets'
import logo from '../../assets/logo.svg'
import hamburger from 'iconoir/icons/menu.svg'
const hamburger_src_url = `url("${hamburger.src}")`;
const hamburger_src_url = `url("${hamburger.src}")`
---
<header>
<a href="/" rel="noopener noreferrer" aria-label="Home" role="link">
<Image src={logo} alt=""/>
<span class="visually-hidden">Firq Logo</span>
<a href="/" rel="noopener noreferrer" aria-label="Home" role="button">
<Image src={logo} alt="" loading="eager"/>
<span class="visually-hidden">Logo</span>
</a>
<ul class="desktop">
<slot name="desktop"/>
<slot name="desktop" />
</ul>
<button class="mobile" aria-label="Navigation Button" tabindex="0" onclick="this.focus()" role="button">
<button
class="mobile"
aria-label="Navigation Button"
tabindex="0"
onclick="this.focus()"
role="button"
>
<ul>
<slot name="mobile"/>
<slot name="mobile" />
</ul>
<div class="placeholder"></div>
<div class="hamburger-menu" role="navigation"></div>
@ -27,12 +33,13 @@ const hamburger_src_url = `url("${hamburger.src}")`;
z-index: 1000;
position: sticky;
top: 0px;
background-color: var(--c-darkgray);
background-color: var(--c-darkergray);
display: flex;
height: auto;
width: 100%;
align-items: flex-start;
line-height: 1.5em;
border-bottom: 2px solid var(--c-darkpurple) ;
}
header > a {
margin-left: 16px;
@ -61,7 +68,7 @@ const hamburger_src_url = `url("${hamburger.src}")`;
line-height: 1.5em;
}
.mobile > ul {
background-color: var(--c-darkgray);
background-color: var(--c-darkergray);
align-items: center;
flex-wrap: wrap;
flex-direction: column;
@ -78,7 +85,7 @@ const hamburger_src_url = `url("${hamburger.src}")`;
.mobile {
display: flex;
background-color: var(--c-darkgray);
background-color: var(--c-darkergray);
border: 0px;
width: 100%;
height: 64px;
@ -108,13 +115,14 @@ const hamburger_src_url = `url("${hamburger.src}")`;
.hamburger-menu {
mask: var(--hamburger_src_url) no-repeat center;
mask-size: cover;
background-color: white;
width: 2rem;
height: 2rem;
width: 2.25rem;
height: 2.25rem;
position: static;
align-self: flex-start;
margin-right: 1rem;
margin-top: 1rem;
margin-top: 0.825rem;
}
@media (min-width: 1140px) {

View file

@ -1,7 +1,7 @@
---
export interface Props {
currentPage?: string
navtype: "mobile" | "desktop"
navtype: 'mobile' | 'desktop'
link: string
text: string
icon: ImageMetadata
@ -18,10 +18,10 @@ if (currentPage === slug) {
currPage = 'current'
}
const icon_src_url = `url("${icon.src}")`;
const icon_src_url = `url("${icon.src}")`
const fulllink = `/${slug}`
let extraattributes = navtype === "mobile" ? { tabindex: "0"} : {}
let extraattributes = navtype === 'mobile' ? { tabindex: '0' } : {}
---
<li>
@ -30,7 +30,7 @@ let extraattributes = navtype === "mobile" ? { tabindex: "0"} : {}
rel="noopener noreferrer"
aria-label={text}
class={currPage}
role="navigation"
role="button"
{...extraattributes}
>
<div class="icon"></div>
@ -60,11 +60,11 @@ let extraattributes = navtype === "mobile" ? { tabindex: "0"} : {}
}
li > a:hover {
color: var(--c-purplepink);
color: var(--c-purplepink) !important;
}
li > a:hover > .icon {
background-color: var(--c-purplepink);
background-color: var(--c-purplepink) !important;
}
.current {

View file

@ -0,0 +1,109 @@
---
import '@fontsource/work-sans/800.css'
import '@fontsource/work-sans/600.css'
export interface Props {
maintext: string
subtext: string
fadeout?: boolean
baseurl?: string
returnbutton?: boolean
}
const { maintext, subtext, fadeout, baseurl, returnbutton } = Astro.props
const displayFadeout = fadeout ? "": "display: none"
const displayBackButton = returnbutton ? "": "display: none"
---
<div class="wrap">
<div class="head">{maintext}</div>
<div class="sub">{subtext}</div>
<a href=`/${baseurl}` style={displayBackButton}>&lt;&lt; Back to {baseurl}</a>
<div class="fade" style={displayFadeout}></div>
</div>
<style>
a {
font-weight: 600;
font-family: 'Work Sans', 'Helvetica Neue', Helvetica, Helvetica, Arial, sans-serif;
color: white;
margin: 1rem 0px 0px;
padding: 0.5rem 0.75rem;
text-decoration: none;
background-color: var(--c-lightgray);
border-radius: 10px;
border-style: solid;
border-width: 2px;
border-color: var(--c-lightgray);
text-transform: capitalize;
}
a:hover {
border-color: var(--c-darkpurple);
}
.wrap {
position: relative;
width: 100%;
display: flex;
text-align: center;
align-items: center;
flex-wrap: wrap;
flex-direction: column;
color: var(--c-lighter);
background-color: var(--c-darkergray);
}
.fade {
margin-top: 2rem;
background: linear-gradient(to bottom, transparent, var(--c-lightgray));
height: 2.5rem;
width: 100%;
}
.head {
hyphens: auto;
padding-top: 2rem;
font-size: 2rem;
font-weight: 800;
font-family: 'Work Sans', 'Helvetica Neue', Helvetica, Helvetica, Arial,
sans-serif;
}
.sub {
font-size: 0.75rem;
font-weight: 600;
font-family: 'Work Sans', 'Helvetica Neue', Helvetica, Helvetica, Arial,
sans-serif;
margin-top: 0.5em;
}
.head {
color: var(--c-darkpurple);
}
@supports (background-clip: text) {
.head {
background: linear-gradient(125deg, var(--c-darkpurple), var(--c-purplepink), var(--c-reddish) );
background-clip: text;
color: transparent;
}
}
@media (min-width: 620px) {
.head {
hyphens: none;
font-size: 3rem;
}
.sub {
font-size: 0.75rem;
}
}
@media (min-width: 1000px) {
.head {
font-size: 4rem;
}
.sub {
font-size: 1rem;
}
}
</style>

View file

@ -0,0 +1,75 @@
---
import '@fontsource/work-sans/800.css'
---
<div class="wrap">
<div class="head">Hi, I'm <span class="fancy">Firq</span></div>
<div class="sub">Nice to meet you</div>
<div class="fade"></div>
</div>
<style>
.wrap {
position: relative;
width: 100%;
display: flex;
text-align: center;
align-items: center;
flex-wrap: wrap;
flex-direction: column;
color: var(--c-lighter);
background-color: var(--c-darkergray);
}
.fade {
margin-top: 1.5rem;
background: linear-gradient(to bottom, transparent, var(--c-lightgray));
height: 2.5rem;
width: 100%;
}
.head {
padding-top: 2rem;
font-size: 3rem;
font-weight: 800;
font-family: 'Work Sans', 'Helvetica Neue', Helvetica, Helvetica, Arial,
sans-serif;
}
.sub {
font-size: 1rem;
font-weight: 800;
font-family: 'Work Sans', 'Helvetica Neue', Helvetica, Helvetica, Arial,
sans-serif;
}
.fancy {
color: var(--c-darkpurple);
}
@supports (background-clip: text) {
.fancy {
background: linear-gradient(125deg, var(--c-darkpurple), var(--c-purplepink), var(--c-reddish) );
background-clip: text;
color: transparent;
}
}
@media (min-width: 620px) {
.head {
font-size: 4rem;
}
.sub {
font-size: 1.25rem;
}
}
@media (min-width: 1000px) {
.head {
font-size: 6rem;
}
.sub {
font-size: 1.5rem;
}
}
</style>

16
src/content/config.ts Normal file
View file

@ -0,0 +1,16 @@
import { z, defineCollection } from 'astro:content'
const blogCollection = defineCollection({
type: 'content', // v2.5.0 and later
schema: z.object({
title: z.string(),
tags: z.array(z.string()),
pubDate: z.date(),
description: z.string(),
author: z.string(),
}),
})
export const collections = {
blog: blogCollection,
}

1
src/env.d.ts vendored
View file

@ -1 +1,2 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />

View file

@ -1,6 +1,6 @@
---
import Navbar from '../components/navbar.astro'
import NavbarEntry from '../components/navbarEntry.astro'
import Navbar from '../components/navbar/navbar.astro'
import NavbarEntry from '../components/navbar/navbarEntry.astro'
import navdata from '../../static/data/_navdata.json'
import embed from '../assets/embed.png'
@ -77,12 +77,22 @@ const mapped_navdata = navdata.map((item) => ({
<Navbar>
{
mapped_navdata.map((item) => (
<NavbarEntry currentPage={currentpage} navtype="desktop" {...item} slot="desktop"/>
<NavbarEntry
currentPage={currentpage}
navtype="desktop"
{...item}
slot="desktop"
/>
))
}
{
mapped_navdata.map((item) => (
<NavbarEntry currentPage={currentpage} navtype="mobile" {...item} slot="mobile"/>
<NavbarEntry
currentPage={currentpage}
navtype="mobile"
{...item}
slot="mobile"
/>
))
}
</Navbar>
@ -98,10 +108,12 @@ const mapped_navdata = navdata.map((item) => ({
--c-darkgray: #1e1e1e;
--c-duskgray: #242424;
--c-gray: #2e2e2e;
--c-lighter: #eee;
--c-lightgray: #3e3e3e;
--c-darkpurple: #b86cff;
--c-purplepink: #c105ff;
--c-darkergray: #1b1b1b;
--c-reddish: #ff0077;
}
body {
background: var(--c-lightgray);
@ -117,5 +129,5 @@ const mapped_navdata = navdata.map((item) => ({
padding: 0;
position: absolute;
width: 1px;
}
}
</style>

View file

@ -1,74 +0,0 @@
---
export interface Props {
title: string
}
const { title } = Astro.props
---
<section class="base">
<h1>{title}</h1>
<div>
<slot />
</div>
</section>
<style>
h1 {
font-size: 40px;
line-height: 48px;
letter-spacing: -1px;
color: white;
font-size: 2.25rem;
margin-top: 1rem;
margin-bottom: 0;
margin-left: auto;
margin-right: auto;
padding: 0.25rem 0.75rem;
max-width: max-content;
background-color: var(--c-darkgray);
padding: 0.25rem 1.5rem;
border-radius: 0.5rem;
padding-bottom: 0.5rem;
}
div {
row-gap: 1em;
column-gap: 1em;
justify-content: center;
align-self: center;
display: flex;
flex-flow: row wrap;
padding: 1em;
color: white;
font-size: 1em;
}
.base {
margin-left: 1rem;
margin-right: 1rem;
}
@media (min-width: 400px) {
.base {
margin-left: 3rem;
margin-right: 3rem;
}
}
@media (min-width: 1500px) {
.base {
margin-left: 10%;
margin-right: 10%;
}
}
@media (min-width: 512px) {
div {
justify-content: left;
}
}
@media (min-width: 520px) {
h1 {
margin: 0.5rem 0.75rem 0.5rem 0.75rem;
}
}
</style>

View file

@ -1,4 +1,5 @@
---
import SmallTitle from '../components/titles/smallTitle.astro'
import Layout from './Layout.astro'
const { frontmatter } = Astro.props
@ -13,15 +14,12 @@ const date = new Date(frontmatter.pubDate).toLocaleDateString(
'en-GB',
options_date
)
const subtext = `Written by ${frontmatter.author} • Published on ${date}`
---
<Layout title={title} currentpage="blog" descriptionOverride={description}>
<a href="/blog"><i class="iconoir-fast-arrow-left"></i>Back to all posts</a>
<SmallTitle maintext={frontmatter.title} subtext={subtext} fadeout={true} returnbutton={true} baseurl='blog'/>
<div>
<h1>
{frontmatter.title}
</h1>
<p>by {frontmatter.author} • Published on {date}</p>
<article>
<slot />
</article>

View file

@ -1,36 +1,59 @@
---
export interface Props {
title: string
titlehidden?: boolean
displayLine?: boolean
}
const { title } = Astro.props
const { title, titlehidden, displayLine } = Astro.props
const display = titlehidden ? "display: none" : ""
const line = displayLine ? "flex" : "none"
---
<section>
<h1>{title}</h1>
<h1 style={display}>{title}</h1>
<div class="wrapper">
<div class="start hightlighter"></div>
<div class="line"></div>
<slot />
<div class="drop"></div>
<div class="drop hightlighter"></div>
</div>
</section>
<style>
.drop {
<style define:vars={{ line }}>
section {
padding-left: 0.25em;
padding-right: 0.25em;
padding-bottom: 5rem;
}
.hightlighter {
left: 0;
right: 0;
display: flex;
position: absolute;
visibility: visible;
left: 0;
right: 0;
bottom: -5rem;
margin-left: auto;
margin-right: auto;
height: 1.5rem;
width: 1.5rem;
}
.drop {
bottom: -5rem;
border-radius: 0% 50% 50% 50%;
transform: rotate(45deg);
background-color: var(--c-darkpurple);
}
.start {
top: -2rem;
border-radius: 40%;
border-style: solid;
border-width: 0.25rem;
border-color: var(--c-lightgray);
background-color: var(--c-darkpurple);
}
.line {
display: flex;
position: absolute;
@ -46,30 +69,31 @@ const { title } = Astro.props
z-index: -1;
}
h1 {
font-size: 40px;
line-height: 48px;
letter-spacing: -1px;
color: white;
font-size: 2.25rem;
font-size: 1.6rem;
margin-top: 1rem;
margin-bottom: 0;
margin-left: auto;
margin-right: auto;
padding: 0.25rem 0.75rem;
max-width: max-content;
background-color: var(--c-darkgray);
padding: 0.25rem 1.5rem;
border-radius: 0.5rem;
padding-bottom: 0.5rem;
justify-self: center;
text-align: center;
}
.wrapper {
margin: 2rem 3rem 0.5rem 3rem;
margin: 2rem 2rem 0.5rem 2rem;
display: flex;
flex-flow: column wrap;
row-gap: 1em;
column-gap: 1em;
align-self: center;
align-items: stretch;
align-content: center;
justify-content: space-around;
padding: 1em;
color: white;
@ -80,21 +104,41 @@ const { title } = Astro.props
.drop {
margin-left: 1.5rem;
}
.start {
margin-left: 1.25rem;
}
.line {
margin-left: 2.1rem;
}
h1 {
margin-left: 3rem;
font-size: 1.85rem;
}
}
@media (min-width: 1500px) {
.wrapper {
margin-left: 20rem;
margin-right: 20rem;
margin-left: 15rem;
margin-right: 15rem;
flex-direction: row;
}
section {
padding-bottom: unset;
}
.drop, .start, .line {
display: var(--line);
margin-left: 2rem;
}
.start {
margin-left: 1.75rem;
}
.line {
margin-left: 2.6rem;
height: calc(100% + 6rem);
translate: 0px -2rem;
}
h1 {
margin-left: 20rem;
margin-right: 20rem;
margin-left: 15rem;
margin-right: 15rem;
}
}
</style>

View file

@ -1,8 +1,11 @@
---
import '@fontsource/work-sans/500.css'
import '@fontsource/work-sans/600.css'
import { Image } from 'astro:assets'
import Layout from '../layouts/Layout.astro'
import BaseSection from '../layouts/baseSection.astro'
import sadshishou from '../assets/shishousad.webp'
import SmallTitle from '../components/titles/smallTitle.astro'
const description = "Error. This shouldn't happen :/"
---
@ -12,7 +15,7 @@ const description = "Error. This shouldn't happen :/"
currentpage="404"
descriptionOverride={description}
>
<BaseSection title="FirqhundredandFirq - Not Found">
<SmallTitle maintext='Error' subtext='FirqhundredandFirq - Not Found' fadeout={true}/>
<div>
<Image src={sadshishou} alt="Sad Shishou" />
<h2>Well ... you were not supposed to end up here.</h2>
@ -20,44 +23,51 @@ const description = "Error. This shouldn't happen :/"
&lt;&lt; Go back home
</a>
</div>
</BaseSection>
</Layout>
<style>
div {
padding: 0px 2rem;
display: flex;
flex-wrap: wrap;
flex-wrap: nowrap;
flex-direction: column;
align-items: center;
}
h2 {
font-family: 'Work Sans', 'Helvetica Neue', Helvetica, Helvetica, Arial, sans-serif;
font-weight: 500;
color: white;
font-size: 2rem;
font-weight: bold;
font-size: 1.25rem;
margin-top: 1rem;
max-width: max-content;
}
a {
display: flex;
align-items: center;
justify-content: center;
width: 75%;
text-align: center;
color: white;
background-color: var(--c-gray);
padding: 0.5rem 0px;
margin-bottom: 2rem;
text-decoration: none;
font-size: 1.5rem;
font-weight: bold;
&:hover {
color: var(--c-darkpurple);
font-style: italic;
}
a {
text-align: center;
width: fit-content;
font-weight: 600;
font-family: 'Work Sans', 'Helvetica Neue', Helvetica, Helvetica, Arial, sans-serif;
color: white;
margin: 1rem 0px 0px;
padding: 0.5rem 0.75rem;
text-decoration: none;
background-color: var(--c-darkergray);
border-radius: 10px;
border-style: solid;
border-width: 2px;
border-color: var(--c-darkergray);
text-transform: capitalize;
}
a:hover {
border-color: var(--c-darkpurple);
}
img {
width: 256px;
height: 256px;
width: 200px;
height: auto;
border-radius: 10%;
}
</style>

View file

@ -1,17 +1,19 @@
---
import Layout from '../layouts/Layout.astro'
import AboutSection from '../layouts/aboutSection.astro'
import ContactSection from '../layouts/contactSection.astro'
import ContactCard from '../components/contactCard.astro'
import ContactCard from '../components/cards/contactCard.astro'
import contactdata from '../../static/data/_contactdata.json'
import CustomFooter from '../layouts/customFooter.astro'
import TechnologyCard from '../components/technologyCard.astro'
import TechnologyCard from '../components/cards/technologyCard.astro'
import technologydata from '../../static/data/_technologydata.json'
import SmallTitle from '../components/titles/smallTitle.astro'
const description =
"A summary of the technologies used as well as my contact information. You'll also find disclaimers and thank you notes for the people that helped me."
const subtext =
"This is a small sideproject that I'm creating. First time doing webdev in general, and first project using Typescript."
---
<Layout
@ -19,10 +21,7 @@ const description =
currentpage="about"
descriptionOverride={description}
>
<AboutSection title="About">
This is a small sideproject that I'm creating. First time doing webdev in
general, and first project using Typescript.
</AboutSection>
<SmallTitle maintext="About" subtext={subtext} fadeout={true} />
<ContactSection title="Technologies used">
{technologydata.map((item) => <TechnologyCard {...item} />)}
</ContactSection>

View file

@ -1,35 +0,0 @@
---
import Layout from '../layouts/Layout.astro'
import BlogCard from '../components/blogCard.astro'
import BlogSection from '../layouts/blogSection.astro'
const description =
'My own small blog. Topics include FGO, TA, Programming, web technologies and more!'
const allPosts = await Astro.glob('../pages/blog/*.{md,mdx}')
allPosts.sort(
(a, b) =>
Date.parse(b.frontmatter.pubDate) - Date.parse(a.frontmatter.pubDate)
)
---
<Layout
title="Blog - Firq FGO Site"
currentpage="blog"
descriptionOverride={description}
>
<BlogSection title="Blog Articles">
{
allPosts.map((post) => (
<BlogCard
url={post.url}
title={post.frontmatter.title}
pubdate={post.frontmatter.pubDate}
description={post.frontmatter.description}
author={post.frontmatter.author}
/>
))
}
</BlogSection>
</Layout>
<style></style>

View file

@ -0,0 +1,17 @@
---
import { getCollection } from 'astro:content'
export async function getStaticPaths() {
const blogEntries = await getCollection('blog')
return blogEntries.map((entry) => ({
params: { slug: entry.slug },
props: { entry },
}))
}
const { entry } = Astro.props
const { Content } = await entry.render()
---
<Content />

View file

@ -0,0 +1,39 @@
---
import Layout from '../../layouts/Layout.astro'
import BlogCard from '../../components/cards/blogCard.astro'
import BlogSection from '../../layouts/blogSection.astro'
import SmallTitle from '../../components/titles/smallTitle.astro'
import { getCollection } from 'astro:content'
const description =
'My own small blog. Topics include FGO, TA, Programming, web technologies and more!'
const blogEntries = await getCollection('blog')
blogEntries.sort(
(a, b) =>
(b.data.pubDate.valueOf() - a.data.pubDate.valueOf() )
)
---
<Layout
title="Blog - Firq FGO Site"
currentpage="blog"
descriptionOverride={description}
>
<SmallTitle maintext="Blog Articles" subtext="" fadeout={true} />
<BlogSection title="Blog Articles" displayLine={true} titlehidden={true}>
{
blogEntries.map((post) => (
<BlogCard
url="blog"
slug={post.slug}
title={post.data.title}
pubdate={post.data.pubDate}
description={post.data.description}
author={post.data.author}
/>
))
}
</BlogSection>
</Layout>
<style></style>

View file

@ -1,9 +1,9 @@
---
import Layout from '../layouts/Layout.astro'
import Hero from '../components/hero.astro'
import BaseSection from '../layouts/baseSection.astro'
import FavouriteCard from '../components/favouriteCard.astro'
import FavouriteCard from '../components/cards/favouriteCard.astro'
import favouritesdata from '../../static/data/_favouritesdata.json'
import Hi from '../components/titles/title.astro'
const description =
'The very own page of Firq for providing informating about TA servants, listing past TA achievements and hosting a blog for talking about FGO, Programming and other stuff'
@ -14,7 +14,7 @@ const description =
currentpage="home"
descriptionOverride={description}
>
<Hero />
<Hi />
<BaseSection title="Favourites">
{favouritesdata.map((item) => <FavouriteCard {...item} />)}
</BaseSection>

View file

@ -2,11 +2,12 @@
import Layout from '../layouts/Layout.astro'
import BaseSection from '../layouts/baseSection.astro'
import ServantCard from '../components/servantCard.astro'
import ServantCard from '../components/cards/servantCard.astro'
import servantdata from '../../static/data/_servantdata.json'
import CeCard from '../components/ceCard.astro'
import CeCard from '../components/cards/ceCard.astro'
import cedata from '../../static/data/_cedata.json'
import SmallTitle from '../components/titles/smallTitle.astro'
const description =
'A list of all the servants and ces that Firq can offer up on support for TA.'
@ -17,6 +18,7 @@ const description =
currentpage="servants"
descriptionOverride={description}
>
<SmallTitle maintext='TA Offering' subtext='Servants and CEs I can offer for your TAs' fadeout={true}/>
<BaseSection title="Servants">
{servantdata.map((item) => <ServantCard {...item} />)}
</BaseSection>

View file

@ -8,10 +8,11 @@
import Layout from '../layouts/Layout.astro'
import TaSection from '../layouts/taSection.astro'
import TaCard from '../components/taCard.astro'
import TaCard from '../components/cards/taCard.astro'
import tadata from '../../static/data/_tadata.json'
import featured_data from '../../static/data/_featureddata.json'
import FgotaHero from '../components/fgotaHero.astro'
import SmallTitle from '../components/titles/smallTitle.astro'
const important_data = tadata.filter(function (el) {
return [
@ -37,7 +38,8 @@ const description = 'A collection of TAs previously completed be Firq.'
currentpage="ta-collection"
descriptionOverride={description}
>
<FgotaHero />
<SmallTitle maintext='TA Collection' subtext=''/>
<FgotaHero fadeout={true}/>
<TaSection title="Notable TAs" abovetext="My most notable TAs">
{important_data.map((item) => <TaCard {...item} />)}
</TaSection>