apply formatting rules
This commit is contained in:
@@ -1,28 +1,32 @@
|
|||||||
{
|
{
|
||||||
"$ref": "#/definitions/blog",
|
"$ref": "#/definitions/blog",
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"blog": {
|
"blog": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"pubDate": {
|
"pubDate": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"$schema": {
|
"$schema": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["title", "pubDate", "tags"],
|
"required": [
|
||||||
"additionalProperties": false
|
"title",
|
||||||
}
|
"pubDate",
|
||||||
},
|
"tags"
|
||||||
"$schema": "http://json-schema.org/draft-07/schema#"
|
],
|
||||||
}
|
"additionalProperties": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#"
|
||||||
|
}
|
||||||
@@ -1,37 +1,10 @@
|
|||||||
import __ASTRO_IMAGE_IMPORT_1OkzEl from "src/assets/blog/gunpla/all-the-parts.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md";
|
|
||||||
import __ASTRO_IMAGE_IMPORT_Zi2DqH from "src/assets/blog/gunpla/box.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md";
|
|
||||||
import __ASTRO_IMAGE_IMPORT_FYQiW from "src/assets/blog/gunpla/final.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md";
|
|
||||||
import __ASTRO_IMAGE_IMPORT_rrnp from "src/assets/blog/ileopard/ileopard-2-0-1.png?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md";
|
|
||||||
import __ASTRO_IMAGE_IMPORT_Z1ESWoO from "src/assets/blog/ileopard/itunes-7.gif?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md";
|
|
||||||
import __ASTRO_IMAGE_IMPORT_1G57ng from "src/assets/blog/ileopard/mac-os-10-1.png?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md";
|
import __ASTRO_IMAGE_IMPORT_1G57ng from "src/assets/blog/ileopard/mac-os-10-1.png?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md";
|
||||||
|
import __ASTRO_IMAGE_IMPORT_Z1ESWoO from "src/assets/blog/ileopard/itunes-7.gif?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md";
|
||||||
|
import __ASTRO_IMAGE_IMPORT_rrnp from "src/assets/blog/ileopard/ileopard-2-0-1.png?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md";
|
||||||
import __ASTRO_IMAGE_IMPORT_3KcDr from "src/assets/blog/my-ai-portrait.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fcreating-a-dating-profile-with-ai.md";
|
import __ASTRO_IMAGE_IMPORT_3KcDr from "src/assets/blog/my-ai-portrait.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fcreating-a-dating-profile-with-ai.md";
|
||||||
export default new Map([
|
import __ASTRO_IMAGE_IMPORT_Zi2DqH from "src/assets/blog/gunpla/box.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md";
|
||||||
[
|
import __ASTRO_IMAGE_IMPORT_1OkzEl from "src/assets/blog/gunpla/all-the-parts.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md";
|
||||||
"src/assets/blog/my-ai-portrait.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fcreating-a-dating-profile-with-ai.md",
|
import __ASTRO_IMAGE_IMPORT_FYQiW from "src/assets/blog/gunpla/final.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md";
|
||||||
__ASTRO_IMAGE_IMPORT_3KcDr,
|
export default new Map([["src/assets/blog/ileopard/mac-os-10-1.png?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md", __ASTRO_IMAGE_IMPORT_1G57ng], ["src/assets/blog/ileopard/itunes-7.gif?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md", __ASTRO_IMAGE_IMPORT_Z1ESWoO], ["src/assets/blog/ileopard/ileopard-2-0-1.png?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md", __ASTRO_IMAGE_IMPORT_rrnp], ["src/assets/blog/my-ai-portrait.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fcreating-a-dating-profile-with-ai.md", __ASTRO_IMAGE_IMPORT_3KcDr], ["src/assets/blog/gunpla/box.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md", __ASTRO_IMAGE_IMPORT_Zi2DqH], ["src/assets/blog/gunpla/all-the-parts.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md", __ASTRO_IMAGE_IMPORT_1OkzEl], ["src/assets/blog/gunpla/final.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md", __ASTRO_IMAGE_IMPORT_FYQiW]]);
|
||||||
],
|
|
||||||
[
|
|
||||||
"src/assets/blog/ileopard/mac-os-10-1.png?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md",
|
|
||||||
__ASTRO_IMAGE_IMPORT_1G57ng,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"src/assets/blog/ileopard/itunes-7.gif?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md",
|
|
||||||
__ASTRO_IMAGE_IMPORT_Z1ESWoO,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"src/assets/blog/ileopard/ileopard-2-0-1.png?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2022%2Fileopard-a-retrospective.md",
|
|
||||||
__ASTRO_IMAGE_IMPORT_rrnp,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"src/assets/blog/gunpla/box.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md",
|
|
||||||
__ASTRO_IMAGE_IMPORT_Zi2DqH,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"src/assets/blog/gunpla/all-the-parts.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md",
|
|
||||||
__ASTRO_IMAGE_IMPORT_1OkzEl,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"src/assets/blog/gunpla/final.jpg?astroContentImageFlag=&importer=src%2Fcontent%2Fblog%2F2023%2Fmy-gunpla-adventure.md",
|
|
||||||
__ASTRO_IMAGE_IMPORT_FYQiW,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
@@ -1 +1 @@
|
|||||||
export default new Map();
|
export default new Map();
|
||||||
Vendored
+58
-92
@@ -1,22 +1,22 @@
|
|||||||
declare module "astro:content" {
|
declare module 'astro:content' {
|
||||||
interface Render {
|
interface Render {
|
||||||
".mdx": Promise<{
|
'.mdx': Promise<{
|
||||||
Content: import("astro").MarkdownInstance<{}>["Content"];
|
Content: import('astro').MarkdownInstance<{}>['Content'];
|
||||||
headings: import("astro").MarkdownHeading[];
|
headings: import('astro').MarkdownHeading[];
|
||||||
remarkPluginFrontmatter: Record<string, any>;
|
remarkPluginFrontmatter: Record<string, any>;
|
||||||
components: import("astro").MDXInstance<{}>["components"];
|
components: import('astro').MDXInstance<{}>['components'];
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "astro:content" {
|
declare module 'astro:content' {
|
||||||
export interface RenderResult {
|
export interface RenderResult {
|
||||||
Content: import("astro/runtime/server/index.js").AstroComponentFactory;
|
Content: import('astro/runtime/server/index.js').AstroComponentFactory;
|
||||||
headings: import("astro").MarkdownHeading[];
|
headings: import('astro').MarkdownHeading[];
|
||||||
remarkPluginFrontmatter: Record<string, any>;
|
remarkPluginFrontmatter: Record<string, any>;
|
||||||
}
|
}
|
||||||
interface Render {
|
interface Render {
|
||||||
".md": Promise<RenderResult>;
|
'.md': Promise<RenderResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RenderedContent {
|
export interface RenderedContent {
|
||||||
@@ -28,13 +28,11 @@ declare module "astro:content" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "astro:content" {
|
declare module 'astro:content' {
|
||||||
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
|
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
|
||||||
|
|
||||||
export type CollectionKey = keyof AnyEntryMap;
|
export type CollectionKey = keyof AnyEntryMap;
|
||||||
export type CollectionEntry<C extends CollectionKey> = Flatten<
|
export type CollectionEntry<C extends CollectionKey> = Flatten<AnyEntryMap[C]>;
|
||||||
AnyEntryMap[C]
|
|
||||||
>;
|
|
||||||
|
|
||||||
export type ContentCollectionKey = keyof ContentEntryMap;
|
export type ContentCollectionKey = keyof ContentEntryMap;
|
||||||
export type DataCollectionKey = keyof DataEntryMap;
|
export type DataCollectionKey = keyof DataEntryMap;
|
||||||
@@ -42,7 +40,7 @@ declare module "astro:content" {
|
|||||||
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
|
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
|
||||||
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
|
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
|
||||||
ContentEntryMap[C]
|
ContentEntryMap[C]
|
||||||
>["slug"];
|
>['slug'];
|
||||||
|
|
||||||
export type ReferenceDataEntry<
|
export type ReferenceDataEntry<
|
||||||
C extends CollectionKey,
|
C extends CollectionKey,
|
||||||
@@ -58,9 +56,7 @@ declare module "astro:content" {
|
|||||||
collection: C;
|
collection: C;
|
||||||
slug: E;
|
slug: E;
|
||||||
};
|
};
|
||||||
export type ReferenceLiveEntry<
|
export type ReferenceLiveEntry<C extends keyof LiveContentConfig['collections']> = {
|
||||||
C extends keyof LiveContentConfig["collections"],
|
|
||||||
> = {
|
|
||||||
collection: C;
|
collection: C;
|
||||||
id: string;
|
id: string;
|
||||||
};
|
};
|
||||||
@@ -78,15 +74,12 @@ declare module "astro:content" {
|
|||||||
: Promise<CollectionEntry<C> | undefined>;
|
: Promise<CollectionEntry<C> | undefined>;
|
||||||
|
|
||||||
/** @deprecated Use `getEntry` instead. */
|
/** @deprecated Use `getEntry` instead. */
|
||||||
export function getDataEntryById<
|
export function getDataEntryById<C extends keyof DataEntryMap, E extends keyof DataEntryMap[C]>(
|
||||||
C extends keyof DataEntryMap,
|
collection: C,
|
||||||
E extends keyof DataEntryMap[C],
|
entryId: E,
|
||||||
>(collection: C, entryId: E): Promise<CollectionEntry<C>>;
|
): Promise<CollectionEntry<C>>;
|
||||||
|
|
||||||
export function getCollection<
|
export function getCollection<C extends keyof AnyEntryMap, E extends CollectionEntry<C>>(
|
||||||
C extends keyof AnyEntryMap,
|
|
||||||
E extends CollectionEntry<C>,
|
|
||||||
>(
|
|
||||||
collection: C,
|
collection: C,
|
||||||
filter?: (entry: CollectionEntry<C>) => entry is E,
|
filter?: (entry: CollectionEntry<C>) => entry is E,
|
||||||
): Promise<E[]>;
|
): Promise<E[]>;
|
||||||
@@ -95,16 +88,11 @@ declare module "astro:content" {
|
|||||||
filter?: (entry: CollectionEntry<C>) => unknown,
|
filter?: (entry: CollectionEntry<C>) => unknown,
|
||||||
): Promise<CollectionEntry<C>[]>;
|
): Promise<CollectionEntry<C>[]>;
|
||||||
|
|
||||||
export function getLiveCollection<
|
export function getLiveCollection<C extends keyof LiveContentConfig['collections']>(
|
||||||
C extends keyof LiveContentConfig["collections"],
|
|
||||||
>(
|
|
||||||
collection: C,
|
collection: C,
|
||||||
filter?: LiveLoaderCollectionFilterType<C>,
|
filter?: LiveLoaderCollectionFilterType<C>,
|
||||||
): Promise<
|
): Promise<
|
||||||
import("astro").LiveDataCollectionResult<
|
import('astro').LiveDataCollectionResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>
|
||||||
LiveLoaderDataType<C>,
|
|
||||||
LiveLoaderErrorType<C>
|
|
||||||
>
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export function getEntry<
|
export function getEntry<
|
||||||
@@ -143,17 +131,10 @@ declare module "astro:content" {
|
|||||||
? Promise<DataEntryMap[C][E]> | undefined
|
? Promise<DataEntryMap[C][E]> | undefined
|
||||||
: Promise<DataEntryMap[C][E]>
|
: Promise<DataEntryMap[C][E]>
|
||||||
: Promise<CollectionEntry<C> | undefined>;
|
: Promise<CollectionEntry<C> | undefined>;
|
||||||
export function getLiveEntry<
|
export function getLiveEntry<C extends keyof LiveContentConfig['collections']>(
|
||||||
C extends keyof LiveContentConfig["collections"],
|
|
||||||
>(
|
|
||||||
collection: C,
|
collection: C,
|
||||||
filter: string | LiveLoaderEntryFilterType<C>,
|
filter: string | LiveLoaderEntryFilterType<C>,
|
||||||
): Promise<
|
): Promise<import('astro').LiveDataEntryResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>>;
|
||||||
import("astro").LiveDataEntryResult<
|
|
||||||
LiveLoaderDataType<C>,
|
|
||||||
LiveLoaderErrorType<C>
|
|
||||||
>
|
|
||||||
>;
|
|
||||||
|
|
||||||
/** Resolve an array of entry references from the same collection */
|
/** Resolve an array of entry references from the same collection */
|
||||||
export function getEntries<C extends keyof ContentEntryMap>(
|
export function getEntries<C extends keyof ContentEntryMap>(
|
||||||
@@ -169,8 +150,8 @@ declare module "astro:content" {
|
|||||||
|
|
||||||
export function reference<C extends keyof AnyEntryMap>(
|
export function reference<C extends keyof AnyEntryMap>(
|
||||||
collection: C,
|
collection: C,
|
||||||
): import("astro/zod").ZodEffects<
|
): import('astro/zod').ZodEffects<
|
||||||
import("astro/zod").ZodString,
|
import('astro/zod').ZodString,
|
||||||
C extends keyof ContentEntryMap
|
C extends keyof ContentEntryMap
|
||||||
? ReferenceContentEntry<C, ValidContentEntrySlug<C>>
|
? ReferenceContentEntry<C, ValidContentEntrySlug<C>>
|
||||||
: ReferenceDataEntry<C, keyof DataEntryMap[C]>
|
: ReferenceDataEntry<C, keyof DataEntryMap[C]>
|
||||||
@@ -180,72 +161,57 @@ declare module "astro:content" {
|
|||||||
// Invalid collection names will be caught at build time.
|
// Invalid collection names will be caught at build time.
|
||||||
export function reference<C extends string>(
|
export function reference<C extends string>(
|
||||||
collection: C,
|
collection: C,
|
||||||
): import("astro/zod").ZodEffects<import("astro/zod").ZodString, never>;
|
): import('astro/zod').ZodEffects<import('astro/zod').ZodString, never>;
|
||||||
|
|
||||||
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
|
type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
|
||||||
type InferEntrySchema<C extends keyof AnyEntryMap> =
|
type InferEntrySchema<C extends keyof AnyEntryMap> = import('astro/zod').infer<
|
||||||
import("astro/zod").infer<
|
ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
|
||||||
ReturnTypeOrOriginal<Required<ContentConfig["collections"][C]>["schema"]>
|
>;
|
||||||
>;
|
|
||||||
|
|
||||||
type ContentEntryMap = {};
|
type ContentEntryMap = {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
type DataEntryMap = {
|
type DataEntryMap = {
|
||||||
blog: Record<
|
"blog": Record<string, {
|
||||||
string,
|
id: string;
|
||||||
{
|
body?: string;
|
||||||
id: string;
|
collection: "blog";
|
||||||
body?: string;
|
data: InferEntrySchema<"blog">;
|
||||||
collection: "blog";
|
rendered?: RenderedContent;
|
||||||
data: InferEntrySchema<"blog">;
|
filePath?: string;
|
||||||
rendered?: RenderedContent;
|
}>;
|
||||||
filePath?: string;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type AnyEntryMap = ContentEntryMap & DataEntryMap;
|
type AnyEntryMap = ContentEntryMap & DataEntryMap;
|
||||||
|
|
||||||
type ExtractLoaderTypes<T> = T extends import("astro/loaders").LiveLoader<
|
type ExtractLoaderTypes<T> = T extends import('astro/loaders').LiveLoader<
|
||||||
infer TData,
|
infer TData,
|
||||||
infer TEntryFilter,
|
infer TEntryFilter,
|
||||||
infer TCollectionFilter,
|
infer TCollectionFilter,
|
||||||
infer TError
|
infer TError
|
||||||
>
|
>
|
||||||
? {
|
? { data: TData; entryFilter: TEntryFilter; collectionFilter: TCollectionFilter; error: TError }
|
||||||
data: TData;
|
: { data: never; entryFilter: never; collectionFilter: never; error: never };
|
||||||
entryFilter: TEntryFilter;
|
type ExtractDataType<T> = ExtractLoaderTypes<T>['data'];
|
||||||
collectionFilter: TCollectionFilter;
|
type ExtractEntryFilterType<T> = ExtractLoaderTypes<T>['entryFilter'];
|
||||||
error: TError;
|
type ExtractCollectionFilterType<T> = ExtractLoaderTypes<T>['collectionFilter'];
|
||||||
}
|
type ExtractErrorType<T> = ExtractLoaderTypes<T>['error'];
|
||||||
: {
|
|
||||||
data: never;
|
|
||||||
entryFilter: never;
|
|
||||||
collectionFilter: never;
|
|
||||||
error: never;
|
|
||||||
};
|
|
||||||
type ExtractDataType<T> = ExtractLoaderTypes<T>["data"];
|
|
||||||
type ExtractEntryFilterType<T> = ExtractLoaderTypes<T>["entryFilter"];
|
|
||||||
type ExtractCollectionFilterType<T> =
|
|
||||||
ExtractLoaderTypes<T>["collectionFilter"];
|
|
||||||
type ExtractErrorType<T> = ExtractLoaderTypes<T>["error"];
|
|
||||||
|
|
||||||
type LiveLoaderDataType<C extends keyof LiveContentConfig["collections"]> =
|
type LiveLoaderDataType<C extends keyof LiveContentConfig['collections']> =
|
||||||
LiveContentConfig["collections"][C]["schema"] extends undefined
|
LiveContentConfig['collections'][C]['schema'] extends undefined
|
||||||
? ExtractDataType<LiveContentConfig["collections"][C]["loader"]>
|
? ExtractDataType<LiveContentConfig['collections'][C]['loader']>
|
||||||
: import("astro/zod").infer<
|
: import('astro/zod').infer<
|
||||||
Exclude<LiveContentConfig["collections"][C]["schema"], undefined>
|
Exclude<LiveContentConfig['collections'][C]['schema'], undefined>
|
||||||
>;
|
>;
|
||||||
type LiveLoaderEntryFilterType<
|
type LiveLoaderEntryFilterType<C extends keyof LiveContentConfig['collections']> =
|
||||||
C extends keyof LiveContentConfig["collections"],
|
ExtractEntryFilterType<LiveContentConfig['collections'][C]['loader']>;
|
||||||
> = ExtractEntryFilterType<LiveContentConfig["collections"][C]["loader"]>;
|
type LiveLoaderCollectionFilterType<C extends keyof LiveContentConfig['collections']> =
|
||||||
type LiveLoaderCollectionFilterType<
|
ExtractCollectionFilterType<LiveContentConfig['collections'][C]['loader']>;
|
||||||
C extends keyof LiveContentConfig["collections"],
|
type LiveLoaderErrorType<C extends keyof LiveContentConfig['collections']> = ExtractErrorType<
|
||||||
> = ExtractCollectionFilterType<
|
LiveContentConfig['collections'][C]['loader']
|
||||||
LiveContentConfig["collections"][C]["loader"]
|
|
||||||
>;
|
>;
|
||||||
type LiveLoaderErrorType<C extends keyof LiveContentConfig["collections"]> =
|
|
||||||
ExtractErrorType<LiveContentConfig["collections"][C]["loader"]>;
|
|
||||||
|
|
||||||
export type ContentConfig = typeof import("../src/content.config.js");
|
export type ContentConfig = typeof import("../src/content.config.js");
|
||||||
export type LiveContentConfig = never;
|
export type LiveContentConfig = never;
|
||||||
|
|||||||
+1
-2087
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
/// <reference types="astro/client" />
|
/// <reference types="astro/client" />
|
||||||
/// <reference path="content.d.ts" />
|
/// <reference path="content.d.ts" />
|
||||||
+14
-15
@@ -1,31 +1,30 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
|
|
||||||
import portrait from "../assets/portrait.jpg";
|
import portrait from "../assets/portrait.jpg";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
size: number;
|
size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { size } = Astro.props;
|
const { size } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<Image
|
<Image
|
||||||
src={portrait}
|
src={portrait}
|
||||||
alt="Illustrated portrait of a person with glasses and a beard, wearing a red and black plaid shirt. The background is a solid green color."
|
alt="Illustrated portrait of a person with glasses and a beard, wearing a red and black plaid shirt. The background is a solid green color."
|
||||||
class="portrait"
|
class="portrait"
|
||||||
width={`${size}`}
|
width={`${size}`}
|
||||||
height={`${size}`}
|
height={`${size}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.portrait {
|
.portrait {
|
||||||
display: block;
|
display: block;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
border-radius: 200px;
|
border-radius: 200px;
|
||||||
}
|
}
|
||||||
a > svg {
|
a > svg {
|
||||||
transform: translateY(0.18rem);
|
transform: translateY(0.18rem);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,44 +1,43 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import { add, format } from "date-fns";
|
import { add, format } from "date-fns";
|
||||||
|
|
||||||
import CalendarIcon from "../assets/svg/calendar.svg";
|
import CalendarIcon from "../assets/svg/calendar.svg";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
slug?: string;
|
slug?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, date, slug } = Astro.props;
|
const { title, date, slug } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="blog-header">
|
<div class="blog-header">
|
||||||
{slug ? <a href={`/blog/${slug}`}>{title}</a> : <h1>{title}</h1>}
|
{slug ? <a href={`/blog/${slug}`}>{title}</a> : <h1>{title}</h1>}
|
||||||
<div>
|
<div>
|
||||||
<CalendarIcon class="calendar-icon" width={24} height={24} />
|
<CalendarIcon class="calendar-icon" width={24} height={24} />
|
||||||
<strong>{format(add(new Date(date), { hours: 6 }), 'MMM do, y')}</strong>
|
<strong>{format(add(new Date(date), { hours: 6 }), "MMM do, y")}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
a {
|
a {
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
font-weight: bolder;
|
font-weight: bolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-header {
|
.blog-header {
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blog-header > h2 {
|
.blog-header > h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-icon {
|
.calendar-icon {
|
||||||
transform: translateY(0.3rem);
|
transform: translateY(0.3rem);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+39
-40
@@ -1,55 +1,54 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title?: string;
|
title?: string;
|
||||||
image?: ImageMetadata;
|
image?: ImageMetadata;
|
||||||
links?: {
|
links?: {
|
||||||
label: string;
|
label: string;
|
||||||
href: string;
|
href: string;
|
||||||
newWindow?: boolean;
|
newWindow?: boolean;
|
||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, image, links } = Astro.props;
|
const { title, image, links } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
{image && <img src={image.src} alt="" />}
|
{image && <img src={image.src} alt="" />}
|
||||||
<div>
|
<div>
|
||||||
{title && <h2>{title}</h2>}
|
{title && <h2>{title}</h2>}
|
||||||
<slot />
|
<slot />
|
||||||
{
|
{
|
||||||
links &&
|
links &&
|
||||||
links.map((link) => (
|
links.map((link) => (
|
||||||
<a
|
<a
|
||||||
href={link.href}
|
href={link.href}
|
||||||
target={link.newWindow ? '_blank' : '_self'}
|
target={link.newWindow ? "_blank" : "_self"}
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
{link.label}
|
{link.label}
|
||||||
</a>
|
</a>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.card {
|
.card {
|
||||||
border: var(--border);
|
border: var(--border);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card > div {
|
.card > div {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+46
-47
@@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import MastodonIcon from "../assets/svg/mastodon.svg";
|
import MastodonIcon from "../assets/svg/mastodon.svg";
|
||||||
import RssIcon from "../assets/svg/rss.svg";
|
import RssIcon from "../assets/svg/rss.svg";
|
||||||
|
|
||||||
@@ -7,61 +6,61 @@ const year = new Date().getFullYear();
|
|||||||
---
|
---
|
||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<div class="socials">
|
<div class="socials">
|
||||||
<a
|
<a
|
||||||
href="https://mastodon.social/@ghalldev"
|
href="https://mastodon.social/@ghalldev"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
><MastodonIcon class="mastodon-icon" width={20} height={20} /> Follow me on
|
><MastodonIcon class="mastodon-icon" width={20} height={20} /> Follow me on
|
||||||
Mastodon</a
|
Mastodon</a
|
||||||
>
|
>
|
||||||
|
|
||||||
<a href="/rss.xml"
|
<a href="/rss.xml"
|
||||||
><RssIcon class="rss-icon" width={20} height={20} /> Subscribe with RSS</a
|
><RssIcon class="rss-icon" width={20} height={20} /> Subscribe with RSS</a
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
Copyright 2022 - {year}, Graham Hall
|
Copyright 2022 - {year}, Graham Hall
|
||||||
|
|
||||||
<br />
|
<br />
|
||||||
Built with <a href="https://astro.build">Astro</a>
|
Built with <a href="https://astro.build">Astro</a>
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
footer {
|
footer {
|
||||||
margin: 2rem 0;
|
margin: 2rem 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border-top: var(--border);
|
border-top: var(--border);
|
||||||
padding-top: 24px;
|
padding-top: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rss-icon {
|
.rss-icon {
|
||||||
transform: translateY(0.18rem);
|
transform: translateY(0.18rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
.socials {
|
.socials {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.socials a {
|
.socials a {
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.rss-icon {
|
.rss-icon {
|
||||||
color: var(--orange);
|
color: var(--orange);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mastodon-icon {
|
.mastodon-icon {
|
||||||
color: var(--blue);
|
color: var(--blue);
|
||||||
transform: translateY(4px);
|
transform: translateY(4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 516px) {
|
@media (max-width: 516px) {
|
||||||
.socials {
|
.socials {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import BarsIcon from "../../assets/svg/bars.svg";
|
import BarsIcon from "../../assets/svg/bars.svg";
|
||||||
import CloseIcon from "../../assets/svg/xmark.svg";
|
import CloseIcon from "../../assets/svg/xmark.svg";
|
||||||
|
|
||||||
@@ -8,94 +7,94 @@ import { navLinks } from "../../data/nav-links";
|
|||||||
|
|
||||||
<!-- drawerOpened is defined in /src/layouts/Layout.astro -->
|
<!-- drawerOpened is defined in /src/layouts/Layout.astro -->
|
||||||
<div class="drawer-container" @keydown.escape="drawerOpen = false">
|
<div class="drawer-container" @keydown.escape="drawerOpen = false">
|
||||||
<button class="icon-button" @click="drawerOpen = !drawerOpen">
|
<button class="icon-button" @click="drawerOpen = !drawerOpen">
|
||||||
<BarsIcon width={24} height={24} />
|
<BarsIcon width={24} height={24} />
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
class="overlay"
|
class="overlay"
|
||||||
@click="drawerOpen = !drawerOpen"
|
@click="drawerOpen = !drawerOpen"
|
||||||
x-show="drawerOpen"
|
x-show="drawerOpen"
|
||||||
x-transition:enter-start="hidden-overlay"
|
x-transition:enter-start="hidden-overlay"
|
||||||
x-transition:enter-end="visible-overlay"
|
x-transition:enter-end="visible-overlay"
|
||||||
x-transition:leave-start="visible-overlay"
|
x-transition:leave-start="visible-overlay"
|
||||||
x-transition:leave-end="hidden-overlay"
|
x-transition:leave-end="hidden-overlay"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="drawer"
|
class="drawer"
|
||||||
x-show="drawerOpen"
|
x-show="drawerOpen"
|
||||||
x-transition:enter-start="hidden-drawer"
|
x-transition:enter-start="hidden-drawer"
|
||||||
x-transition:enter-end="visible-drawer"
|
x-transition:enter-end="visible-drawer"
|
||||||
x-transition:leave-start="visible-drawer"
|
x-transition:leave-start="visible-drawer"
|
||||||
x-transition:leave-end="hidden-drawer"
|
x-transition:leave-end="hidden-drawer"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<button class="icon-button" @click="drawerOpen = !drawerOpen">
|
<button class="icon-button" @click="drawerOpen = !drawerOpen">
|
||||||
<CloseIcon width={24} height={24} /></button
|
<CloseIcon width={24} height={24} /></button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<nav>
|
<nav>
|
||||||
{navLinks.map((link) => <a href={`/${link.path}`}>{link.label}</a>)}
|
{navLinks.map((link) => <a href={`/${link.path}`}>{link.label}</a>)}
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
--transition: all 0.3s ease-in-out;
|
--transition: all 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.drawer-container {
|
.drawer-container {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.overlay {
|
.overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background-color: rgba(0, 0, 0, 0.6);
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
transition: var(--transition);
|
transition: var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden-overlay {
|
.hidden-overlay {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.drawer {
|
.drawer {
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 75vw;
|
width: 75vw;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
transition: var(--transition);
|
transition: var(--transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
.drawer > div {
|
.drawer > div {
|
||||||
padding: 8px 6px 4px;
|
padding: 8px 6px 4px;
|
||||||
border-bottom: var(--border);
|
border-bottom: var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
nav {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hidden-drawer {
|
.hidden-drawer {
|
||||||
transform: translateX(75vw);
|
transform: translateX(75vw);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
.drawer-container {
|
.drawer-container {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,50 +1,49 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import Drawer from "./Drawer.astro";
|
import Drawer from "./Drawer.astro";
|
||||||
import Nav from "./Nav.astro";
|
import Nav from "./Nav.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a href="/">ghall.space</a>
|
<a href="/">ghall.space</a>
|
||||||
<Nav />
|
<Nav />
|
||||||
<Drawer />
|
<Drawer />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
header {
|
header {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
height: 70px;
|
height: 70px;
|
||||||
background-color: rgba(252, 252, 252, 90%);
|
background-color: rgba(252, 252, 252, 90%);
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
top: 0;
|
top: 0;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
border-bottom: var(--border);
|
border-bottom: var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
max-width: var(--max-page-width);
|
max-width: var(--max-page-width);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
font-size: 1.6rem;
|
font-size: 1.6rem;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
header {
|
header {
|
||||||
background-color: rgba(30, 30, 46, 90%);
|
background-color: rgba(30, 30, 46, 90%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,65 +1,64 @@
|
|||||||
---
|
---
|
||||||
|
import { navLinks } from "../../data/nav-links";
|
||||||
import { navLinks } from '../../data/nav-links';
|
|
||||||
|
|
||||||
const { pathname } = Astro.url;
|
const { pathname } = Astro.url;
|
||||||
|
|
||||||
const pathComponents = pathname.split('/').slice(1);
|
const pathComponents = pathname.split("/").slice(1);
|
||||||
---
|
---
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
{
|
{
|
||||||
navLinks.map((link) => (
|
navLinks.map((link) => (
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
href={`/${link.path}`}
|
href={`/${link.path}`}
|
||||||
class={pathComponents[0] === link.path ? 'selected' : null}
|
class={pathComponents[0] === link.path ? "selected" : null}
|
||||||
>
|
>
|
||||||
{link.label}
|
{link.label}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
nav {
|
nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
font-size: 1.15rem;
|
font-size: 1.15rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
padding: 5px 10px;
|
padding: 5px 10px;
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
transition: background-color 0.2s ease-in-out;
|
transition: background-color 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
background-color: rgba(0, 0, 0, 0.04);
|
background-color: rgba(0, 0, 0, 0.04);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.underline {
|
.underline {
|
||||||
height: 2px;
|
height: 2px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: var(--orange);
|
background-color: var(--orange);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
nav {
|
nav {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
a:hover {
|
a:hover {
|
||||||
background-color: rgba(231, 237, 255, 0.1);
|
background-color: rgba(231, 237, 255, 0.1);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<div
|
<div
|
||||||
x-data="{
|
x-data="{
|
||||||
latestPost: null,
|
latestPost: null,
|
||||||
fetchPost() {
|
fetchPost() {
|
||||||
fetch('https://mastodon.social/@ghalldev.rss')
|
fetch('https://mastodon.social/@ghalldev.rss')
|
||||||
@@ -21,32 +21,32 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
}"
|
}"
|
||||||
x-init="fetchPost()"
|
x-init="fetchPost()"
|
||||||
>
|
>
|
||||||
<template x-if="latestPost">
|
<template x-if="latestPost">
|
||||||
<div class="mastodon-post">
|
<div class="mastodon-post">
|
||||||
<h2>Latest Mastodon Post</h2>
|
<h2>Latest Mastodon Post</h2>
|
||||||
<div x-html="latestPost.body"></div>
|
<div x-html="latestPost.body"></div>
|
||||||
<a x-bind:href="latestPost.link" target="_blank" rel="noopener noreferrer"
|
<a x-bind:href="latestPost.link" target="_blank" rel="noopener noreferrer"
|
||||||
>View Post</a
|
>View Post</a
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template x-if="!latestPost">
|
<template x-if="!latestPost">
|
||||||
<p>Loading...</p>
|
<p>Loading...</p>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.mastodon-post {
|
.mastodon-post {
|
||||||
margin: 2rem auto;
|
margin: 2rem auto;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
border: var(--border);
|
border: var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mastodon-post > h2 {
|
.mastodon-post > h2 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,27 +1,26 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import type { CollectionEntry } from "astro:content";
|
import type { CollectionEntry } from "astro:content";
|
||||||
import BlogHeader from "@components/BlogHeader.astro";
|
import BlogHeader from "@components/BlogHeader.astro";
|
||||||
import Tags from "@components/Tags.astro";
|
import Tags from "@components/Tags.astro";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
post: CollectionEntry<"blog">;
|
post: CollectionEntry<"blog">;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<article>
|
<article>
|
||||||
<BlogHeader title={post.data.title} date={post.data.pubDate} slug={post.id} />
|
<BlogHeader title={post.data.title} date={post.data.pubDate} slug={post.id} />
|
||||||
<Tags tags={post.data.tags} />
|
<Tags tags={post.data.tags} />
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
article {
|
article {
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
article:not(:first-child) {
|
article:not(:first-child) {
|
||||||
border-top: var(--border);
|
border-top: var(--border);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+11
-12
@@ -1,21 +1,20 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tags: string[];
|
tags: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { tags } = Astro.props;
|
const { tags } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
{
|
{
|
||||||
tags.sort().map((tag: string, index: number) => (
|
tags.sort().map((tag: string, index: number) => (
|
||||||
<>
|
<>
|
||||||
<a class="tag" href={`/blog/tag/${tag}`}>
|
<a class="tag" href={`/blog/tag/${tag}`}>
|
||||||
{tag}
|
{tag}
|
||||||
</a>
|
</a>
|
||||||
{index < tags.length - 1 ? ' | ' : ''}
|
{index < tags.length - 1 ? " | " : ""}
|
||||||
</>
|
</>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
-2241
File diff suppressed because it is too large
Load Diff
+34
-35
@@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import { ClientRouter } from "astro:transitions";
|
import { ClientRouter } from "astro:transitions";
|
||||||
|
|
||||||
import "../global.css";
|
import "../global.css";
|
||||||
@@ -8,10 +7,10 @@ import Footer from "@components/Footer.astro";
|
|||||||
import Header from "@components/Header/Header.astro";
|
import Header from "@components/Header/Header.astro";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
title: string;
|
title: string;
|
||||||
frontmatter?: {
|
frontmatter?: {
|
||||||
title: string;
|
title: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = Astro.props.title || Astro.props.frontmatter?.title || "Unknown";
|
const title = Astro.props.title || Astro.props.frontmatter?.title || "Unknown";
|
||||||
@@ -19,37 +18,37 @@ const title = Astro.props.title || Astro.props.frontmatter?.title || "Unknown";
|
|||||||
|
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<meta name="robots" content="noindex" /><meta
|
<meta name="robots" content="noindex" /><meta
|
||||||
name="description"
|
name="description"
|
||||||
content="My little space on the World Wide Web."
|
content="My little space on the World Wide Web."
|
||||||
/><link
|
/><link
|
||||||
rel="alternate"
|
rel="alternate"
|
||||||
type="application/rss+xml"
|
type="application/rss+xml"
|
||||||
title="ghall.space - RSS"
|
title="ghall.space - RSS"
|
||||||
href={`${Astro.site}rss.xml`}
|
href={`${Astro.site}rss.xml`}
|
||||||
/><title>{`ghall.space - ${title}`}</title>
|
/><title>{`ghall.space - ${title}`}</title>
|
||||||
<ClientRouter />
|
<ClientRouter />
|
||||||
</head>
|
</head>
|
||||||
<body
|
<body
|
||||||
class="layout-simple"
|
class="layout-simple"
|
||||||
x-data="{ drawerOpen: false }"
|
x-data="{ drawerOpen: false }"
|
||||||
:class="drawerOpen ? 'lock-scroll' : ''"
|
:class="drawerOpen ? 'lock-scroll' : ''"
|
||||||
>
|
>
|
||||||
<Header />
|
<Header />
|
||||||
<main transition:animate="initial">
|
<main transition:animate="initial">
|
||||||
<slot />
|
<slot />
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* Prevent scrolling when drawer (located in Header) is open */
|
/* Prevent scrolling when drawer (located in Header) is open */
|
||||||
.lock-scroll {
|
.lock-scroll {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+15
-16
@@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import { Image } from "astro:assets";
|
import { Image } from "astro:assets";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
|
|
||||||
@@ -7,23 +6,23 @@ import DataGif from "../assets/it-does-not-exist.gif";
|
|||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Not Found">
|
<Layout title="Not Found">
|
||||||
<h2>404 - Page Not Found</h2>
|
<h2>404 - Page Not Found</h2>
|
||||||
<Image
|
<Image
|
||||||
class="gif"
|
class="gif"
|
||||||
src={DataGif}
|
src={DataGif}
|
||||||
alt="Data from Star Trek with the caption 'It does not exist'"
|
alt="Data from Star Trek with the caption 'It does not exist'"
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
h2 {
|
h2 {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gif {
|
.gif {
|
||||||
display: block;
|
display: block;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
box-shadow: var(--shadow);
|
box-shadow: var(--shadow);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import { getCollection, render } from "astro:content";
|
import { getCollection, render } from "astro:content";
|
||||||
import BlogHeader from "@components/BlogHeader.astro";
|
import BlogHeader from "@components/BlogHeader.astro";
|
||||||
import Tags from "@components/Tags.astro";
|
import Tags from "@components/Tags.astro";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const posts = await getCollection("blog");
|
const posts = await getCollection("blog");
|
||||||
return posts.map((post) => ({
|
return posts.map((post) => ({
|
||||||
params: { slug: post.id },
|
params: { slug: post.id },
|
||||||
props: { post },
|
props: { post },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { post } = Astro.props;
|
const { post } = Astro.props;
|
||||||
@@ -21,31 +20,30 @@ const { Content } = await render(post);
|
|||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={data.title}>
|
<Layout title={data.title}>
|
||||||
<h1></h1>
|
<article>
|
||||||
<article>
|
<BlogHeader title={data.title} date={data.pubDate} />
|
||||||
<BlogHeader title={data.title} date={data.pubDate} />
|
<Content />
|
||||||
<Content />
|
<a href="https://notbyai.fyi/">
|
||||||
<a href="https://notbyai.fyi/">
|
<i class="not-by-ai"></i>
|
||||||
<i class="not-by-ai"></i>
|
</a>
|
||||||
</a>
|
<Tags tags={data.tags} />
|
||||||
<Tags tags={data.tags} />
|
</article>
|
||||||
</article>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.not-by-ai {
|
.not-by-ai {
|
||||||
display: block;
|
display: block;
|
||||||
width: 134px;
|
width: 134px;
|
||||||
height: 45px;
|
height: 45px;
|
||||||
background-image: url(../../assets/svg/Written-By-Human-Not-By-AI-Badge-white.svg);
|
background-image: url(../../assets/svg/Written-By-Human-Not-By-AI-Badge-white.svg);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
margin: 1rem 0;
|
margin: 1rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
.not-by-ai {
|
.not-by-ai {
|
||||||
background-image: url(../../assets/svg/Written-By-Human-Not-By-AI-Badge-black.svg);
|
background-image: url(../../assets/svg/Written-By-Human-Not-By-AI-Badge-black.svg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,65 +1,64 @@
|
|||||||
---
|
---
|
||||||
|
import { type CollectionEntry, getCollection } from "astro:content";
|
||||||
|
import PostPreview from "@components/PostPreview.astro";
|
||||||
|
|
||||||
import { type CollectionEntry, getCollection } from 'astro:content';
|
import Layout from "@layouts/Layout.astro";
|
||||||
import PostPreview from '@components/PostPreview.astro';
|
import type { Page } from "astro";
|
||||||
|
|
||||||
import Layout from '@layouts/Layout.astro';
|
|
||||||
import type { Page } from 'astro';
|
|
||||||
|
|
||||||
export async function getStaticPaths({ paginate }) {
|
export async function getStaticPaths({ paginate }) {
|
||||||
const allPosts = await getCollection('blog');
|
const allPosts = await getCollection("blog");
|
||||||
|
|
||||||
allPosts.sort(
|
allPosts.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
Date.parse(String(b.data.pubDate)) - Date.parse(String(a.data.pubDate))
|
Date.parse(String(b.data.pubDate)) - Date.parse(String(a.data.pubDate)),
|
||||||
);
|
);
|
||||||
|
|
||||||
return paginate(allPosts, { pageSize: 10 });
|
return paginate(allPosts, { pageSize: 10 });
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
page: Page<CollectionEntry<'blog'>>;
|
page: Page<CollectionEntry<"blog">>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { page } = Astro.props;
|
const { page } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Blog Archive">
|
<Layout title="Blog Archive">
|
||||||
{page.data.map((post) => <PostPreview post={post} />)}
|
{page.data.map((post) => <PostPreview post={post} />)}
|
||||||
|
|
||||||
<div class="pagination">
|
<div class="pagination">
|
||||||
{
|
{
|
||||||
page.currentPage !== 1 ? (
|
page.currentPage !== 1 ? (
|
||||||
<a href={`/blog/page/${page.currentPage - 1}`}>Previous</a>
|
<a href={`/blog/page/${page.currentPage - 1}`}>Previous</a>
|
||||||
) : (
|
) : (
|
||||||
<span class="disabled">Previous</span>
|
<span class="disabled">Previous</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
page.currentPage !== page.lastPage ? (
|
page.currentPage !== page.lastPage ? (
|
||||||
<a href={`/blog/page/${page.currentPage + 1}`}>Next</a>
|
<a href={`/blog/page/${page.currentPage + 1}`}>Next</a>
|
||||||
) : (
|
) : (
|
||||||
<span class="disabled">Next</span>
|
<span class="disabled">Next</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
ul {
|
ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination {
|
.pagination {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.disabled {
|
.disabled {
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,73 +1,72 @@
|
|||||||
---
|
---
|
||||||
|
import { getCollection } from "astro:content";
|
||||||
import { getCollection } from 'astro:content';
|
import Layout from "@layouts/Layout.astro";
|
||||||
import Layout from '@layouts/Layout.astro';
|
import { add, format } from "date-fns";
|
||||||
import { add, format } from 'date-fns';
|
|
||||||
|
|
||||||
export async function getStaticPaths() {
|
export async function getStaticPaths() {
|
||||||
const posts = await getCollection('blog');
|
const posts = await getCollection("blog");
|
||||||
|
|
||||||
const tags = ['all'];
|
const tags = ["all"];
|
||||||
|
|
||||||
posts.forEach((post) => {
|
posts.forEach((post) => {
|
||||||
post.data.tags.forEach((tag) => {
|
post.data.tags.forEach((tag) => {
|
||||||
if (!tags.includes(tag)) {
|
if (!tags.includes(tag)) {
|
||||||
tags.push(tag);
|
tags.push(tag);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return tags.map((tag) => ({
|
return tags.map((tag) => ({
|
||||||
params: { tag },
|
params: { tag },
|
||||||
props: { tag },
|
props: { tag },
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { tag }: { tag?: string } = Astro.params;
|
const { tag }: { tag?: string } = Astro.params;
|
||||||
|
|
||||||
const posts = await getCollection('blog', ({ data }) => {
|
const posts = await getCollection("blog", ({ data }) => {
|
||||||
if (!tag) {
|
if (!tag) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tag === 'all') {
|
if (tag === "all") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data.tags.includes(tag);
|
return data.tags.includes(tag);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (posts.length === 0) {
|
if (posts.length === 0) {
|
||||||
return Astro.redirect('/404');
|
return Astro.redirect("/404");
|
||||||
}
|
}
|
||||||
|
|
||||||
posts.sort(
|
posts.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
Date.parse(String(b.data.pubDate)) - Date.parse(String(a.data.pubDate))
|
Date.parse(String(b.data.pubDate)) - Date.parse(String(a.data.pubDate)),
|
||||||
);
|
);
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={`Blog - ${tag}`}>
|
<Layout title={`Blog - ${tag}`}>
|
||||||
<h1>All posts tagged: {tag}</h1>
|
<h1>All posts tagged: {tag}</h1>
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
posts.map((post) => (
|
posts.map((post) => (
|
||||||
<li>
|
<li>
|
||||||
<a href={`/posts/${post.id}`}>{post.data.title}</a> -
|
<a href={`/posts/${post.id}`}>{post.data.title}</a> -
|
||||||
<span>
|
<span>
|
||||||
{format(
|
{format(
|
||||||
add(new Date(post.data.pubDate), { hours: 6 }),
|
add(new Date(post.data.pubDate), { hours: 6 }),
|
||||||
'MMM do, y'
|
"MMM do, y",
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
ul {
|
ul {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+53
-54
@@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
export const prerender = true;
|
export const prerender = true;
|
||||||
|
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
@@ -13,64 +12,64 @@ const iconSize = 16;
|
|||||||
const posts = await getCollection("blog");
|
const posts = await getCollection("blog");
|
||||||
|
|
||||||
const latestPost = posts.sort(
|
const latestPost = posts.sort(
|
||||||
(a, b) =>
|
(a, b) =>
|
||||||
new Date(b.data.pubDate).valueOf() - new Date(a.data.pubDate).valueOf(),
|
new Date(b.data.pubDate).valueOf() - new Date(a.data.pubDate).valueOf(),
|
||||||
)[0];
|
)[0];
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title="Welcome">
|
<Layout title="Welcome">
|
||||||
<Avatar size={200} />
|
<Avatar size={200} />
|
||||||
<p>
|
<p>
|
||||||
My name is <strong>Graham</strong> (he/him), a full-stack web developer, and
|
My name is <strong>Graham</strong> (he/him), a full-stack web developer, and
|
||||||
tech enthusiast.
|
tech enthusiast.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
When I'm not writing code, I'm usually enjoying one of my other hobbies;
|
When I'm not writing code, I'm usually enjoying one of my other hobbies;
|
||||||
video games, board games, music, photography, art, the list goes on...
|
video games, board games, music, photography, art, the list goes on...
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
I also like writing about stuff, so I put together this site to share
|
I also like writing about stuff, so I put together this site to share
|
||||||
whatever's on my mind about the world of tech, gaming, life, web
|
whatever's on my mind about the world of tech, gaming, life, web
|
||||||
development, and whatever else strikes my fancy.
|
development, and whatever else strikes my fancy.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Read my latest blog post, <a href={`blog/${latestPost.id}`}
|
Read my latest blog post, <a href={`blog/${latestPost.id}`}
|
||||||
>{latestPost.data.title}</a
|
>{latestPost.data.title}</a
|
||||||
>, posted on {new Date(latestPost.data.pubDate).toLocaleDateString()}.
|
>, posted on {new Date(latestPost.data.pubDate).toLocaleDateString()}.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If your interested in checking out my web dev projects, check out <a
|
If your interested in checking out my web dev projects, check out <a
|
||||||
href="https://ghall.dev/"
|
href="https://ghall.dev/"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer">my portfolio</a
|
rel="noopener noreferrer">my portfolio</a
|
||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If you want to get in touch, I'm on <a
|
If you want to get in touch, I'm on <a
|
||||||
rel="me"
|
rel="me"
|
||||||
href="https://mastodon.social/@ghalldev"
|
href="https://mastodon.social/@ghalldev"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
><MastodonIcon width={iconSize} height={iconSize} />Mastodon</a
|
><MastodonIcon width={iconSize} height={iconSize} />Mastodon</a
|
||||||
> and <a
|
> and <a
|
||||||
href="https://bsky.app/profile/ghalldev.bsky.social"
|
href="https://bsky.app/profile/ghalldev.bsky.social"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
><BlueskyIcon width={iconSize} height={iconSize} />Bluesky</a
|
><BlueskyIcon width={iconSize} height={iconSize} />Bluesky</a
|
||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
My portrait was drawn by <a
|
My portrait was drawn by <a
|
||||||
href="https://www.nataliavazquezgarcia.com"
|
href="https://www.nataliavazquezgarcia.com"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer">Natalia Vazquez</a
|
rel="noopener noreferrer">Natalia Vazquez</a
|
||||||
>.
|
>.
|
||||||
</p>
|
</p>
|
||||||
<LatestPost />
|
<LatestPost />
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
a > svg {
|
a > svg {
|
||||||
transform: translateY(0.1rem);
|
transform: translateY(0.1rem);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
+33
-34
@@ -1,5 +1,4 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
import Card from "@components/Card.astro";
|
import Card from "@components/Card.astro";
|
||||||
import { projects } from "@data/projects";
|
import { projects } from "@data/projects";
|
||||||
import Layout from "@layouts/Layout.astro";
|
import Layout from "@layouts/Layout.astro";
|
||||||
@@ -8,41 +7,41 @@ const title = "Projects";
|
|||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={title}>
|
<Layout title={title}>
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
<div class="projects-grid">
|
<div class="projects-grid">
|
||||||
{
|
{
|
||||||
projects.map((project) => (
|
projects.map((project) => (
|
||||||
<Card
|
<Card
|
||||||
title={project.title}
|
title={project.title}
|
||||||
image={project.image}
|
image={project.image}
|
||||||
links={[
|
links={[
|
||||||
{
|
{
|
||||||
label: 'More...',
|
label: "More...",
|
||||||
href: project.link,
|
href: project.link,
|
||||||
newWindow: true,
|
newWindow: true,
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<div class="project-content">
|
<div class="project-content">
|
||||||
<p>{project.description}</p>
|
<p>{project.description}</p>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.projects-grid {
|
.projects-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.project-content {
|
.project-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
height: 8rem;
|
height: 8rem;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user