feat: Add services/static
This commit is contained in:
12 files changed
+459
No files matched your search
@@ -0,0 +1,26 @@
|
||||
// @ts-check
|
||||
import react from '@astrojs/react';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import { defineConfig } from 'astro/config';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: 'https://static.ermnvldmr.com',
|
||||
output: 'static',
|
||||
build: {
|
||||
format: 'file',
|
||||
},
|
||||
srcDir: './src',
|
||||
integrations: [react()],
|
||||
|
||||
vite: {
|
||||
plugins: [tailwindcss()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@ermnvldmr/stl': new URL('../../packages/stl/src', import.meta.url).pathname,
|
||||
'@ermnvldmr/ui': new URL('../../packages/ui/src', import.meta.url).pathname,
|
||||
'#': new URL('./src/', import.meta.url).pathname,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "@ermnvldmr/static",
|
||||
"version": "1.0.0",
|
||||
"description": "static.ermnvldmr.com landing pages",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro",
|
||||
"lint": "eslint src --max-warnings 0",
|
||||
"format": "prettier --write .",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"clean": "rm -rf dist .turbo node_modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/react": "^4.2.5",
|
||||
"@ermnvldmr/stl": "workspace:*",
|
||||
"@ermnvldmr/ui": "workspace:*",
|
||||
"astro": "^5.7.5",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"tailwindcss": "^4.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ermnvldmr/eslint-config": "workspace:*",
|
||||
"@tailwindcss/vite": "^4.1.4",
|
||||
"eslint": "^9.25.1",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Type definitions for the static service
|
||||
*/
|
||||
/// <reference path="../.astro/types.d.ts" />
|
||||
|
||||
interface PerformanceNavigationTiming {
|
||||
responseStatus?: number;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
@import "../../../packages/ui/src/styles/index.css";
|
||||
@source "../../../packages/ui/src";
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
/**
|
||||
* Base layout for static service pages
|
||||
*/
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const { title, description } = Astro.props;
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script is:inline>
|
||||
const getThemePreference = () => {
|
||||
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
|
||||
return localStorage.getItem('theme');
|
||||
}
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
};
|
||||
const isDark = getThemePreference() === 'dark';
|
||||
document.documentElement.classList[isDark ? 'add' : 'remove']('dark');
|
||||
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
const observer = new MutationObserver(() => {
|
||||
const isDark = document.documentElement.classList.contains('dark');
|
||||
localStorage.setItem('theme', isDark ? 'dark' : 'light');
|
||||
});
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class'],
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
|
||||
<title>{title}</title>
|
||||
<meta name="description" content={description} />
|
||||
<link rel="canonical" href={Astro.url.href} />
|
||||
</head>
|
||||
<body>
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
import { VStack, HStack } from '@ermnvldmr/ui';
|
||||
|
||||
import StaticLayout from '#layouts/StaticLayout/StaticLayout.astro';
|
||||
import {
|
||||
AUTHOR_EMAIL,
|
||||
AUTHOR_NAME,
|
||||
SITE_URL,
|
||||
ERROR_TITLE,
|
||||
ERROR_DESCRIPTION,
|
||||
} from '#shared/constants';
|
||||
import { getCurrentYear } from '#shared/utils';
|
||||
import '#global.css';
|
||||
---
|
||||
|
||||
<StaticLayout title={ERROR_TITLE} description={ERROR_DESCRIPTION}>
|
||||
<main class="h-screen w-screen">
|
||||
<VStack className="w-full h-full" align="center" justify="center">
|
||||
<VStack align="start" gap={8}>
|
||||
<h1 id="title">Exceptional Situation</h1>
|
||||
<p id="message">
|
||||
This location is unavailable at the moment — static content does not dwell here
|
||||
</p>
|
||||
<HStack justify="between" className="w-full">
|
||||
<span>
|
||||
<a href={`mailto:${AUTHOR_EMAIL}`}>{AUTHOR_NAME}</a>, {getCurrentYear()}
|
||||
</span>
|
||||
<span>
|
||||
<a href={SITE_URL}>ermnvldmr.com</a>
|
||||
</span>
|
||||
</HStack>
|
||||
</VStack>
|
||||
</VStack>
|
||||
</main>
|
||||
<script>
|
||||
import { getHttpStatusUrl } from '#shared/utils';
|
||||
|
||||
function isNavigationTiming(
|
||||
entry: PerformanceEntry,
|
||||
): entry is PerformanceNavigationTiming {
|
||||
return entry.entryType === 'navigation';
|
||||
}
|
||||
|
||||
const navigationData = window.performance.getEntries().find(isNavigationTiming);
|
||||
|
||||
if (navigationData?.responseStatus) {
|
||||
const { responseStatus } = navigationData;
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = getHttpStatusUrl(responseStatus);
|
||||
link.textContent = `#${responseStatus}`;
|
||||
|
||||
document.getElementById('title')?.append(' ', link);
|
||||
}
|
||||
</script>
|
||||
</StaticLayout>
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
import { VStack, HStack } from '@ermnvldmr/ui';
|
||||
|
||||
import StaticLayout from '#layouts/StaticLayout/StaticLayout.astro';
|
||||
import {
|
||||
AUTHOR_EMAIL,
|
||||
AUTHOR_NAME,
|
||||
SITE_DESCRIPTION,
|
||||
SITE_TITLE,
|
||||
SITE_URL,
|
||||
} from '#shared/constants';
|
||||
import { getCurrentYear } from '#shared/utils';
|
||||
import '#global.css';
|
||||
---
|
||||
|
||||
<StaticLayout title={SITE_TITLE} description={SITE_DESCRIPTION}>
|
||||
<main class="h-screen w-screen">
|
||||
<VStack className="w-full h-full" align="center" justify="center">
|
||||
<VStack align="start" gap={8}>
|
||||
<h1>Static Content Dwells Here</h1>
|
||||
<p>
|
||||
Other pages direct you down specific paths to the content that resides here
|
||||
</p>
|
||||
<HStack justify="between" className="w-full">
|
||||
<span>
|
||||
<a href={`mailto:${AUTHOR_EMAIL}`}>{AUTHOR_NAME}</a>, {getCurrentYear()}
|
||||
</span>
|
||||
<span>
|
||||
<a href={SITE_URL}>ermnvldmr.com</a>
|
||||
</span>
|
||||
</HStack>
|
||||
</VStack>
|
||||
</VStack>
|
||||
</main>
|
||||
</StaticLayout>
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Site title for static landing pages
|
||||
*/
|
||||
export const SITE_TITLE = 'Static Storage - ermnvldmr.com';
|
||||
|
||||
/**
|
||||
* Site description for static landing pages
|
||||
*/
|
||||
export const SITE_DESCRIPTION = 'Static file storage and content delivery';
|
||||
|
||||
export const AUTHOR_NAME = 'Vladimir Eremin';
|
||||
export const AUTHOR_EMAIL = 'personal@ermnvldmr.com';
|
||||
export const SITE_URL = 'https://ermnvldmr.com';
|
||||
export const STATIC_URL = 'https://static.ermnvldmr.com';
|
||||
|
||||
export const ERROR_TITLE = 'Exceptional Situation - Static Storage';
|
||||
export const ERROR_DESCRIPTION = 'This location is unavailable at the moment';
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Returns the current year
|
||||
*
|
||||
* @returns {number} The current year
|
||||
* @example
|
||||
* getCurrentYear() // 2024
|
||||
*/
|
||||
export const getCurrentYear = (): number => new Date().getFullYear();
|
||||
|
||||
/**
|
||||
* Returns MDN URL for a given HTTP status code
|
||||
*
|
||||
* @param {number | string} code - The HTTP status code
|
||||
* @returns {string} The MDN URL for the status code
|
||||
* @example
|
||||
* getHttpStatusUrl(404) // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404
|
||||
*/
|
||||
export const getHttpStatusUrl = (code: number | string): string =>
|
||||
`https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/${code}`;
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./src",
|
||||
"paths": {
|
||||
"#*": ["./*"],
|
||||
"@ermnvldmr/stl": ["../../../packages/stl/src"],
|
||||
"@ermnvldmr/ui": ["../../../packages/ui/src"],
|
||||
"@ermnvldmr/ui/*": ["../../../packages/ui/src/*"]
|
||||
}
|
||||
},
|
||||
"include": [".astro/types.d.ts", "src/**/*"],
|
||||
"exclude": ["dist", "node_modules", "**/*.config.*"]
|
||||
}
|
||||
Reference in new issue
Block a user