Compare commits
11 Commits
master
...
640097c072
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
640097c072 | ||
|
|
b62865cf04 | ||
|
|
403f8146d9 | ||
|
|
dc22676254 | ||
|
|
5ac9285248 | ||
|
|
e23c077a05 | ||
|
|
f914b7db1c | ||
|
|
770198bb5b | ||
|
|
025a84b2ef | ||
|
|
5caf0424cc | ||
|
|
3865b4b089 |
2
astro/.env.example
Normal file
2
astro/.env.example
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DIRECTUS_URL="https://"
|
||||||
|
DIRECTUS_TOKEN=""
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
// @ts-check
|
// @ts-check
|
||||||
import { defineConfig } from 'astro/config';
|
import { defineConfig } from 'astro/config';
|
||||||
|
|
||||||
import preact from '@astrojs/preact';
|
import preact from '@astrojs/preact';
|
||||||
import tailwindcss from '@tailwindcss/vite';
|
import tailwindcss from '@tailwindcss/vite';
|
||||||
|
import graphql from '@rollup/plugin-graphql';
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [preact()],
|
integrations: [preact()],
|
||||||
|
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [tailwindcss()]
|
plugins: [tailwindcss(), graphql()]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
1945
astro/package-lock.json
generated
1945
astro/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,11 +11,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/preact": "^4.1.3",
|
"@astrojs/preact": "^4.1.3",
|
||||||
"@directus/sdk": "^21.2.0",
|
"@directus/sdk": "^21.2.0",
|
||||||
|
"@rollup/plugin-graphql": "^2.0.5",
|
||||||
"@tailwindcss/vite": "^4.2.1",
|
"@tailwindcss/vite": "^4.2.1",
|
||||||
"astro": "^5.17.1",
|
"astro": "^5.17.1",
|
||||||
"mdast-util-to-string": "^4.0.0",
|
"mdast-util-to-string": "^4.0.0",
|
||||||
|
"minify-xml": "^4.5.2",
|
||||||
"preact": "^10.28.4",
|
"preact": "^10.28.4",
|
||||||
"reading-time": "^1.5.0",
|
"reading-time": "^1.5.0",
|
||||||
"tailwindcss": "^4.2.1"
|
"tailwindcss": "^4.2.1",
|
||||||
|
"tslib": "^2.8.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
133
astro/src/content/settings/settings.ts
Normal file
133
astro/src/content/settings/settings.ts
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
import { print } from 'graphql';
|
||||||
|
import { createDirectusConnection } from "@/lib/directus";
|
||||||
|
import getSettingsQuery from '@/graphql/settings/settings.graphql';
|
||||||
|
|
||||||
|
export async function getSettings(): Promise<GlobalSettings> {
|
||||||
|
const client = await createDirectusConnection();
|
||||||
|
const result = await client.query(print(getSettingsQuery));
|
||||||
|
|
||||||
|
const websiteResults = result["Website_Settings"];
|
||||||
|
const websiteSettings: WebsiteSettings = {
|
||||||
|
domainName: websiteResults["domain_name"],
|
||||||
|
titleTemplate: websiteResults["title_template"],
|
||||||
|
applicationName: websiteResults["application_name"],
|
||||||
|
colors: {
|
||||||
|
primary: websiteResults["primary_color"],
|
||||||
|
secondary: websiteResults["secondary_color"]
|
||||||
|
},
|
||||||
|
author: {
|
||||||
|
name: websiteResults["author_name"],
|
||||||
|
url: websiteResults["author_url"]
|
||||||
|
},
|
||||||
|
owner: websiteResults["owner"],
|
||||||
|
designer: websiteResults["designer"],
|
||||||
|
developer: websiteResults["developer"],
|
||||||
|
copyright: websiteResults["copyright"],
|
||||||
|
twitter: {
|
||||||
|
id: websiteResults["twitter_id"],
|
||||||
|
handle: websiteResults["twitter_handle"]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const blogResults = result["Blog_Settings"];
|
||||||
|
const blogSettings: BlogSettings = {
|
||||||
|
enabled: blogResults["enabled"],
|
||||||
|
title: blogResults["title"],
|
||||||
|
subtext: blogResults["subtext"],
|
||||||
|
indexRouteTemplate: blogResults["index_route_template"],
|
||||||
|
blogRouteTemplate: blogResults["blog_route_template"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const projectResults = result["Project_Settings"];
|
||||||
|
const projectSettings: ProjectSettings = {
|
||||||
|
enabled: projectResults["enabled"],
|
||||||
|
title: projectResults["title"],
|
||||||
|
subtext: projectResults["subtext"],
|
||||||
|
indexRouteTemplate: projectResults["index_route_template"],
|
||||||
|
projectRouteTemplate: projectResults["project_route_template"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const photoResults = result["Photo_Settings"];
|
||||||
|
const photoSettings: WebsitePhotoSettings = {
|
||||||
|
enabled: photoResults["enabled"],
|
||||||
|
categoryIndex: {
|
||||||
|
indexRouteTemplate: photoResults["categories_index_route_template_url"]
|
||||||
|
},
|
||||||
|
category: {
|
||||||
|
routeTemplate: photoResults["category_route_template_url"],
|
||||||
|
perPage: photoResults["albums_per_category_page"],
|
||||||
|
icons: {
|
||||||
|
photos: {
|
||||||
|
url: photoResults["category_icons"]["photos_icon"]["filename_download"],
|
||||||
|
height: photoResults["category_icons"]["photos_icon"]["height"],
|
||||||
|
width: photoResults["category_icons"]["photos_icon"]["width"]
|
||||||
|
},
|
||||||
|
location: {
|
||||||
|
url: photoResults["category_icons"]["location_icon"]["filename_download"],
|
||||||
|
height: photoResults["category_icons"]["location_icon"]["height"],
|
||||||
|
width: photoResults["category_icons"]["location_icon"]["width"]
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
url: photoResults["category_icons"]["date_icon"]["filename_download"],
|
||||||
|
height: photoResults["category_icons"]["date_icon"]["height"],
|
||||||
|
width: photoResults["category_icons"]["date_icon"]["width"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
album: {
|
||||||
|
routeTemplate: photoResults["album_route_template_url"],
|
||||||
|
perPage: photoResults["photos_per_album_page"]
|
||||||
|
},
|
||||||
|
photo: {
|
||||||
|
routeTemplate: photoResults["photo_route_template_url"],
|
||||||
|
icons: {
|
||||||
|
previous: {
|
||||||
|
url: photoResults["photo_icons"]["previous_icon"]["filename_download"],
|
||||||
|
height: photoResults["photo_icons"]["previous_icon"]["height"],
|
||||||
|
width: photoResults["photo_icons"]["previous_icon"]["width"]
|
||||||
|
},
|
||||||
|
next: {
|
||||||
|
url: photoResults["photo_icons"]["next_icon"]["filename_download"],
|
||||||
|
height: photoResults["photo_icons"]["next_icon"]["height"],
|
||||||
|
width: photoResults["photo_icons"]["next_icon"]["width"]
|
||||||
|
},
|
||||||
|
close: {
|
||||||
|
url: photoResults["photo_icons"]["close_icon"]["filename_download"],
|
||||||
|
height: photoResults["photo_icons"]["close_icon"]["height"],
|
||||||
|
width: photoResults["photo_icons"]["close_icon"]["width"]
|
||||||
|
},
|
||||||
|
download: {
|
||||||
|
url: photoResults["photo_icons"]["download_icon"]["filename_download"],
|
||||||
|
height: photoResults["photo_icons"]["download_icon"]["height"],
|
||||||
|
width: photoResults["photo_icons"]["download_icon"]["width"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const sitemapResults = result["Sitemap_Settings"];
|
||||||
|
const sitemapSettings: SitemapSettings = {
|
||||||
|
perPage: sitemapResults["per_page"]
|
||||||
|
};
|
||||||
|
|
||||||
|
const pluginResults = result["Plugin_Settings"];
|
||||||
|
const pluginSettings: PluginSettings = {
|
||||||
|
swetrix: {
|
||||||
|
id: pluginResults["swetrix_id"],
|
||||||
|
url: pluginResults["swetrix_url"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pluginResults["swetrix_id"] === null && pluginResults["swetrix_url"] === null) {
|
||||||
|
pluginSettings.swetrix = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
website: websiteSettings,
|
||||||
|
blog: blogSettings,
|
||||||
|
project: projectSettings,
|
||||||
|
photo: photoSettings,
|
||||||
|
sitemap: sitemapSettings,
|
||||||
|
plugins: pluginSettings
|
||||||
|
}
|
||||||
|
}
|
||||||
8
astro/src/env.d.ts
vendored
Normal file
8
astro/src/env.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
interface ImportMetaEnv {
|
||||||
|
readonly DIRECTUS_TOKEN: string;
|
||||||
|
readonly DIRECTUS_URL: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: ImportMetaEnv;
|
||||||
|
}
|
||||||
5
astro/src/graphql.d.ts
vendored
Normal file
5
astro/src/graphql.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
declare module '*.graphql' {
|
||||||
|
import { DocumentNode } from 'graphql';
|
||||||
|
const Schema: DocumentNode;
|
||||||
|
export default Schema;
|
||||||
|
}
|
||||||
124
astro/src/graphql/settings/settings.graphql
Normal file
124
astro/src/graphql/settings/settings.graphql
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
query getAllSettings {
|
||||||
|
Website_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
domain_name,
|
||||||
|
title_template,
|
||||||
|
application_name,
|
||||||
|
primary_color,
|
||||||
|
secondary_color,
|
||||||
|
author_name,
|
||||||
|
author_url,
|
||||||
|
designer,
|
||||||
|
developer,
|
||||||
|
owner,
|
||||||
|
copyright,
|
||||||
|
twitter_id,
|
||||||
|
twitter_handle
|
||||||
|
},
|
||||||
|
Blog_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
enabled,
|
||||||
|
title,
|
||||||
|
subtext,
|
||||||
|
index_route_template,
|
||||||
|
blog_route_template
|
||||||
|
},
|
||||||
|
Project_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
enabled,
|
||||||
|
title,
|
||||||
|
subtext,
|
||||||
|
index_route_template,
|
||||||
|
project_route_template
|
||||||
|
},
|
||||||
|
Photo_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
enabled,
|
||||||
|
categories_index_route_template_url,
|
||||||
|
category_route_template_url,
|
||||||
|
albums_per_category_page,
|
||||||
|
category_icons {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
photos_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
location_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
date_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
},
|
||||||
|
album_route_template_url,
|
||||||
|
photos_per_album_page,
|
||||||
|
photo_route_template_url,
|
||||||
|
photo_icons {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
previous_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
next_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
close_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
},
|
||||||
|
download_icon {
|
||||||
|
id,
|
||||||
|
created_on,
|
||||||
|
filename_download,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Sitemap_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
per_page
|
||||||
|
},
|
||||||
|
Plugin_Settings {
|
||||||
|
id,
|
||||||
|
date_created,
|
||||||
|
date_updated,
|
||||||
|
swetrix_id,
|
||||||
|
swetrix_url
|
||||||
|
}
|
||||||
|
}
|
||||||
62
astro/src/layouts/WebpageLayout.astro
Normal file
62
astro/src/layouts/WebpageLayout.astro
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
|
||||||
|
const settings = await getSettings();
|
||||||
|
---
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- High Priority Metadata -->
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="lanuage" content="EN" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
|
||||||
|
<!-- High Priority Page Metadata -->
|
||||||
|
<title>{settings.website.titleTemplate.replaceAll("%T", "")}</title>
|
||||||
|
|
||||||
|
<!-- Medium Priority Metadata -->
|
||||||
|
<meta name="msapplication-TileColor" content={settings.website.colors.primary}>
|
||||||
|
<meta name="msapplication-TileImage" content="">
|
||||||
|
<link rel="sitemap" href="/sitemap/index.xml">
|
||||||
|
<link rel="alternate" type="application/rss+xml" href="/rss.xml" title="RSS">
|
||||||
|
<link rel="canonical" href={`${settings.website.domainName}/`}>
|
||||||
|
<meta name="robots" content="index,follow" />
|
||||||
|
|
||||||
|
<!-- Low Priority Page Metadata -->
|
||||||
|
<meta name="description" content="">
|
||||||
|
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:locale" content="en-GB" />
|
||||||
|
<meta property="og:title" content={settings.website.titleTemplate.replaceAll("%T", "")} />
|
||||||
|
<meta property="og:description" content="" />
|
||||||
|
<meta property="og:image:url" content="" />
|
||||||
|
<meta property="og:image:alt" content="" />
|
||||||
|
<meta property="og:url" content={`${settings.website.domainName}${Astro.url.pathname}`} />
|
||||||
|
<meta property="og:site_name" content={settings.website.applicationName} />
|
||||||
|
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:title" content={settings.website.titleTemplate.replaceAll("%T", "")}>
|
||||||
|
<meta name="twitter:description" content="">
|
||||||
|
<meta name="twitter:image" content="">
|
||||||
|
<meta name="twitter:image:alt" content="">
|
||||||
|
<meta name="twitter:url" content={`${settings.website.domainName}${Astro.url.pathname}`}>
|
||||||
|
<meta name="twitter:site" content={settings.website.twitter.handle}>
|
||||||
|
<meta name="twitter:creator" content={settings.website.twitter.handle}>
|
||||||
|
|
||||||
|
<meta name="pagename" content="" />
|
||||||
|
<meta name="category" content="webpage" />
|
||||||
|
|
||||||
|
<!-- Low Priority Metadata -->
|
||||||
|
<meta name="copyright" content={settings.website.copyright} />
|
||||||
|
<meta name="author" content={`${settings.website.author.name}, ${settings.website.author.url}`} />
|
||||||
|
<meta name="designer" content={settings.website.designer} />
|
||||||
|
<meta name="owner" content={settings.website.owner} />
|
||||||
|
<meta name="developer" content={settings.website.developer} />
|
||||||
|
<meta name="application-name" content={settings.website.applicationName} />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<slot />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
9
astro/src/lib/directus.ts
Normal file
9
astro/src/lib/directus.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createDirectus, graphql, staticToken } from "@directus/sdk";
|
||||||
|
|
||||||
|
export async function createDirectusConnection() {
|
||||||
|
const directus = await createDirectus(import.meta.env.DIRECTUS_URL)
|
||||||
|
.with(graphql())
|
||||||
|
.with(staticToken(import.meta.env.DIRECTUS_TOKEN));
|
||||||
|
|
||||||
|
return directus;
|
||||||
|
}
|
||||||
@@ -1,17 +1,10 @@
|
|||||||
---
|
---
|
||||||
|
import { getSettings } from "@/content/settings/settings"
|
||||||
|
import WebpageLayout from "@/layouts/WebpageLayout.astro";
|
||||||
|
|
||||||
|
const settings = await getSettings();
|
||||||
|
---
|
||||||
|
|
||||||
---
|
<WebpageLayout>
|
||||||
|
<h1>Test</h1>
|
||||||
<html lang="en">
|
</WebpageLayout>
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
||||||
<link rel="icon" href="/favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width" />
|
|
||||||
<meta name="generator" content={Astro.generator} />
|
|
||||||
<title>Astro</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Astro</h1>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
27
astro/src/pages/rss.xml.ts
Normal file
27
astro/src/pages/rss.xml.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<rss version="2.0">
|
||||||
|
<channel>
|
||||||
|
<title>${settings.website.applicationName}</title>
|
||||||
|
<description>This is the RSS feed of ${settings.website.applicationName}</description>
|
||||||
|
<link>${settings.website.domainName}</link>
|
||||||
|
<lastBuildDate>Sat, 13 Dec 2003 18:30:02 GMT</lastBuildDate>
|
||||||
|
</channel>
|
||||||
|
</rss>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
52
astro/src/pages/sitemap/albums-[page].xml.ts
Normal file
52
astro/src/pages/sitemap/albums-[page].xml.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async ({ params }) => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const currentPage = params.page;
|
||||||
|
|
||||||
|
let pages: SitemapPage[] = [
|
||||||
|
{
|
||||||
|
url: "/",
|
||||||
|
lastModified: new Date()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${pages.map((page) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const albumCount = 250;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(albumCount / perPage);
|
||||||
|
|
||||||
|
let items: any[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
items.push({ params: { page: (i + 1) } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
40
astro/src/pages/sitemap/albums.xml.ts
Normal file
40
astro/src/pages/sitemap/albums.xml.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const albumCount = 250;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(albumCount / perPage);
|
||||||
|
|
||||||
|
let sitemaps: SitemapIndex[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
sitemaps.push({
|
||||||
|
url: `/sitemap/albums-${i + 1}.xml`,
|
||||||
|
lastModified: new Date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemaps.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
59
astro/src/pages/sitemap/blogs-[page].xml.ts
Normal file
59
astro/src/pages/sitemap/blogs-[page].xml.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async ({ params }) => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.blog.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPage = params.page;
|
||||||
|
|
||||||
|
let pages: SitemapPage[] = [
|
||||||
|
{
|
||||||
|
url: "/",
|
||||||
|
lastModified: new Date()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${pages.map((page) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const blogCount = 250;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(blogCount / perPage);
|
||||||
|
|
||||||
|
let items: any[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
items.push({ params: { page: (i + 1) } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
47
astro/src/pages/sitemap/blogs.xml.ts
Normal file
47
astro/src/pages/sitemap/blogs.xml.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.blog.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const blogCount = 250;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(blogCount / perPage);
|
||||||
|
|
||||||
|
let sitemaps: SitemapIndex[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
sitemaps.push({
|
||||||
|
url: `/sitemap/blogs-${i + 1}.xml`,
|
||||||
|
lastModified: new Date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemaps.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
53
astro/src/pages/sitemap/index.xml.ts
Normal file
53
astro/src/pages/sitemap/index.xml.ts
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
let sitemapIndex: SitemapIndex[] = [
|
||||||
|
{
|
||||||
|
url: "/sitemap/pages.xml",
|
||||||
|
lastModified: new Date()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
if (settings.blog.enabled) {
|
||||||
|
sitemapIndex.push({
|
||||||
|
url: "/sitemap/blogs.xml",
|
||||||
|
lastModified: new Date()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (settings.project.enabled) {
|
||||||
|
sitemapIndex.push({
|
||||||
|
url: "/sitemap/projects.xml",
|
||||||
|
lastModified: new Date()
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (settings.photo.enabled) {
|
||||||
|
sitemapIndex.push({
|
||||||
|
url: "/sitemap/photos.xml",
|
||||||
|
lastModified: new Date()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemapIndex.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
52
astro/src/pages/sitemap/pages-[page].xml.ts
Normal file
52
astro/src/pages/sitemap/pages-[page].xml.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async ({ params }) => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const currentPage = params.page;
|
||||||
|
|
||||||
|
let pages: SitemapPage[] = [
|
||||||
|
{
|
||||||
|
url: "/",
|
||||||
|
lastModified: new Date()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${pages.map((page) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const pageCount = 250;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(pageCount / perPage);
|
||||||
|
|
||||||
|
let items: any[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
items.push({ params: { page: (i + 1) } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
40
astro/src/pages/sitemap/pages.xml.ts
Normal file
40
astro/src/pages/sitemap/pages.xml.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const pageCount = 250;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(pageCount / perPage);
|
||||||
|
|
||||||
|
let sitemaps: SitemapIndex[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
sitemaps.push({
|
||||||
|
url: `/sitemap/pages-${i + 1}.xml`,
|
||||||
|
lastModified: new Date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemaps.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
59
astro/src/pages/sitemap/projects-[page].xml.ts
Normal file
59
astro/src/pages/sitemap/projects-[page].xml.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async ({ params }) => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.project.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPage = params.page;
|
||||||
|
|
||||||
|
let pages: SitemapPage[] = [
|
||||||
|
{
|
||||||
|
url: "/",
|
||||||
|
lastModified: new Date()
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${pages.map((page) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${page.url}</loc>
|
||||||
|
<lastmod>${page.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
const projectCount = 250;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(projectCount / perPage);
|
||||||
|
|
||||||
|
let items: any[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
items.push({ params: { page: (i + 1) } });
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
47
astro/src/pages/sitemap/projects.xml.ts
Normal file
47
astro/src/pages/sitemap/projects.xml.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { getSettings } from "@/content/settings/settings";
|
||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import minifyXML from "minify-xml";
|
||||||
|
|
||||||
|
export const GET = (async () => {
|
||||||
|
const settings = await getSettings();
|
||||||
|
|
||||||
|
if (!settings.blog.enabled) {
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
statusText: "Not Found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectCount = 250;
|
||||||
|
const perPage = settings.sitemap.perPage;
|
||||||
|
const pages = Math.ceil(projectCount / perPage);
|
||||||
|
|
||||||
|
let sitemaps: SitemapIndex[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < pages; i++) {
|
||||||
|
sitemaps.push({
|
||||||
|
url: `/sitemap/projects-${i + 1}.xml`,
|
||||||
|
lastModified: new Date()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sitemapContent = `
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
${sitemaps.map((item) => `
|
||||||
|
<sitemap>
|
||||||
|
<loc>${settings.website.domainName}${item.url}</loc>
|
||||||
|
<lastmod>${item.lastModified.toISOString()}</lastmod>
|
||||||
|
</sitemap>
|
||||||
|
`).join('')}
|
||||||
|
</sitemapindex>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return new Response(minifyXML(sitemapContent), {
|
||||||
|
status: 200,
|
||||||
|
statusText: "OK",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/xml"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}) satisfies APIRoute;
|
||||||
5
astro/src/types/common/images.d.ts
vendored
Normal file
5
astro/src/types/common/images.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
type PhotoProps = {
|
||||||
|
url: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
9
astro/src/types/settings/blog.d.ts
vendored
Normal file
9
astro/src/types/settings/blog.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
type BlogSettings = {
|
||||||
|
enabled: string;
|
||||||
|
|
||||||
|
title: string;
|
||||||
|
subtext: string | null;
|
||||||
|
|
||||||
|
indexRouteTemplate: string;
|
||||||
|
blogRouteTemplate: string;
|
||||||
|
}
|
||||||
37
astro/src/types/settings/photo.d.ts
vendored
Normal file
37
astro/src/types/settings/photo.d.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
type WebsitePhotoSettings = {
|
||||||
|
enabled: boolean;
|
||||||
|
|
||||||
|
categoryIndex: WebsitePhotoSettingsCategoryIndex;
|
||||||
|
category: WebsitePhotoSettingsCategory;
|
||||||
|
album: WebsitePhotoSettingsAlbum;
|
||||||
|
photo: WebsitePhotoSettingsPhoto;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePhotoSettingsCategoryIndex = {
|
||||||
|
indexRouteTemplate: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePhotoSettingsCategory = {
|
||||||
|
routeTemplate: string;
|
||||||
|
perPage: number;
|
||||||
|
icons: {
|
||||||
|
photos: PhotoProps;
|
||||||
|
location: PhotoProps;
|
||||||
|
date: PhotoProps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePhotoSettingsAlbum = {
|
||||||
|
routeTemplate: string;
|
||||||
|
perPage: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsitePhotoSettingsPhoto = {
|
||||||
|
routeTemplate: string;
|
||||||
|
icons: {
|
||||||
|
previous: PhotoProps;
|
||||||
|
next: PhotoProps;
|
||||||
|
close: PhotoProps;
|
||||||
|
download: PhotoProps;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
astro/src/types/settings/plugin.d.ts
vendored
Normal file
8
astro/src/types/settings/plugin.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
type PluginSettings = {
|
||||||
|
swetrix: PluginSettingsSwetrix | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type PluginSettingsSwetrix = {
|
||||||
|
id: string | null;
|
||||||
|
url: string | null;
|
||||||
|
}
|
||||||
9
astro/src/types/settings/project.d.ts
vendored
Normal file
9
astro/src/types/settings/project.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
type ProjectSettings = {
|
||||||
|
enabled: string;
|
||||||
|
|
||||||
|
title: string;
|
||||||
|
subtext: string | null;
|
||||||
|
|
||||||
|
indexRouteTemplate: string;
|
||||||
|
projectRouteTemplate: string;
|
||||||
|
}
|
||||||
8
astro/src/types/settings/setting.d.ts
vendored
Normal file
8
astro/src/types/settings/setting.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
type GlobalSettings = {
|
||||||
|
website: WebsiteSettings;
|
||||||
|
blog: BlogSettings;
|
||||||
|
project: ProjectSettings;
|
||||||
|
photo: WebsitePhotoSettings;
|
||||||
|
sitemap: SitemapSettings;
|
||||||
|
plugins: PluginSettings;
|
||||||
|
}
|
||||||
3
astro/src/types/settings/sitemap.d.ts
vendored
Normal file
3
astro/src/types/settings/sitemap.d.ts
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
type SitemapSettings = {
|
||||||
|
perPage: number;
|
||||||
|
}
|
||||||
32
astro/src/types/settings/website.d.ts
vendored
Normal file
32
astro/src/types/settings/website.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
type WebsiteSettings = {
|
||||||
|
domainName: string;
|
||||||
|
titleTemplate: string;
|
||||||
|
applicationName: string;
|
||||||
|
|
||||||
|
colors: WebsiteSettingsColors;
|
||||||
|
|
||||||
|
author: WebsiteSettingsAuthor;
|
||||||
|
|
||||||
|
owner: string;
|
||||||
|
designer: string;
|
||||||
|
developer: string;
|
||||||
|
copyright: string;
|
||||||
|
|
||||||
|
twitter: WebsiteSettingsTwitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteSettingsColors = {
|
||||||
|
primary: string;
|
||||||
|
secondary: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteSettingsAuthor = {
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WebsiteSettingsTwitter = {
|
||||||
|
id: string;
|
||||||
|
handle: string;
|
||||||
|
}
|
||||||
|
|
||||||
9
astro/src/types/sitemaps/sitemap.d.ts
vendored
Normal file
9
astro/src/types/sitemaps/sitemap.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
type SitemapIndex = {
|
||||||
|
url: string;
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
type SitemapPage = {
|
||||||
|
url: string;
|
||||||
|
lastModified: Date;
|
||||||
|
}
|
||||||
@@ -9,6 +9,9 @@
|
|||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"jsx": "react-jsx",
|
"jsx": "react-jsx",
|
||||||
"jsxImportSource": "preact"
|
"jsxImportSource": "preact",
|
||||||
|
"paths": {
|
||||||
|
"@/*": ["./src/*"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user