Compare commits
3 Commits
e136eb8381
...
4964727717
| Author | SHA1 | Date | |
|---|---|---|---|
| 4964727717 | |||
| 2ac5a7e244 | |||
| 0c4a8a1ddf |
5
.gitignore
vendored
5
.gitignore
vendored
@@ -130,3 +130,8 @@ dist
|
|||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
|
# Astro
|
||||||
|
.astro/
|
||||||
|
|
||||||
|
# Direnv
|
||||||
|
.direnv/
|
||||||
|
|||||||
10
astro.config.mjs
Normal file
10
astro.config.mjs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// @ts-check
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
import mdx from '@astrojs/mdx';
|
||||||
|
import sitemap from '@astrojs/sitemap';
|
||||||
|
|
||||||
|
// https://astro.build/config
|
||||||
|
export default defineConfig({
|
||||||
|
site: 'https://example.com',
|
||||||
|
integrations: [mdx(), sitemap()],
|
||||||
|
});
|
||||||
42
flake.lock
generated
Normal file
42
flake.lock
generated
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-schemas": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1721999734,
|
||||||
|
"narHash": "sha256-G5CxYeJVm4lcEtaO87LKzOsVnWeTcHGKbKxNamNWgOw=",
|
||||||
|
"rev": "0a5c42297d870156d9c57d8f99e476b738dcd982",
|
||||||
|
"revCount": 75,
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://api.flakehub.com/f/pinned/DeterminateSystems/flake-schemas/0.1.5/0190ef2f-61e0-794b-ba14-e82f225e55e6/source.tar.gz"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://flakehub.com/f/DeterminateSystems/flake-schemas/%2A"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1748889542,
|
||||||
|
"narHash": "sha256-Hb4iMhIbjX45GcrgOp3b8xnyli+ysRPqAgZ/LZgyT5k=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "10d7f8d34e5eb9c0f9a0485186c1ca691d2c5922",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-25.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-schemas": "flake-schemas",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
52
flake.nix
Normal file
52
flake.nix
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# This flake was initially generated by fh, the CLI for FlakeHub (version 0.1.24)
|
||||||
|
{
|
||||||
|
# A helpful description of your flake
|
||||||
|
description = "Terakoda.com homepage";
|
||||||
|
|
||||||
|
# Flake inputs
|
||||||
|
inputs = {
|
||||||
|
flake-schemas.url = "https://flakehub.com/f/DeterminateSystems/flake-schemas/*";
|
||||||
|
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.05";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Flake outputs that other flakes can use
|
||||||
|
outputs =
|
||||||
|
{
|
||||||
|
self,
|
||||||
|
flake-schemas,
|
||||||
|
nixpkgs,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
# Helpers for producing system-specific outputs
|
||||||
|
supportedSystems = [ "x86_64-linux" ];
|
||||||
|
forEachSupportedSystem =
|
||||||
|
f:
|
||||||
|
nixpkgs.lib.genAttrs supportedSystems (
|
||||||
|
system:
|
||||||
|
f {
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Schemas tell Nix about the structure of your flake's outputs
|
||||||
|
schemas = flake-schemas.schemas;
|
||||||
|
|
||||||
|
# Development environments
|
||||||
|
devShells = forEachSupportedSystem (
|
||||||
|
{ pkgs }:
|
||||||
|
{
|
||||||
|
default = pkgs.mkShell {
|
||||||
|
# Pinned packages available in the environment
|
||||||
|
packages = with pkgs; [
|
||||||
|
nodejs_22
|
||||||
|
eslint
|
||||||
|
git
|
||||||
|
nixpkgs-fmt
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
5698
package-lock.json
generated
Normal file
5698
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
package.json
Normal file
17
package.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "astro",
|
||||||
|
"type": "module",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "astro dev",
|
||||||
|
"build": "astro build",
|
||||||
|
"preview": "astro preview",
|
||||||
|
"astro": "astro"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/mdx": "^4.3.0",
|
||||||
|
"@astrojs/rss": "^4.0.11",
|
||||||
|
"@astrojs/sitemap": "^3.4.0",
|
||||||
|
"astro": "^5.8.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
public/HeaderLogo.png
Normal file
BIN
public/HeaderLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
BIN
public/favicon.png
Normal file
BIN
public/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
public/fonts/atkinson-bold.woff
Normal file
BIN
public/fonts/atkinson-bold.woff
Normal file
Binary file not shown.
BIN
public/fonts/atkinson-regular.woff
Normal file
BIN
public/fonts/atkinson-regular.woff
Normal file
Binary file not shown.
55
src/components/BaseHead.astro
Normal file
55
src/components/BaseHead.astro
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
// Import the global.css file here so that it is included on
|
||||||
|
// all pages through the use of the <BaseHead /> component.
|
||||||
|
import '../styles/global.css';
|
||||||
|
import { SITE_TITLE } from '../consts';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
image?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
|
||||||
|
|
||||||
|
const { title, description, image = '/blog-placeholder-1.jpg' } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- Global Metadata -->
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
<link rel="icon" type="image/svg+xml" href="/favicon.png" />
|
||||||
|
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||||
|
<link
|
||||||
|
rel="alternate"
|
||||||
|
type="application/rss+xml"
|
||||||
|
title={SITE_TITLE}
|
||||||
|
href={new URL('rss.xml', Astro.site)}
|
||||||
|
/>
|
||||||
|
<meta name="generator" content={Astro.generator} />
|
||||||
|
|
||||||
|
<!-- Font preloads -->
|
||||||
|
<link rel="preload" href="/fonts/atkinson-regular.woff" as="font" type="font/woff" crossorigin />
|
||||||
|
<link rel="preload" href="/fonts/atkinson-bold.woff" as="font" type="font/woff" crossorigin />
|
||||||
|
|
||||||
|
<!-- Canonical URL -->
|
||||||
|
<link rel="canonical" href={canonicalURL} />
|
||||||
|
|
||||||
|
<!-- Primary Meta Tags -->
|
||||||
|
<title>{title}</title>
|
||||||
|
<meta name="title" content={title} />
|
||||||
|
<meta name="description" content={description} />
|
||||||
|
|
||||||
|
<!-- Open Graph / Facebook -->
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:url" content={Astro.url} />
|
||||||
|
<meta property="og:title" content={title} />
|
||||||
|
<meta property="og:description" content={description} />
|
||||||
|
<meta property="og:image" content={new URL(image, Astro.url)} />
|
||||||
|
|
||||||
|
<!-- Twitter -->
|
||||||
|
<meta property="twitter:card" content="summary_large_image" />
|
||||||
|
<meta property="twitter:url" content={Astro.url} />
|
||||||
|
<meta property="twitter:title" content={title} />
|
||||||
|
<meta property="twitter:description" content={description} />
|
||||||
|
<meta property="twitter:image" content={new URL(image, Astro.url)} />
|
||||||
72
src/components/Footer.astro
Normal file
72
src/components/Footer.astro
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
---
|
||||||
|
const today = new Date();
|
||||||
|
---
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
© {today.getFullYear()} Terakoda, LLC. All rights reserved.
|
||||||
|
<!--
|
||||||
|
<div class="social-links">
|
||||||
|
footer {
|
||||||
|
background-color: #334155; /* Slightly darker dark background */
|
||||||
|
color: #fdfafc; /* Light Text */
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
<a href="https://m.webtoo.ls/@astro" target="_blank">
|
||||||
|
<span class="sr-only">Follow Astro on Mastodon</span>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
aria-hidden="true"
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
astro-icon="social/mastodon"
|
||||||
|
><path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M11.19 12.195c2.016-.24 3.77-1.475 3.99-2.603.348-1.778.32-4.339.32-4.339 0-3.47-2.286-4.488-2.286-4.488C12.062.238 10.083.017 8.027 0h-.05C5.92.017 3.942.238 2.79.765c0 0-2.285 1.017-2.285 4.488l-.002.662c-.004.64-.007 1.35.011 2.091.083 3.394.626 6.74 3.78 7.57 1.454.383 2.703.463 3.709.408 1.823-.1 2.847-.647 2.847-.647l-.06-1.317s-1.303.41-2.767.36c-1.45-.05-2.98-.156-3.215-1.928a3.614 3.614 0 0 1-.033-.496s1.424.346 3.228.428c1.103.05 2.137-.064 3.188-.189zm1.613-2.47H11.13v-4.08c0-.859-.364-1.295-1.091-1.295-.804 0-1.207.517-1.207 1.541v2.233H7.168V5.89c0-1.024-.403-1.541-1.207-1.541-.727 0-1.091.436-1.091 1.296v4.079H3.197V5.522c0-.859.22-1.541.66-2.046.456-.505 1.052-.764 1.793-.764.856 0 1.504.328 1.933.983L8 4.39l.417-.695c.429-.655 1.077-.983 1.934-.983.74 0 1.336.259 1.791.764.442.505.661 1.187.661 2.046v4.203z"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
<a href="https://twitter.com/astrodotbuild" target="_blank">
|
||||||
|
<span class="sr-only">Follow Astro on Twitter</span>
|
||||||
|
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/twitter"
|
||||||
|
><path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M5.026 15c6.038 0 9.341-5.003 9.341-9.334 0-.14 0-.282-.006-.422A6.685 6.685 0 0 0 16 3.542a6.658 6.658 0 0 1-1.889.518 3.301 3.301 0 0 0 1.447-1.817 6.533 6.533 0 0 1-2.087.793A3.286 3.286 0 0 0 7.875 6.03a9.325 9.325 0 0 1-6.767-3.429 3.289 3.289 0 0 0 1.018 4.382A3.323 3.323 0 0 1 .64 6.575v.045a3.288 3.288 0 0 0 2.632 3.218 3.203 3.203 0 0 1-.865.115 3.23 3.23 0 0 1-.614-.057 3.283 3.283 0 0 0 3.067 2.277A6.588 6.588 0 0 1 .78 13.58a6.32 6.32 0 0 1-.78-.045A9.344 9.344 0 0 0 5.026 15z"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/withastro/astro" target="_blank">
|
||||||
|
<span class="sr-only">Go to Astro's GitHub repo</span>
|
||||||
|
<svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" astro-icon="social/github"
|
||||||
|
><path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"
|
||||||
|
></path></svg
|
||||||
|
>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
</footer>
|
||||||
|
<style>
|
||||||
|
footer {
|
||||||
|
padding: 2em 1em 6em 1em;
|
||||||
|
background-color: #334155; /* Slightly darker dark background */
|
||||||
|
color: #fdfafc; /* Light Text */
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.social-links {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1em;
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
.social-links a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
}
|
||||||
|
.social-links a:hover {
|
||||||
|
color: rgb(var(--gray-dark));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
17
src/components/FormattedDate.astro
Normal file
17
src/components/FormattedDate.astro
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
date: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { date } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<time datetime={date.toISOString()}>
|
||||||
|
{
|
||||||
|
date.toLocaleDateString('en-us', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</time>
|
||||||
94
src/components/Header.astro
Normal file
94
src/components/Header.astro
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
---
|
||||||
|
import HeaderLink from './HeaderLink.astro';
|
||||||
|
import { SITE_TITLE } from '../consts';
|
||||||
|
---
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<nav>
|
||||||
|
<h2><a href="/">
|
||||||
|
<img src="/HeaderLogo.png" alt="Terakoda Logo" class="logo">
|
||||||
|
</a></h2>
|
||||||
|
<div class="internal-links">
|
||||||
|
<HeaderLink href="/">Home</HeaderLink>
|
||||||
|
<HeaderLink href="/blog">Blog</HeaderLink>
|
||||||
|
<HeaderLink href="/about">About</HeaderLink>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="social-links"> -->
|
||||||
|
<!-- <a href="https://m.webtoo.ls/@astro" target="_blank"> -->
|
||||||
|
<!-- <span class="sr-only">Follow Astro on Mastodon</span> -->
|
||||||
|
<!-- <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" -->
|
||||||
|
<!-- ><path -->
|
||||||
|
<!-- fill="currentColor" -->
|
||||||
|
<!-- d="M11.19 12.195c2.016-.24 3.77-1.475 3.99-2.603.348-1.778.32-4.339.32-4.339 0-3.47-2.286-4.488-2.286-4.488C12.062.238 10.083.017 8.027 0h-.05C5.92.017 3.942.238 2.79.765c0 0-2.285 1.017-2.285 4.488l-.002.662c-.004.64-.007 1.35.011 2.091.083 3.394.626 6.74 3.78 7.57 1.454.383 2.703.463 3.709.408 1.823-.1 2.847-.647 2.847-.647l-.06-1.317s-1.303.41-2.767.36c-1.45-.05-2.98-.156-3.215-1.928a3.614 3.614 0 0 1-.033-.496s1.424.346 3.228.428c1.103.05 2.137-.064 3.188-.189zm1.613-2.47H11.13v-4.08c0-.859-.364-1.295-1.091-1.295-.804 0-1.207.517-1.207 1.541v2.233H7.168V5.89c0-1.024-.403-1.541-1.207-1.541-.727 0-1.091.436-1.091 1.296v4.079H3.197V5.522c0-.859.22-1.541.66-2.046.456-.505 1.052-.764 1.793-.764.856 0 1.504.328 1.933.983L8 4.39l.417-.695c.429-.655 1.077-.983 1.934-.983.74 0 1.336.259 1.791.764.442.505.661 1.187.661 2.046v4.203z" -->
|
||||||
|
<!-- ></path></svg -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- </a> -->
|
||||||
|
<!-- <a href="https://twitter.com/astrodotbuild" target="_blank"> -->
|
||||||
|
<!-- <span class="sr-only">Follow Astro on Twitter</span> -->
|
||||||
|
<!-- <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" -->
|
||||||
|
<!-- ><path -->
|
||||||
|
<!-- fill="currentColor" -->
|
||||||
|
<!-- d="M5.026 15c6.038 0 9.341-5.003 9.341-9.334 0-.14 0-.282-.006-.422A6.685 6.685 0 0 0 16 3.542a6.658 6.658 0 0 1-1.889.518 3.301 3.301 0 0 0 1.447-1.817 6.533 6.533 0 0 1-2.087.793A3.286 3.286 0 0 0 7.875 6.03a9.325 9.325 0 0 1-6.767-3.429 3.289 3.289 0 0 0 1.018 4.382A3.323 3.323 0 0 1 .64 6.575v.045a3.288 3.288 0 0 0 2.632 3.218 3.203 3.203 0 0 1-.865.115 3.23 3.23 0 0 1-.614-.057 3.283 3.283 0 0 0 3.067 2.277A6.588 6.588 0 0 1 .78 13.58a6.32 6.32 0 0 1-.78-.045A9.344 9.344 0 0 0 5.026 15z" -->
|
||||||
|
<!-- ></path></svg -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- </a> -->
|
||||||
|
<!-- <a href="https://github.com/withastro/astro" target="_blank"> -->
|
||||||
|
<!-- <span class="sr-only">Go to Astro's GitHub repo</span> -->
|
||||||
|
<!-- <svg viewBox="0 0 16 16" aria-hidden="true" width="32" height="32" -->
|
||||||
|
<!-- ><path -->
|
||||||
|
<!-- fill="currentColor" -->
|
||||||
|
<!-- d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z" -->
|
||||||
|
<!-- ></path></svg -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- </a> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
</nav>
|
||||||
|
</header>
|
||||||
|
<style>
|
||||||
|
header {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 1em;
|
||||||
|
box-shadow: 0 2px 8px rgba(var(--black), 5%);
|
||||||
|
background-color: #1f2932; /* Dark Background */
|
||||||
|
color: #fdfafc; /* Light Text */
|
||||||
|
}
|
||||||
|
|
||||||
|
header .logo {
|
||||||
|
height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 a,
|
||||||
|
h2 a.active {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
nav {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
nav a {
|
||||||
|
padding: 1em 0.5em;
|
||||||
|
color: var(--black);
|
||||||
|
border-bottom: 4px solid transparent;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
nav a.active {
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom-color: var(--accent);
|
||||||
|
}
|
||||||
|
.social-links,
|
||||||
|
.social-links a {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
.social-links {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
24
src/components/HeaderLink.astro
Normal file
24
src/components/HeaderLink.astro
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
import type { HTMLAttributes } from 'astro/types';
|
||||||
|
|
||||||
|
type Props = HTMLAttributes<'a'>;
|
||||||
|
|
||||||
|
const { href, class: className, ...props } = Astro.props;
|
||||||
|
const pathname = Astro.url.pathname.replace(import.meta.env.BASE_URL, '');
|
||||||
|
const subpath = pathname.match(/[^\/]+/g);
|
||||||
|
const isActive = href === pathname || href === '/' + (subpath?.[0] || '');
|
||||||
|
---
|
||||||
|
|
||||||
|
<a href={href} class:list={[className, { active: isActive }]} {...props}>
|
||||||
|
<slot />
|
||||||
|
</a>
|
||||||
|
<style>
|
||||||
|
a {
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a.active {
|
||||||
|
font-weight: bolder;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
2
src/consts.ts
Normal file
2
src/consts.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export const SITE_TITLE = "Terakoda";
|
||||||
|
export const SITE_DESCRIPTION = "A tech cooperative";
|
||||||
18
src/content.config.ts
Normal file
18
src/content.config.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { glob } from 'astro/loaders';
|
||||||
|
import { defineCollection, z } from 'astro:content';
|
||||||
|
|
||||||
|
const blog = defineCollection({
|
||||||
|
// Load Markdown and MDX files in the `src/content/blog/` directory.
|
||||||
|
loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
|
||||||
|
// Type-check frontmatter using a schema
|
||||||
|
schema: z.object({
|
||||||
|
title: z.string(),
|
||||||
|
description: z.string(),
|
||||||
|
// Transform string to Date object
|
||||||
|
pubDate: z.coerce.date(),
|
||||||
|
updatedDate: z.coerce.date().optional(),
|
||||||
|
heroImage: z.string().optional(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const collections = { blog };
|
||||||
17
src/content/blog/a-fresh-start.md
Normal file
17
src/content/blog/a-fresh-start.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
title: "A Fresh Start"
|
||||||
|
description: "Starting a new venture"
|
||||||
|
pubDate: "2025-06-03"
|
||||||
|
heroImage: "https://placecats.com/500/400"
|
||||||
|
---
|
||||||
|
|
||||||
|
This year we decided that we wanted to try something different. As funding
|
||||||
|
tightens and the AI bubble grows we realized that start-ups are not where we
|
||||||
|
want to be.
|
||||||
|
|
||||||
|
We decided to found a tech co-operative to:
|
||||||
|
|
||||||
|
- Support democratic decision making.
|
||||||
|
- Center the company around the workers and not just profit.
|
||||||
|
- Capture the value of our work for the workers and their communities.
|
||||||
|
- Align our work with our values.
|
||||||
85
src/layouts/BlogPost.astro
Normal file
85
src/layouts/BlogPost.astro
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
---
|
||||||
|
import type { CollectionEntry } from 'astro:content';
|
||||||
|
import BaseHead from '../components/BaseHead.astro';
|
||||||
|
import Header from '../components/Header.astro';
|
||||||
|
import Footer from '../components/Footer.astro';
|
||||||
|
import FormattedDate from '../components/FormattedDate.astro';
|
||||||
|
|
||||||
|
type Props = CollectionEntry<'blog'>['data'];
|
||||||
|
|
||||||
|
const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<BaseHead title={title} description={description} />
|
||||||
|
<style>
|
||||||
|
main {
|
||||||
|
width: calc(100% - 2em);
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.hero-image {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.hero-image img {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: var(--box-shadow);
|
||||||
|
}
|
||||||
|
.prose {
|
||||||
|
width: 720px;
|
||||||
|
max-width: calc(100% - 2em);
|
||||||
|
margin: auto;
|
||||||
|
padding: 1em;
|
||||||
|
color: rgb(var(--gray-dark));
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding: 1em 0;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.title h1 {
|
||||||
|
margin: 0 0 0.5em 0;
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
}
|
||||||
|
.last-updated-on {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<Header />
|
||||||
|
<main>
|
||||||
|
<article>
|
||||||
|
<div class="hero-image">
|
||||||
|
{heroImage && <img width={1020} height={510} src={heroImage} alt="" />}
|
||||||
|
</div>
|
||||||
|
<div class="prose">
|
||||||
|
<div class="title">
|
||||||
|
<div class="date">
|
||||||
|
<FormattedDate date={pubDate} />
|
||||||
|
{
|
||||||
|
updatedDate && (
|
||||||
|
<div class="last-updated-on">
|
||||||
|
Last updated on <FormattedDate date={updatedDate} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<h1>{title}</h1>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
62
src/pages/about.astro
Normal file
62
src/pages/about.astro
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
import Layout from '../layouts/BlogPost.astro';
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout
|
||||||
|
title="About Me"
|
||||||
|
description="Lorem ipsum dolor sit amet"
|
||||||
|
pubDate={new Date('August 08 2021')}
|
||||||
|
heroImage="/blog-placeholder-about.jpg"
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
|
||||||
|
labore et dolore magna aliqua. Vitae ultricies leo integer malesuada nunc vel risus commodo
|
||||||
|
viverra. Adipiscing enim eu turpis egestas pretium. Euismod elementum nisi quis eleifend quam
|
||||||
|
adipiscing. In hac habitasse platea dictumst vestibulum. Sagittis purus sit amet volutpat. Netus
|
||||||
|
et malesuada fames ac turpis egestas. Eget magna fermentum iaculis eu non diam phasellus
|
||||||
|
vestibulum lorem. Varius sit amet mattis vulputate enim. Habitasse platea dictumst quisque
|
||||||
|
sagittis. Integer quis auctor elit sed vulputate mi. Dictumst quisque sagittis purus sit amet.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Morbi tristique senectus et netus. Id semper risus in hendrerit gravida rutrum quisque non
|
||||||
|
tellus. Habitasse platea dictumst quisque sagittis purus sit amet. Tellus molestie nunc non
|
||||||
|
blandit massa. Cursus vitae congue mauris rhoncus. Accumsan tortor posuere ac ut. Fringilla urna
|
||||||
|
porttitor rhoncus dolor. Elit ullamcorper dignissim cras tincidunt lobortis. In cursus turpis
|
||||||
|
massa tincidunt dui ut ornare lectus. Integer feugiat scelerisque varius morbi enim nunc.
|
||||||
|
Bibendum neque egestas congue quisque egestas diam. Cras ornare arcu dui vivamus arcu felis
|
||||||
|
bibendum. Dignissim suspendisse in est ante in nibh mauris. Sed tempus urna et pharetra pharetra
|
||||||
|
massa massa ultricies mi.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Mollis nunc sed id semper risus in. Convallis a cras semper auctor neque. Diam sit amet nisl
|
||||||
|
suscipit. Lacus viverra vitae congue eu consequat ac felis donec. Egestas integer eget aliquet
|
||||||
|
nibh praesent tristique magna sit amet. Eget magna fermentum iaculis eu non diam. In vitae
|
||||||
|
turpis massa sed elementum. Tristique et egestas quis ipsum suspendisse ultrices. Eget lorem
|
||||||
|
dolor sed viverra ipsum. Vel turpis nunc eget lorem dolor sed viverra. Posuere ac ut consequat
|
||||||
|
semper viverra nam. Laoreet suspendisse interdum consectetur libero id faucibus. Diam phasellus
|
||||||
|
vestibulum lorem sed risus ultricies tristique. Rhoncus dolor purus non enim praesent elementum
|
||||||
|
facilisis. Ultrices tincidunt arcu non sodales neque. Tempus egestas sed sed risus pretium quam
|
||||||
|
vulputate. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus ornare. Fringilla
|
||||||
|
urna porttitor rhoncus dolor purus non. Amet dictum sit amet justo donec enim.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Mattis ullamcorper velit sed ullamcorper morbi tincidunt. Tortor posuere ac ut consequat semper
|
||||||
|
viverra. Tellus mauris a diam maecenas sed enim ut sem viverra. Venenatis urna cursus eget nunc
|
||||||
|
scelerisque viverra mauris in. Arcu ac tortor dignissim convallis aenean et tortor at. Curabitur
|
||||||
|
gravida arcu ac tortor dignissim convallis aenean et tortor. Egestas tellus rutrum tellus
|
||||||
|
pellentesque eu. Fusce ut placerat orci nulla pellentesque dignissim enim sit amet. Ut enim
|
||||||
|
blandit volutpat maecenas volutpat blandit aliquam etiam. Id donec ultrices tincidunt arcu. Id
|
||||||
|
cursus metus aliquam eleifend mi.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Tempus quam pellentesque nec nam aliquam sem. Risus at ultrices mi tempus imperdiet. Id porta
|
||||||
|
nibh venenatis cras sed felis eget velit. Ipsum a arcu cursus vitae. Facilisis magna etiam
|
||||||
|
tempor orci eu lobortis elementum. Tincidunt dui ut ornare lectus sit. Quisque non tellus orci
|
||||||
|
ac. Blandit libero volutpat sed cras. Nec tincidunt praesent semper feugiat nibh sed pulvinar
|
||||||
|
proin gravida. Egestas integer eget aliquet nibh praesent tristique magna.
|
||||||
|
</p>
|
||||||
|
</Layout>
|
||||||
21
src/pages/blog/[...slug].astro
Normal file
21
src/pages/blog/[...slug].astro
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
import { type CollectionEntry, getCollection } from 'astro:content';
|
||||||
|
import BlogPost from '../../layouts/BlogPost.astro';
|
||||||
|
import { render } from 'astro:content';
|
||||||
|
|
||||||
|
export async function getStaticPaths() {
|
||||||
|
const posts = await getCollection('blog');
|
||||||
|
return posts.map((post) => ({
|
||||||
|
params: { slug: post.id },
|
||||||
|
props: post,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
type Props = CollectionEntry<'blog'>;
|
||||||
|
|
||||||
|
const post = Astro.props;
|
||||||
|
const { Content } = await render(post);
|
||||||
|
---
|
||||||
|
|
||||||
|
<BlogPost {...post.data}>
|
||||||
|
<Content />
|
||||||
|
</BlogPost>
|
||||||
135
src/pages/blog/index.astro
Normal file
135
src/pages/blog/index.astro
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
---
|
||||||
|
import BaseHead from '../../components/BaseHead.astro';
|
||||||
|
import Header from '../../components/Header.astro';
|
||||||
|
import Footer from '../../components/Footer.astro';
|
||||||
|
import { SITE_TITLE, SITE_DESCRIPTION } from '../../consts';
|
||||||
|
import { getCollection } from 'astro:content';
|
||||||
|
import FormattedDate from '../../components/FormattedDate.astro';
|
||||||
|
|
||||||
|
const posts = (await getCollection('blog')).sort(
|
||||||
|
(a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf(),
|
||||||
|
);
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
||||||
|
<style>
|
||||||
|
main {
|
||||||
|
width: 960px;
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 2rem;
|
||||||
|
list-style-type: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
ul li {
|
||||||
|
width: calc(50% - 1rem);
|
||||||
|
}
|
||||||
|
ul li * {
|
||||||
|
text-decoration: none;
|
||||||
|
transition: 0.2s ease;
|
||||||
|
}
|
||||||
|
ul li:first-child {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
ul li:first-child img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
ul li:first-child .title {
|
||||||
|
font-size: 2.369rem;
|
||||||
|
}
|
||||||
|
ul li img {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
ul li a {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
margin: 0;
|
||||||
|
color: rgb(var(--black));
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
margin: 0;
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
}
|
||||||
|
ul li a:hover h4,
|
||||||
|
ul li a:hover .date {
|
||||||
|
color: rgb(var(--accent));
|
||||||
|
}
|
||||||
|
ul a:hover img {
|
||||||
|
box-shadow: var(--box-shadow);
|
||||||
|
}
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
ul {
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
ul li {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
ul li:first-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
ul li:first-child .title {
|
||||||
|
font-size: 1.563em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.post {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: top;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-text {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-image img {
|
||||||
|
max-height: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<Header />
|
||||||
|
<main>
|
||||||
|
<section>
|
||||||
|
<ul>
|
||||||
|
{
|
||||||
|
posts.map((post) => (
|
||||||
|
<li>
|
||||||
|
<a href={`/blog/${post.id}/`}>
|
||||||
|
<div class="post">
|
||||||
|
<div class="post-image">
|
||||||
|
<img width={200} height={200} src={post.data.heroImage} alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="post-text">
|
||||||
|
<p class="date">
|
||||||
|
<FormattedDate date={post.data.pubDate} />
|
||||||
|
</p>
|
||||||
|
<h4 class="title">{post.data.title}</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
211
src/pages/index.astro
Normal file
211
src/pages/index.astro
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
---
|
||||||
|
import BaseHead from '../components/BaseHead.astro';
|
||||||
|
import Header from '../components/Header.astro';
|
||||||
|
import Footer from '../components/Footer.astro';
|
||||||
|
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
|
||||||
|
---
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<Header />
|
||||||
|
<main>
|
||||||
|
<div class="hero">
|
||||||
|
<div class="hero-content">
|
||||||
|
<img src="HeaderLogo.png" alt="Terakoda Software Systems Logo" class="logo">
|
||||||
|
<p>Solving Your Unique Software Challenges with Precision and Quality</p>
|
||||||
|
<a href="#contact" class="cta-button">Get a Consultation</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="services">
|
||||||
|
<h2>Our Expertise</h2>
|
||||||
|
<div class="services-content">
|
||||||
|
<div class="service-item">
|
||||||
|
<h3>Custom Software Solutions</h3>
|
||||||
|
<p>We specialize in providing bespoke software solutions for those critical, isolated challenges that can impact your operations and growth.</p>
|
||||||
|
</div>
|
||||||
|
<div class="service-item">
|
||||||
|
<h3>Engineering Challenges</h3>
|
||||||
|
<p>Our experienced developers can tackle complex engineering hurdles that fall outside your team's immediate expertise.</p>
|
||||||
|
</div>
|
||||||
|
<div class="service-item">
|
||||||
|
<h3>Organizational Challenges</h3>
|
||||||
|
<p>We offer solutions to organizational challenges that can be addressed through tailored software applications.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="quality">
|
||||||
|
<h2>Our Commitment to Quality</h2>
|
||||||
|
<div class="quality-content">
|
||||||
|
<p>At Terakoda Software Systems, we are dedicated to delivering solutions that meet the highest standards of quality and reliability.</p>
|
||||||
|
<ul class="quality-list">
|
||||||
|
<li>Expert Analysis to understand your specific needs.</li>
|
||||||
|
<li>Custom-Crafted Solutions designed for optimal performance.</li>
|
||||||
|
<li>Uncompromising Quality through rigorous development standards.</li>
|
||||||
|
<li>Clear Communication throughout the entire process.</li>
|
||||||
|
<li>Long-Term Value ensuring lasting solutions.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="contact" id="contact">
|
||||||
|
<h2>Ready to Solve Your Software Puzzle?</h2>
|
||||||
|
<p>Contact us today for a consultation and let Terakoda Software Systems help you overcome your unique software challenges with precision and excellence.</p>
|
||||||
|
<a href="mailto:your-email@example.com" class="contact-button">Contact Us</a>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
.logo {
|
||||||
|
max-width: 400px; /* Adjust as needed */
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero {
|
||||||
|
background-color: #1f2932; /* Dark Background */
|
||||||
|
color: #fdfafc; /* Light Text */
|
||||||
|
padding: 80px 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-content {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h1 {
|
||||||
|
font-size: 2.5em;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero p {
|
||||||
|
font-size: 1.2em;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #2EB670; /* Accent Color */
|
||||||
|
color: #1f2932; /* Dark Text */
|
||||||
|
padding: 15px 30px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cta-button:hover {
|
||||||
|
background-color: #269e61;
|
||||||
|
}
|
||||||
|
|
||||||
|
.services {
|
||||||
|
padding: 60px 20px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #f9f7f7; /* Slightly darker light background for contrast */
|
||||||
|
}
|
||||||
|
|
||||||
|
.services h2 {
|
||||||
|
font-size: 2em;
|
||||||
|
color: #1f2932; /* Dark Text */
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.services-content {
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
gap: 30px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item {
|
||||||
|
background-color: white;
|
||||||
|
padding: 25px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.service-item h3 {
|
||||||
|
color: #2EB670; /* Accent Color */
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quality {
|
||||||
|
background-color: #fdfafc; /* Light Background */
|
||||||
|
padding: 60px 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quality h2 {
|
||||||
|
font-size: 2em;
|
||||||
|
color: #1f2932; /* Dark Text */
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quality-content {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quality-list {
|
||||||
|
list-style: none;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quality-list li {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding-left: 25px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quality-list li::before {
|
||||||
|
content: "\2713"; /* Checkmark */
|
||||||
|
color: #2EB670; /* Accent Color */
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact {
|
||||||
|
background-color: #1f2932; /* Dark Background */
|
||||||
|
color: #fdfafc; /* Light Text */
|
||||||
|
padding: 60px 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact h2 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact p {
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-button {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: #2EB670; /* Accent Color */
|
||||||
|
color: #1f2932; /* Dark Text */
|
||||||
|
padding: 15px 30px;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact-button:hover {
|
||||||
|
background-color: #269e61;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</html>
|
||||||
16
src/pages/rss.xml.js
Normal file
16
src/pages/rss.xml.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import rss from '@astrojs/rss';
|
||||||
|
import { getCollection } from 'astro:content';
|
||||||
|
import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
|
||||||
|
|
||||||
|
export async function GET(context) {
|
||||||
|
const posts = await getCollection('blog');
|
||||||
|
return rss({
|
||||||
|
title: SITE_TITLE,
|
||||||
|
description: SITE_DESCRIPTION,
|
||||||
|
site: context.site,
|
||||||
|
items: posts.map((post) => ({
|
||||||
|
...post.data,
|
||||||
|
link: `/blog/${post.id}/`,
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
}
|
||||||
155
src/styles/global.css
Normal file
155
src/styles/global.css
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
The CSS in this style tag is based off of Bear Blog's default CSS.
|
||||||
|
https://github.com/HermanMartinus/bearblog/blob/297026a877bc2ab2b3bdfbd6b9f7961c350917dd/templates/styles/blog/default.css
|
||||||
|
License MIT: https://github.com/HermanMartinus/bearblog/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--accent: #2337ff;
|
||||||
|
--accent-dark: #000d8a;
|
||||||
|
--black: 15, 18, 25;
|
||||||
|
--gray: 96, 115, 159;
|
||||||
|
--gray-light: 229, 233, 240;
|
||||||
|
--gray-dark: 34, 41, 57;
|
||||||
|
--gray-gradient: rgba(var(--gray-light), 50%), #fff;
|
||||||
|
--box-shadow:
|
||||||
|
0 2px 6px rgba(var(--gray), 25%), 0 8px 24px rgba(var(--gray), 33%),
|
||||||
|
0 16px 32px rgba(var(--gray), 33%);
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson";
|
||||||
|
src: url("/fonts/atkinson-regular.woff") format("woff");
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "Atkinson";
|
||||||
|
src: url("/fonts/atkinson-bold.woff") format("woff");
|
||||||
|
font-weight: 700;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-family: "Atkinson", sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
text-align: left;
|
||||||
|
background: linear-gradient(var(--gray-gradient)) no-repeat;
|
||||||
|
background-size: 100% 600px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
color: rgb(var(--gray-dark));
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
width: 720px;
|
||||||
|
max-width: calc(100% - 2em);
|
||||||
|
margin: auto;
|
||||||
|
padding: 3em 1em;
|
||||||
|
}
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
margin: 0 0 0.5rem 0;
|
||||||
|
color: rgb(var(--black));
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
font-size: 3.052em;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 2.441em;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
font-size: 1.953em;
|
||||||
|
}
|
||||||
|
h4 {
|
||||||
|
font-size: 1.563em;
|
||||||
|
}
|
||||||
|
h5 {
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
strong,
|
||||||
|
b {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
.prose p {
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
code {
|
||||||
|
padding: 2px 5px;
|
||||||
|
background-color: rgb(var(--gray-light));
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
pre {
|
||||||
|
padding: 1.5em;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
pre > code {
|
||||||
|
all: unset;
|
||||||
|
}
|
||||||
|
blockquote {
|
||||||
|
border-left: 4px solid var(--accent);
|
||||||
|
padding: 0 0 0 20px;
|
||||||
|
margin: 0px;
|
||||||
|
font-size: 1.333em;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
border-top: 1px solid rgb(var(--gray-light));
|
||||||
|
}
|
||||||
|
@media (max-width: 720px) {
|
||||||
|
body {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
main {
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sr-only {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
position: absolute !important;
|
||||||
|
height: 1px;
|
||||||
|
width: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
/* IE6, IE7 - a 0 height clip, off to the bottom right of the visible 1px box */
|
||||||
|
clip: rect(1px 1px 1px 1px);
|
||||||
|
/* maybe deprecated but we need to support legacy browsers */
|
||||||
|
clip: rect(1px, 1px, 1px, 1px);
|
||||||
|
/* modern browsers, clip-path works inwards from each corner */
|
||||||
|
clip-path: inset(50%);
|
||||||
|
/* added line to stop words getting smushed together (as they go onto separate lines and some screen readers do not understand line feeds as a space */
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
8
tsconfig.json
Normal file
8
tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"extends": "astro/tsconfigs/strict",
|
||||||
|
"include": [".astro/types.d.ts", "**/*"],
|
||||||
|
"exclude": ["dist"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"strictNullChecks": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user