init astro landing page template
19
.direnv/bin/nix-direnv-reload
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
if [[ ! -d "/home/ryan/Documents/Work/Sejour/landing-page" ]]; then
|
||||
echo "Cannot find source directory; Did you move it?"
|
||||
echo "(Looking for "/home/ryan/Documents/Work/Sejour/landing-page")"
|
||||
echo 'Cannot force reload with this script - use "direnv reload" manually and then try again'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# rebuild the cache forcefully
|
||||
_nix_direnv_force_reload=1 direnv exec "/home/ryan/Documents/Work/Sejour/landing-page" true
|
||||
|
||||
# Update the mtime for .envrc.
|
||||
# This will cause direnv to reload again - but without re-building.
|
||||
touch "/home/ryan/Documents/Work/Sejour/landing-page/.envrc"
|
||||
|
||||
# Also update the timestamp of whatever profile_rc we have.
|
||||
# This makes sure that we know we are up to date.
|
||||
touch -r "/home/ryan/Documents/Work/Sejour/landing-page/.envrc" "/home/ryan/Documents/Work/Sejour/landing-page/.direnv"/*.rc
|
||||
1
.direnv/flake-inputs/01x5k4nlxcpyd85nnr0b9gm89rm8ff4x-source
Symbolic link
@ -0,0 +1 @@
|
||||
/nix/store/01x5k4nlxcpyd85nnr0b9gm89rm8ff4x-source
|
||||
1
.direnv/flake-inputs/j0kr3c6j54vgdzb9nikqwr0nqjxahf3r-source
Symbolic link
@ -0,0 +1 @@
|
||||
/nix/store/j0kr3c6j54vgdzb9nikqwr0nqjxahf3r-source
|
||||
1
.direnv/flake-inputs/w85m7nzs0czxvjqhks0apmh5lfbgqccp-source
Symbolic link
@ -0,0 +1 @@
|
||||
/nix/store/w85m7nzs0czxvjqhks0apmh5lfbgqccp-source
|
||||
1
.direnv/flake-inputs/yj1wxm9hh8610iyzqnz75kvs6xl8j3my-source
Symbolic link
@ -0,0 +1 @@
|
||||
/nix/store/yj1wxm9hh8610iyzqnz75kvs6xl8j3my-source
|
||||
1
.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa
Symbolic link
@ -0,0 +1 @@
|
||||
/nix/store/rmpd7vwzl1zr1p9w5agb0gsy45gmpf1h-nix-shell-env
|
||||
2148
.direnv/flake-profile-a5d5b61aa8a61b7d9d765e1daf971a9a578f1cfa.rc
Normal file
12
Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM node:lts AS runtime
|
||||
WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm install
|
||||
RUN npm run build
|
||||
|
||||
ENV HOST=0.0.0.0
|
||||
ENV PORT=4321
|
||||
EXPOSE 4321
|
||||
CMD node ./dist/server/entry.mjs
|
||||
9
LICENSE
Normal file
@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022-present Markus Hsi-Yang Fritz
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
9
astro.config.mjs
Normal file
@ -0,0 +1,9 @@
|
||||
import tailwind from "@astrojs/tailwind";
|
||||
import icon from "astro-icon";
|
||||
import { defineConfig } from "astro/config";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
site: "https://astro-moon-landing.netlify.app/",
|
||||
integrations: [tailwind(), icon()],
|
||||
});
|
||||
61
flake.lock
generated
Normal file
@ -0,0 +1,61 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1767966113,
|
||||
"narHash": "sha256-mSTsvXa4WveSRJexsmCbm9dY17B1fKp7NLpJxllpQw4=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5f02c91314c8ba4afe83b256b023756412218535",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
34
flake.nix
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
description = "Lifetracker";
|
||||
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
outputs =
|
||||
{ nixpkgs, flake-utils, ... }:
|
||||
flake-utils.lib.eachDefaultSystem (
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
|
||||
in
|
||||
with pkgs;
|
||||
{
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = [
|
||||
bashInteractive
|
||||
glibcLocales
|
||||
git
|
||||
nodejs
|
||||
pnpm
|
||||
postgresql
|
||||
inotify-tools
|
||||
claude-code
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
7943
package-lock.json
generated
Normal file
35
package.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "astro-landing-page",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro",
|
||||
"format": "prettier --write **/*.astro .",
|
||||
"clean": "rimraf dist .astro node_modules"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@astrojs/tailwind": "^5.1.2",
|
||||
"@iconify-json/fa-brands": "^1.2.0",
|
||||
"@iconify-json/mdi": "^1.2.1",
|
||||
"@types/micromodal": "^0.3.5",
|
||||
"astro": "^4.16.14",
|
||||
"astro-icon": "^1.1.4",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-astro": "^0.14.1",
|
||||
"prettier-plugin-tailwindcss": "^0.6.9",
|
||||
"rimraf": "^6.0.1",
|
||||
"tailwindcss-fluid-type": "^2.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource-variable/inter": "^5.1.0",
|
||||
"micromodal": "^0.4.10",
|
||||
"sharp": "^0.33.5",
|
||||
"tailwindcss": "^3.4.15",
|
||||
"tiny-invariant": "^1.3.3"
|
||||
}
|
||||
}
|
||||
4609
pnpm-lock.yaml
generated
Normal file
24
public/favicon.svg
Executable file
@ -0,0 +1,24 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 627 894" fill="none">
|
||||
<style>
|
||||
#letter-a {
|
||||
fill: black;
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
#letter-a {
|
||||
fill: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<path
|
||||
id="letter-a"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M445.433 22.9832C452.722 32.0324 456.439 44.2432 463.873 68.6647L626.281 602.176C566.234 571.026 500.957 548.56 432.115 536.439L326.371 179.099C324.641 173.252 319.27 169.241 313.173 169.241C307.06 169.241 301.68 173.273 299.963 179.14L195.5 536.259C126.338 548.325 60.7632 570.832 0.459473 602.095L163.664 68.5412C171.121 44.1617 174.85 31.9718 182.14 22.9393C188.575 14.9651 196.946 8.77213 206.454 4.95048C217.224 0.621582 229.971 0.621582 255.466 0.621582H372.034C397.562 0.621582 410.326 0.621582 421.106 4.95951C430.622 8.78908 438.998 14.9946 445.433 22.9832Z"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M464.867 627.566C438.094 650.46 384.655 666.073 323.101 666.073C247.551 666.073 184.229 642.553 167.426 610.921C161.419 629.05 160.072 649.798 160.072 663.052C160.072 663.052 156.114 728.134 201.38 773.401C201.38 749.896 220.435 730.842 243.939 730.842C284.226 730.842 284.181 765.99 284.144 794.506C284.143 795.36 284.142 796.209 284.142 797.051C284.142 840.333 310.595 877.436 348.215 893.075C342.596 881.518 339.444 868.54 339.444 854.825C339.444 813.545 363.679 798.175 391.845 780.311C414.255 766.098 439.155 750.307 456.315 718.629C465.268 702.101 470.352 683.17 470.352 663.052C470.352 650.68 468.43 638.757 464.867 627.566Z"
|
||||
fill="#FF5D01"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/social.jpg
Executable file
|
After Width: | Height: | Size: 97 KiB |
BIN
screenshots.jpg
Executable file
|
After Width: | Height: | Size: 313 KiB |
BIN
src/assets/astronaut.png
Executable file
|
After Width: | Height: | Size: 147 KiB |
BIN
src/assets/moon.jpg
Executable file
|
After Width: | Height: | Size: 295 KiB |
37
src/components/compatibility-list.astro
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import type { CompatibilityItem } from "~/types";
|
||||
|
||||
export interface Props {
|
||||
items: Array<CompatibilityItem>;
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
const { items, title, url } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="w-full max-w-6xl space-y-2">
|
||||
<div class="relative border border-default bg-offset px-6 pb-4 pt-8">
|
||||
<h3
|
||||
class="absolute right-4 top-0 -translate-y-1/2 rounded-full border border-current bg-default px-4 py-1 uppercase tracking-tight text-xs"
|
||||
>
|
||||
{title}
|
||||
</h3>
|
||||
<ul class="grid grid-cols-2 gap-8 sm:grid-cols-3 md:grid-cols-6">
|
||||
{
|
||||
items.map((item) => (
|
||||
<li>
|
||||
<a class="flex flex-col items-center gap-2" href={item.url}>
|
||||
<Icon class="size-12" name={item.icon} />
|
||||
<span>{item.title}</span>
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
<p class="text-right text-sm">
|
||||
<a class="text-primary" href={url}> ...and more →</a>
|
||||
</p>
|
||||
</div>
|
||||
89
src/components/compatibility.astro
Normal file
@ -0,0 +1,89 @@
|
||||
---
|
||||
import CompatibilityList from "~/components/compatibility-list.astro";
|
||||
import ContentSection from "~/components/content-section.astro";
|
||||
import type { CompatibilityItem } from "~/types";
|
||||
|
||||
const frameworks: Array<CompatibilityItem> = [
|
||||
{
|
||||
title: "React",
|
||||
icon: "frameworks/react",
|
||||
url: "https://reactjs.org/",
|
||||
},
|
||||
{
|
||||
title: "Preact",
|
||||
icon: "frameworks/preact",
|
||||
url: "https://preactjs.com/",
|
||||
},
|
||||
{
|
||||
title: "Svelte",
|
||||
icon: "frameworks/svelte",
|
||||
url: "https://svelte.dev/",
|
||||
},
|
||||
{
|
||||
title: "Vue",
|
||||
icon: "frameworks/vue",
|
||||
url: "https://vuejs.org/",
|
||||
},
|
||||
{
|
||||
title: "Solid",
|
||||
icon: "frameworks/solid",
|
||||
url: "https://www.solidjs.com/",
|
||||
},
|
||||
{
|
||||
title: "Lit",
|
||||
icon: "frameworks/lit",
|
||||
url: "https://lit.dev/",
|
||||
},
|
||||
];
|
||||
|
||||
const platforms: Array<CompatibilityItem> = [
|
||||
{
|
||||
title: "Netlify",
|
||||
icon: "platforms/netlify",
|
||||
url: "https://www.netlify.com/",
|
||||
},
|
||||
{
|
||||
title: "Vercel",
|
||||
icon: "platforms/vercel",
|
||||
url: "https://vercel.com/",
|
||||
},
|
||||
{
|
||||
title: "Cloudflare",
|
||||
icon: "fa-brands:cloudflare",
|
||||
url: "https://pages.cloudflare.com/",
|
||||
},
|
||||
{
|
||||
title: "Render",
|
||||
icon: "platforms/render",
|
||||
url: "https://render.com/",
|
||||
},
|
||||
{
|
||||
title: "GitHub",
|
||||
icon: "fa-brands:github",
|
||||
url: "https://pages.github.com/",
|
||||
},
|
||||
{
|
||||
title: "GitLab",
|
||||
icon: "fa-brands:gitlab",
|
||||
url: "https://docs.gitlab.com/ee/user/project/pages/",
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<ContentSection title="Compatibility" id="compatibility">
|
||||
<Fragment slot="lead">
|
||||
Astro <span class="text-primary">plays nice</span>. Bring your own UI{" "}
|
||||
<span class="text-primary">framework</span>
|
||||
and deploy to your favorite <span class="text-primary">platform</span>.
|
||||
</Fragment>
|
||||
<CompatibilityList
|
||||
items={frameworks}
|
||||
title="Frameworks"
|
||||
url="https://docs.astro.build/core-concepts/framework-components/"
|
||||
/>
|
||||
<CompatibilityList
|
||||
items={platforms}
|
||||
title="Platforms"
|
||||
url="https://docs.astro.build/guides/deploy/"
|
||||
/>
|
||||
</ContentSection>
|
||||
26
src/components/content-section.astro
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
export interface Props {
|
||||
id: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const { title, id } = Astro.props;
|
||||
---
|
||||
|
||||
<section
|
||||
id={id}
|
||||
class="flex scroll-mt-24 flex-col items-center gap-4 space-y-8"
|
||||
>
|
||||
<div class="flex flex-col items-center gap-4">
|
||||
<slot name="eyebrow" />
|
||||
<h2
|
||||
class="gradient-text text-center font-extrabold tracking-tight text-6xl"
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
</div>
|
||||
<p class="max-w-xl text-center font-extrabold text-2xl">
|
||||
<slot name="lead" />
|
||||
</p>
|
||||
<slot />
|
||||
</section>
|
||||
66
src/components/features.astro
Normal file
@ -0,0 +1,66 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import ContentSection from "~/components/content-section.astro";
|
||||
import type { FeatureItem } from "~/types";
|
||||
|
||||
const features: Array<FeatureItem> = [
|
||||
{
|
||||
title: "Bring Your Own Framework",
|
||||
description:
|
||||
"Build your site using React, Svelte, Vue, Preact, web components, or just plain ol' HTML + JavaScript.",
|
||||
icon: "mdi:handshake",
|
||||
},
|
||||
{
|
||||
title: "100% Static HTML, No JS",
|
||||
description:
|
||||
"Astro renders your entire page to static HTML, removing all JavaScript from your final build by default.",
|
||||
icon: "mdi:feather",
|
||||
},
|
||||
{
|
||||
title: "On-Demand Components",
|
||||
description:
|
||||
"Need some JS? Astro can automatically hydrate interactive components when they become visible on the page. If the user never sees it, they never load it.",
|
||||
icon: "mdi:directions-fork",
|
||||
},
|
||||
{
|
||||
title: "Broad Integration",
|
||||
description:
|
||||
"Astro supports TypeScript, Scoped CSS, CSS Modules, Sass, Tailwind, Markdown, MDX, and any of your favorite npm packages.",
|
||||
icon: "mdi:graph",
|
||||
},
|
||||
{
|
||||
title: "SEO Enabled",
|
||||
description:
|
||||
"Automatic sitemaps, RSS feeds, pagination and collections take the pain out of SEO and syndication.",
|
||||
icon: "mdi:search-web",
|
||||
},
|
||||
{
|
||||
title: "Community",
|
||||
description:
|
||||
"Astro is an open source project powered by hundreds of contributors making thousands of individual contributions.",
|
||||
icon: "mdi:account-group",
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<ContentSection title="Features" id="features">
|
||||
<Fragment slot="lead">
|
||||
Astro comes <span class="text-primary">batteries included</span>. It takes
|
||||
the best parts of
|
||||
<span class="text-primary">state-of-the-art</span>
|
||||
tools and adds its own <span class="text-primary">innovations</span>.
|
||||
</Fragment>
|
||||
<ul class="grid max-w-6xl grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
|
||||
{
|
||||
features.map(({ title, description, icon }) => (
|
||||
<li class="flex flex-col items-center gap-4 border border-default bg-offset p-6">
|
||||
<div class="size-16 rounded-full border-2 border-current p-3">
|
||||
<Icon name={icon} class="size-full" />
|
||||
</div>
|
||||
<p class="text-center font-extrabold text-xl">{title}</p>
|
||||
<p class="text-center text-offset text-sm">{description}</p>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</ContentSection>
|
||||
49
src/components/footer.astro
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import HeroImage from "~/components/hero-image.astro";
|
||||
import type { FooterLink } from "~/types";
|
||||
|
||||
const links: Array<FooterLink> = [
|
||||
{
|
||||
url: "https://astro.build/",
|
||||
description: "Astro's official website",
|
||||
icon: "mdi:home",
|
||||
},
|
||||
{
|
||||
url: "https://github.com/mhyfritz/astro-landing-page",
|
||||
description: "View source on GitHub",
|
||||
icon: "fa-brands:github-alt",
|
||||
},
|
||||
{
|
||||
url: "https://astro.build/chat",
|
||||
description: "Astro on Discord",
|
||||
icon: "fa-brands:discord",
|
||||
},
|
||||
{
|
||||
url: "https://twitter.com/astrodotbuild",
|
||||
description: "Astro on Twitter",
|
||||
icon: "fa-brands:twitter",
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<footer class="relative flex h-64 items-center justify-center">
|
||||
<div class="absolute inset-0 overflow-hidden opacity-40">
|
||||
<HeroImage />
|
||||
</div>
|
||||
<ul class="relative grid grid-cols-2 gap-4 sm:grid-cols-4">
|
||||
{
|
||||
links.map((link) => (
|
||||
<li>
|
||||
<a
|
||||
class="flex size-16 items-center justify-center rounded-full border-2 border-current p-4"
|
||||
href={link.url}
|
||||
>
|
||||
<span class="sr-only">{link.description}</span>
|
||||
<Icon class="size-full" name={link.icon} />
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</footer>
|
||||
52
src/components/github-corner.astro
Normal file
@ -0,0 +1,52 @@
|
||||
<!-- https://github.com/tholman/github-corners -->
|
||||
<a
|
||||
href="https://github.com/mhyfritz/astro-landing-page"
|
||||
aria-label="View source on GitHub"
|
||||
class="absolute right-0 top-0 z-10 text-black hover:text-black focus:ring-0 focus:ring-offset-0"
|
||||
><svg
|
||||
class="fill-white"
|
||||
width="80"
|
||||
height="80"
|
||||
viewBox="0 0 250 250"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path>
|
||||
<path
|
||||
d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2"
|
||||
fill="currentColor"
|
||||
style="transform-origin: 130px 106px;"
|
||||
class="octo-arm"></path>
|
||||
<path
|
||||
d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z"
|
||||
fill="currentColor"
|
||||
class="octo-body"></path>
|
||||
</svg>
|
||||
</a>
|
||||
|
||||
<style>
|
||||
a:hover .octo-arm {
|
||||
animation: octocat-wave 560ms ease-in-out;
|
||||
}
|
||||
@keyframes octocat-wave {
|
||||
0%,
|
||||
100% {
|
||||
transform: rotate(0);
|
||||
}
|
||||
20%,
|
||||
60% {
|
||||
transform: rotate(-25deg);
|
||||
}
|
||||
40%,
|
||||
80% {
|
||||
transform: rotate(10deg);
|
||||
}
|
||||
}
|
||||
@media (max-width: 500px) {
|
||||
a:hover .octo-arm {
|
||||
animation: none;
|
||||
}
|
||||
a .octo-arm {
|
||||
animation: octocat-wave 560ms ease-in-out;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
138
src/components/header.astro
Normal file
@ -0,0 +1,138 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import ThemeSwitcher from "~/components/theme-switcher.astro";
|
||||
import type { NavItem } from "~/types";
|
||||
|
||||
const navItems: Array<NavItem> = [
|
||||
{ title: "Features", url: "#features" },
|
||||
{ title: "Compatibility", url: "#compatibility" },
|
||||
{ title: "Showcase", url: "#showcase" },
|
||||
];
|
||||
---
|
||||
|
||||
<header
|
||||
id="page-header"
|
||||
class="absolute bottom-0 z-20 flex w-full items-center justify-between border-b border-transparent px-8 py-4 text-white"
|
||||
>
|
||||
<a class="flex items-center gap-3 hover:!text-default" href="#">
|
||||
<h1 class="sr-only">Astro</h1>
|
||||
<Icon name="logomark" class="size-10" />
|
||||
<Icon name="wordmark" class="hidden h-4 sm:block" />
|
||||
</a>
|
||||
<div>
|
||||
<div class="flex items-center gap-6">
|
||||
<nav class="hidden sm:block">
|
||||
<ul class="flex items-center gap-6">
|
||||
{
|
||||
navItems.map(({ title, url }) => (
|
||||
<li>
|
||||
<a class="text-sm" href={url}>
|
||||
{title}
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
<button
|
||||
id="open-nav-button"
|
||||
type="button"
|
||||
class="btn sm:hidden"
|
||||
aria-label="Navigation"
|
||||
>
|
||||
<Icon name="mdi:menu" class="size-8" />
|
||||
</button>
|
||||
<ThemeSwitcher />
|
||||
</div>
|
||||
<div id="menu-modal" class="modal hidden" aria-hidden="true">
|
||||
<div class="fixed inset-0 bg-default px-8 py-4 text-default">
|
||||
<div class="space-y-4" role="dialog" aria-modal="true">
|
||||
<header class="text-right">
|
||||
<button
|
||||
id="close-nav-button"
|
||||
type="button"
|
||||
class="btn"
|
||||
aria-label="Close navigation"
|
||||
>
|
||||
<Icon name="mdi:close" class="size-8" />
|
||||
</button>
|
||||
</header>
|
||||
<div class="flex justify-center">
|
||||
<Icon name="logomark" class="size-16" />
|
||||
</div>
|
||||
<nav>
|
||||
<ul class="flex flex-col">
|
||||
{
|
||||
navItems.map(({ title, url }) => (
|
||||
<li>
|
||||
<a class="block py-4 text-center text-xl" href={url}>
|
||||
{title}
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<script>
|
||||
import MicroModal from "micromodal";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const menuModalId = "menu-modal";
|
||||
|
||||
const header = document.querySelector("#page-header") as HTMLElement;
|
||||
const page = document.documentElement;
|
||||
const menu = document.querySelector(`#${menuModalId} ul`);
|
||||
const openNavButton = document.querySelector("#open-nav-button");
|
||||
const closeNavButton = document.querySelector("#close-nav-button");
|
||||
|
||||
invariant(header, "header should not be null");
|
||||
invariant(menu, "menu should not be null");
|
||||
invariant(openNavButton, "openNavButton should not be null");
|
||||
invariant(closeNavButton, "closeNavButton should not be null");
|
||||
|
||||
const openMenu = () => {
|
||||
MicroModal.show(menuModalId, { disableScroll: true });
|
||||
};
|
||||
|
||||
const closeMenu = () => {
|
||||
MicroModal.close(menuModalId);
|
||||
};
|
||||
|
||||
openNavButton.addEventListener("click", openMenu);
|
||||
closeNavButton.addEventListener("click", closeMenu);
|
||||
|
||||
document.addEventListener("scroll", () => {
|
||||
const d = page.clientHeight - page.scrollTop - header.offsetHeight;
|
||||
header.classList.toggle("fixed-header", d < 0);
|
||||
});
|
||||
|
||||
menu.addEventListener("click", (event) => {
|
||||
if ((event.target as HTMLElement).tagName === "A") {
|
||||
closeMenu();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<noscript>
|
||||
<style>
|
||||
#open-nav-button {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</noscript>
|
||||
|
||||
<style>
|
||||
.fixed-header {
|
||||
@apply fixed bottom-auto top-0;
|
||||
@apply border-default bg-default text-default;
|
||||
}
|
||||
.modal.is-open {
|
||||
@apply block;
|
||||
}
|
||||
</style>
|
||||
15
src/components/hero-image.astro
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
import { Image } from "astro:assets";
|
||||
import moonImage from "~/assets/moon.jpg";
|
||||
|
||||
const widths = [450, 800, 1200];
|
||||
const sizes = "100vw";
|
||||
---
|
||||
|
||||
<Image
|
||||
class="h-full w-full object-cover"
|
||||
src={moonImage}
|
||||
widths={widths}
|
||||
sizes={sizes}
|
||||
alt="The ridged surface of the moon"
|
||||
/>
|
||||
30
src/components/intro.astro
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
import ContentSection from "~/components/content-section.astro";
|
||||
---
|
||||
|
||||
<ContentSection title="Just ship less" id="intro">
|
||||
<Icon slot="eyebrow" name="logomark" class="size-32" />
|
||||
<Fragment slot="lead">
|
||||
Astro is a new kind of site builder for the
|
||||
<span class="text-primary">modern</span> web.
|
||||
<span class="text-primary">Lightning-fast</span>
|
||||
performance meets <span class="text-primary">powerful</span> developer experience.
|
||||
</Fragment>
|
||||
<div class="grid grid-cols-1 gap-2 sm:grid-cols-2">
|
||||
<a
|
||||
href="https://docs.astro.build/"
|
||||
class="flex items-center justify-center gap-3 border-2 border-current px-6 py-4"
|
||||
>
|
||||
<Icon name="mdi:telescope" class="size-8" />
|
||||
<span>Read the docs</span>
|
||||
</a>
|
||||
<a
|
||||
href="https://astro.new/"
|
||||
class="flex items-center justify-center gap-3 border-2 border-current px-6 py-4"
|
||||
>
|
||||
<Icon name="mdi:rocket" class="size-8" />
|
||||
<span>Try it out</span>
|
||||
</a>
|
||||
</div>
|
||||
</ContentSection>
|
||||
35
src/components/showcase-card.astro
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
import { Image } from "astro:assets";
|
||||
import type { CollectionEntry } from "astro:content";
|
||||
|
||||
export interface Props {
|
||||
site: CollectionEntry<"showcase">;
|
||||
}
|
||||
|
||||
const { site } = Astro.props;
|
||||
|
||||
const widths = [450, 800];
|
||||
const sizes = "(min-width: 1024px) 33vw, (min-width: 768px) 50vw, 100vw";
|
||||
---
|
||||
|
||||
<a class="group aspect-video hover:!text-default" href={site.data.url}>
|
||||
<figure class="relative h-full w-full overflow-hidden">
|
||||
<Image
|
||||
class="h-full w-full bg-cover object-cover transition-all duration-300 group-hover:scale-110 group-hover:opacity-20 group-focus:scale-110 group-focus:opacity-20"
|
||||
src={site.data.image}
|
||||
widths={widths}
|
||||
sizes={sizes}
|
||||
alt={`A screenshot of ${site.data.url}`}
|
||||
/>
|
||||
<figcaption class="absolute inset-0">
|
||||
<div
|
||||
class="flex h-full flex-col items-center justify-center gap-2 opacity-0 transition-all duration-300 group-hover:opacity-100 group-focus:opacity-100"
|
||||
>
|
||||
<h3 class="text-center font-extrabold uppercase text-xl">
|
||||
{site.data.title}
|
||||
</h3>
|
||||
<p class="border border-current px-4 py-2">{site.data.url}</p>
|
||||
</div>
|
||||
</figcaption>
|
||||
</figure>
|
||||
</a>
|
||||
31
src/components/showcase.astro
Normal file
@ -0,0 +1,31 @@
|
||||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import ContentSection from "~/components/content-section.astro";
|
||||
import ShowcaseCard from "~/components/showcase-card.astro";
|
||||
|
||||
const featuredSites = await getCollection(
|
||||
"showcase",
|
||||
({ data }) => "featured" in data,
|
||||
);
|
||||
const orderedSites = featuredSites.sort(
|
||||
(a, b) => a.data.featured! - b.data.featured!,
|
||||
);
|
||||
---
|
||||
|
||||
<ContentSection title="Showcase" id="showcase">
|
||||
<Fragment slot="lead">
|
||||
Astro is <span class="text-primary">versatile</span>.{" "}
|
||||
<span class="text-primary">Explore</span> what's possible and get{" "}
|
||||
<span class="text-primary">inspired</span>.
|
||||
</Fragment>
|
||||
<div class="max-w-6xl space-y-2">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3">
|
||||
{orderedSites.map((site) => <ShowcaseCard site={site} />)}
|
||||
</div>
|
||||
<p class="text-right text-sm">
|
||||
<a class="text-primary" href="https://astro.build/showcase/">
|
||||
...and more →
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</ContentSection>
|
||||
84
src/components/splash.astro
Normal file
@ -0,0 +1,84 @@
|
||||
---
|
||||
import { Image } from "astro:assets";
|
||||
import { Icon } from "astro-icon/components";
|
||||
import astronautImage from "~/assets/astronaut.png";
|
||||
import HeroImage from "~/components/hero-image.astro";
|
||||
import Starfield from "~/components/starfield.astro";
|
||||
import GitHubCorner from "./github-corner.astro";
|
||||
|
||||
const widths = [450, 800];
|
||||
const sizes = "(min-width: 640px) 42vw, 67vw";
|
||||
---
|
||||
|
||||
<section class="relative h-full bg-black">
|
||||
<Starfield />
|
||||
<GitHubCorner />
|
||||
<div id="splash-bg-fallback" class="absolute inset-0 hidden opacity-40">
|
||||
<HeroImage />
|
||||
</div>
|
||||
<div class="relative grid h-full place-items-center sm:grid-cols-2">
|
||||
<h2
|
||||
class="flex flex-col items-center gap-2 self-end sm:gap-4 sm:self-auto sm:justify-self-end"
|
||||
>
|
||||
<Icon name="logomark" class="size-20 text-white md:size-32" />
|
||||
<div
|
||||
class="gradient-text text-center font-extrabold tracking-tighter text-6xl md:text-8xl"
|
||||
>
|
||||
Build fast
|
||||
<br /> websites,
|
||||
<br /> faster.
|
||||
</div>
|
||||
</h2>
|
||||
<div
|
||||
id="astronaut"
|
||||
class="w-2/3 max-w-3xl self-start sm:w-10/12 sm:self-auto sm:justify-self-start"
|
||||
>
|
||||
<Image
|
||||
class="h-full w-full object-cover"
|
||||
src={astronautImage}
|
||||
widths={widths}
|
||||
sizes={sizes}
|
||||
loading="eager"
|
||||
alt="A floating astronaut in a space suit"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<noscript>
|
||||
<style>
|
||||
#splash-bg-fallback {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</noscript>
|
||||
|
||||
<style>
|
||||
@keyframes float {
|
||||
0% {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translate3d(0, 30px, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#astronaut {
|
||||
animation: float linear 2.5s infinite alternate;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
#astronaut {
|
||||
@apply animate-none;
|
||||
}
|
||||
|
||||
:global(#starfield) {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
#splash-bg-fallback {
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
105
src/components/starfield.astro
Normal file
@ -0,0 +1,105 @@
|
||||
<div id="starfield" class="absolute inset-0">
|
||||
<canvas id="starfield-canvas"></canvas>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const COUNT = 800;
|
||||
const SPEED = 0.1;
|
||||
|
||||
class Star {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
xPrev: number;
|
||||
yPrev: number;
|
||||
|
||||
constructor(x = 0, y = 0, z = 0) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.xPrev = x;
|
||||
this.yPrev = y;
|
||||
}
|
||||
|
||||
update(width: number, height: number, speed: number) {
|
||||
this.xPrev = this.x;
|
||||
this.yPrev = this.y;
|
||||
this.z += speed * 0.0675;
|
||||
this.x += this.x * (speed * 0.0225) * this.z;
|
||||
this.y += this.y * (speed * 0.0225) * this.z;
|
||||
if (
|
||||
this.x > width / 2 ||
|
||||
this.x < -width / 2 ||
|
||||
this.y > height / 2 ||
|
||||
this.y < -height / 2
|
||||
) {
|
||||
this.x = Math.random() * width - width / 2;
|
||||
this.y = Math.random() * height - height / 2;
|
||||
this.xPrev = this.x;
|
||||
this.yPrev = this.y;
|
||||
this.z = 0;
|
||||
}
|
||||
}
|
||||
|
||||
draw(ctx: CanvasRenderingContext2D) {
|
||||
ctx.lineWidth = this.z;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(this.x, this.y);
|
||||
ctx.lineTo(this.xPrev, this.yPrev);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
const stars = Array.from({ length: COUNT }, () => new Star(0, 0, 0));
|
||||
let rafId = 0;
|
||||
|
||||
const canvas = document.querySelector(
|
||||
"#starfield-canvas",
|
||||
) as HTMLCanvasElement;
|
||||
invariant(canvas, "canvas should not be null");
|
||||
const ctx = canvas.getContext("2d");
|
||||
|
||||
const container = document.querySelector("#starfield") as HTMLElement;
|
||||
invariant(container, "container should not be null");
|
||||
const resizeObserver = new ResizeObserver(setup);
|
||||
resizeObserver.observe(container);
|
||||
|
||||
function setup() {
|
||||
invariant(ctx, "canvas context should not be null");
|
||||
rafId > 0 && cancelAnimationFrame(rafId);
|
||||
|
||||
const { clientWidth: width, clientHeight: height } = container;
|
||||
const dpr = window.devicePixelRatio || 1;
|
||||
canvas.width = width * dpr;
|
||||
canvas.height = height * dpr;
|
||||
canvas.style.width = `${width}px`;
|
||||
canvas.style.height = `${height}px`;
|
||||
ctx.scale(dpr, dpr);
|
||||
|
||||
for (const star of stars) {
|
||||
star.x = Math.random() * width - width / 2;
|
||||
star.y = Math.random() * height - height / 2;
|
||||
star.z = 0;
|
||||
}
|
||||
|
||||
ctx.translate(width / 2, height / 2);
|
||||
ctx.fillStyle = "rgba(0, 0, 0, 0.4)";
|
||||
ctx.strokeStyle = "white";
|
||||
rafId = requestAnimationFrame(frame);
|
||||
}
|
||||
|
||||
function frame() {
|
||||
invariant(ctx, "canvas context should not be null");
|
||||
const { clientWidth: width, clientHeight: height } = container;
|
||||
|
||||
for (const star of stars) {
|
||||
star.update(width, height, SPEED);
|
||||
star.draw(ctx);
|
||||
}
|
||||
|
||||
ctx.fillRect(-width / 2, -height / 2, width, height);
|
||||
rafId = requestAnimationFrame(frame);
|
||||
}
|
||||
</script>
|
||||
64
src/components/theme-switcher.astro
Normal file
@ -0,0 +1,64 @@
|
||||
---
|
||||
import { Icon } from "astro-icon/components";
|
||||
---
|
||||
|
||||
<!--
|
||||
negative margin is sum of button width (6) and gap size of flex parent (6)
|
||||
TODO don't hardcode these values
|
||||
-->
|
||||
<button
|
||||
id="theme-switcher"
|
||||
type="button"
|
||||
class="-ml-12 origin-[right_center] scale-0 transition-all duration-500"
|
||||
>
|
||||
<div id="icon-theme-light">
|
||||
<Icon name="mdi:white-balance-sunny" class="size-6" />
|
||||
<span class="sr-only">Use light theme</span>
|
||||
</div>
|
||||
<div id="icon-theme-dark" class="hidden">
|
||||
<Icon name="mdi:weather-night" class="size-6" />
|
||||
<span class="sr-only">Use dark theme</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<script>
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const themes = ["light", "dark"];
|
||||
const button = document.querySelector("#theme-switcher");
|
||||
invariant(button, "button should not be null");
|
||||
|
||||
const getThemeCurrent = () => document.documentElement.dataset.theme;
|
||||
const getThemeNext = () => {
|
||||
const themeCurrent = getThemeCurrent();
|
||||
invariant(themeCurrent, "themeCurrent should not be undefined");
|
||||
const indexThemeCurrent = themes.indexOf(themeCurrent);
|
||||
return themes[(indexThemeCurrent + 1) % themes.length];
|
||||
};
|
||||
|
||||
const updateIcon = () => {
|
||||
const themeCurrent = getThemeCurrent();
|
||||
document
|
||||
.querySelector(`#icon-theme-${themeCurrent}`)
|
||||
?.classList.add("hidden");
|
||||
const themeNext = getThemeNext();
|
||||
document
|
||||
.querySelector(`#icon-theme-${themeNext}`)
|
||||
?.classList.remove("hidden");
|
||||
};
|
||||
|
||||
button.addEventListener("click", () => {
|
||||
const themeNext = getThemeNext();
|
||||
document.documentElement.dataset.theme = themeNext;
|
||||
localStorage.setItem("theme", themeNext);
|
||||
updateIcon();
|
||||
});
|
||||
|
||||
updateIcon();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:global(.fixed-header) #theme-switcher {
|
||||
@apply ml-0 scale-100;
|
||||
}
|
||||
</style>
|
||||
16
src/content/config.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { defineCollection, z } from "astro:content";
|
||||
|
||||
const showcase = defineCollection({
|
||||
type: "data",
|
||||
schema: ({ image }) =>
|
||||
z.object({
|
||||
title: z.string().min(1),
|
||||
image: image(),
|
||||
url: z.string().url(),
|
||||
featured: z.number().min(1).optional(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = {
|
||||
showcase,
|
||||
};
|
||||
BIN
src/content/showcase/_images/astro-docs.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
src/content/showcase/_images/corset.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
src/content/showcase/_images/designcember.png
Normal file
|
After Width: | Height: | Size: 169 KiB |
BIN
src/content/showcase/_images/divriots.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
src/content/showcase/_images/firebase-blog.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
src/content/showcase/_images/polinations.png
Normal file
|
After Width: | Height: | Size: 327 KiB |
6
src/content/showcase/astro-docs.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "Astro Docs",
|
||||
"image": "/src/content/showcase/_images/astro-docs.png",
|
||||
"url": "https://docs.astro.build/",
|
||||
"featured": 2
|
||||
}
|
||||
6
src/content/showcase/corset.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "Corset",
|
||||
"image": "/src/content/showcase/_images/corset.png",
|
||||
"url": "https://corset.dev/",
|
||||
"featured": 6
|
||||
}
|
||||
6
src/content/showcase/designcember.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "Designcember",
|
||||
"image": "/src/content/showcase/_images/designcember.png",
|
||||
"url": "https://designcember.com/",
|
||||
"featured": 4
|
||||
}
|
||||
6
src/content/showcase/divriots.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "<div>RIOTS",
|
||||
"image": "/src/content/showcase/_images/divriots.png",
|
||||
"url": "https://divriots.com/",
|
||||
"featured": 3
|
||||
}
|
||||
6
src/content/showcase/firebase-blog.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "The Firebase Blog",
|
||||
"image": "/src/content/showcase/_images/firebase-blog.png",
|
||||
"url": "https://firebase.blog/",
|
||||
"featured": 5
|
||||
}
|
||||
6
src/content/showcase/polinations.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"title": "PoliNations",
|
||||
"image": "/src/content/showcase/_images/polinations.png",
|
||||
"url": "https://polinations.com/",
|
||||
"featured": 1
|
||||
}
|
||||
2
src/env.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
||||
10
src/icons/frameworks/lit.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 190 190">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M95 143V79l33-33v65l-33 32Zm-65 0 32 33v-65H46"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M62 111V46l33-32v65l-33 32Zm66 65v-65l32-32v64l-32 33Zm-98-33V79l32 32"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 290 B |
22
src/icons/frameworks/preact.svg
Normal file
@ -0,0 +1,22 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 190 190">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m101 61 24-10c6-2 12-3 17-2 4 0 7 1 9 4 1 2 2 5 1 9l-6 16-10 13a181 181 0 0 0-35-30ZM54 91l-9-13c-4-6-6-11-7-16 0-4 0-7 2-9 2-3 4-4 9-4 4-1 10 0 17 2l24 10a190 190 0 0 0-36 30Z"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
d="M58 95a174 174 0 0 1 37-30 182 182 0 0 1 37 30 174 174 0 0 1-37 30 182 182 0 0 1-37-30Zm37 13a13 13 0 1 0 0-26 13 13 0 0 0 0 26Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="m54 99-9 13c-4 6-6 11-7 16 0 4 0 7 2 9 2 3 4 4 9 4 4 1 10 0 17-2l24-10a191 191 0 0 1-36-30Zm47 30 24 10c6 2 12 3 17 2 4 0 7-1 9-4 1-2 2-5 1-9l-6-16-10-13a181 181 0 0 1-35 30Z"
|
||||
/>
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
d="M178 48 95 0 13 48v95l82 47 83-47V48ZM95 58c10-6 20-10 28-13 7-2 14-3 19-2 6 0 10 2 13 6s4 9 3 14c-1 6-4 12-7 18l-11 14 11 14c3 6 6 12 7 18 1 5 0 10-3 14s-7 6-13 6c-5 1-12 0-19-2-8-3-18-7-28-13-10 6-19 10-28 13-7 2-13 3-19 2-5 0-10-2-13-6s-3-9-2-14c1-6 3-12 7-18l10-14-10-14c-4-6-6-12-7-18-1-5-1-10 2-14s8-6 13-6c6-1 12 0 19 2 9 3 18 7 28 13Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
7
src/icons/frameworks/react.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 190 190">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M190 95c0-13-16-25-40-32 6-25 3-45-8-51l-8-2v9l4 1c5 3 8 14 6 29l-2 11-25-4c-5-7-10-14-16-19 13-12 25-18 33-18v-9c-11 0-25 8-39 21-14-13-28-21-39-21v9c8 0 20 6 33 18L73 56l-25 4-2-11c-2-15 1-26 6-29l4-1v-9l-9 2c-10 7-13 26-7 51C16 70 0 82 0 95c0 12 16 24 40 32-6 24-3 44 8 50 2 2 5 2 8 2 11 0 25-7 39-21 14 14 28 21 39 21l9-2c10-6 13-26 7-51 24-7 40-19 40-31Zm-50-26-6 15a184 184 0 0 0-10-18l16 3Zm-18 41-9 15a202 202 0 0 1-35 0 213 213 0 0 1-18-30 202 202 0 0 1 17-31 202 202 0 0 1 35 0 213 213 0 0 1 18 31l-8 15Zm12-5 6 15-16 4a212 212 0 0 0 10-19Zm-39 41-11-12a240 240 0 0 0 22 0l-11 12Zm-29-22-16-4 6-15a183 183 0 0 0 10 19Zm29-81 11 12a240 240 0 0 0-22 0l11-12ZM66 66a214 214 0 0 0-10 18l-6-15 16-3Zm-35 48c-14-6-22-13-22-19s8-14 22-20l11-4 9 24-9 23-11-4Zm21 56c-5-3-8-15-6-30l2-11 25 4c5 7 10 14 16 19-13 12-25 19-33 19l-4-1Zm92-30c2 15-1 26-6 29l-4 1c-8 0-20-6-33-18 6-5 11-12 16-19l25-4 2 11Zm15-26-11 4-9-23 9-24 11 4c14 6 22 14 22 20s-9 13-22 19Z"
|
||||
/>
|
||||
<path fill="currentColor" d="M95 112a18 18 0 1 0 0-35 18 18 0 0 0 0 35Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
22
src/icons/frameworks/solid.svg
Normal file
@ -0,0 +1,22 @@
|
||||
<svg viewBox="0 0 190 190" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M127.61 135.052C121.624 127.573 113.542 122.052 104.399 119.195C95.2561 116.338 85.4683 116.275 76.2893 119.014L10 140.398C10 140.398 66.6667 183.165 110.503 172.473L113.711 171.404C131.887 166.058 138.302 148.951 127.61 135.052Z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.85"
|
||||
/>
|
||||
<path
|
||||
d="M125.783 81.7735C134.926 84.6307 143.008 90.152 148.994 97.6304C154.34 106.184 155.409 114.737 151.132 122.222L129.748 160.712L129.314 160.639C134.288 153.175 134.123 143.518 127.61 135.052C121.624 127.573 113.542 122.052 104.399 119.195C95.2561 116.338 85.4683 116.275 76.2893 119.014L10 140.398L31.3836 102.976L97.673 81.5926C106.852 78.8533 116.64 78.9163 125.783 81.7735Z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.65"
|
||||
/>
|
||||
<path
|
||||
d="M57.0441 50.5863L61.3208 49.5171C104.088 39.8945 160.755 81.5926 160.755 81.5926L139.663 88.7366C135.466 85.6958 130.783 83.3362 125.783 81.7735C116.64 78.9163 106.852 78.8533 97.673 81.5926L51.96 96.3387C48.5484 93.9348 45.5491 91.1335 43.1447 88.0077C33.5221 73.0392 38.868 55.9322 57.0441 50.5863Z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.45"
|
||||
/>
|
||||
<path
|
||||
d="M79.4969 17.4417C123.333 7.81904 180 49.5172 180 49.5172L160.755 81.5926C160.755 81.5926 104.088 39.8945 61.3208 49.5172L57.0441 50.5863C51.0678 52.344 46.4787 55.3732 43.3525 59.1798C43.2832 59.1664 43.2139 59.1531 43.1447 59.1398L59.1824 31.3411L61.3208 28.1335C64.5283 23.8568 69.8742 20.6492 76.2893 18.5109L79.4969 17.4417Z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.3"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
8
src/icons/frameworks/svelte.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 190 190">
|
||||
<path
|
||||
fill="currentColor"
|
||||
fill-rule="evenodd"
|
||||
d="M87 14c23-15 56-8 72 15v1a50 50 0 0 1 9 38c-1 6-4 12-7 17a50 50 0 0 1-3 51c-4 5-8 10-14 13l-41 26a54 54 0 0 1-81-33v-20c1-7 3-13 7-18a50 50 0 0 1 2-50c4-6 9-10 14-14l42-26ZM63 161c6 2 13 3 20 1l8-4 41-26a28 28 0 0 0 13-31l-5-11a33 33 0 0 0-35-13l-9 4-15 10a9 9 0 0 1-9 0 10 10 0 0 1-6-6v-4a9 9 0 0 1 4-6l41-26 3-1a10 10 0 0 1 10 4l2 6v1l1 1c6 2 12 4 16 8l3 1v-2l1-4a30 30 0 0 0-5-23 33 33 0 0 0-35-13l-8 4-42 26a28 28 0 0 0-13 19 30 30 0 0 0 6 23 33 33 0 0 0 35 13c3 0 5-2 8-3l16-10 2-2a10 10 0 0 1 12 8l1 3a9 9 0 0 1-4 6l-42 26-2 1a10 10 0 0 1-12-10v-1l-2-1c-6-1-11-4-16-8l-2-1-1 2-1 4a30 30 0 0 0 5 23c4 5 10 10 16 12Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 796 B |
11
src/icons/frameworks/vue.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<svg viewBox="0 0 190 190" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M149.4 17.0008H185.426L95.3608 172.999L5.2959 17.0008H41.3223L95.3611 110.598L149.4 17.0008Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M116.16 17.0007L95.3604 53.0268L74.5613 17.0007H41.3223L95.3611 110.598L149.4 17.0007H116.16Z"
|
||||
fill="currentColor"
|
||||
fill-opacity="0.45"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 383 B |
14
src/icons/logomark.svg
Executable file
@ -0,0 +1,14 @@
|
||||
<svg viewBox="0 0 627 894" fill="none">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M445.433 22.9832C452.722 32.0324 456.439 44.2432 463.873 68.6647L626.281 602.176C566.234 571.026 500.957 548.56 432.115 536.439L326.371 179.099C324.641 173.252 319.27 169.241 313.173 169.241C307.06 169.241 301.68 173.273 299.963 179.14L195.5 536.259C126.338 548.325 60.7632 570.832 0.459473 602.095L163.664 68.5412C171.121 44.1617 174.85 31.9718 182.14 22.9393C188.575 14.9651 196.946 8.77213 206.454 4.95048C217.224 0.621582 229.971 0.621582 255.466 0.621582H372.034C397.562 0.621582 410.326 0.621582 421.106 4.95951C430.622 8.78908 438.998 14.9946 445.433 22.9832Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M464.867 627.566C438.094 650.46 384.655 666.073 323.101 666.073C247.551 666.073 184.229 642.553 167.426 610.921C161.419 629.05 160.072 649.798 160.072 663.052C160.072 663.052 156.114 728.134 201.38 773.401C201.38 749.896 220.435 730.842 243.939 730.842C284.226 730.842 284.181 765.99 284.144 794.506C284.143 795.36 284.142 796.209 284.142 797.051C284.142 840.333 310.595 877.436 348.215 893.075C342.596 881.518 339.444 868.54 339.444 854.825C339.444 813.545 363.679 798.175 391.845 780.311C414.255 766.098 439.155 750.307 456.315 718.629C465.268 702.101 470.352 683.17 470.352 663.052C470.352 650.68 468.43 638.757 464.867 627.566Z"
|
||||
fill="#FF5D01"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
6
src/icons/platforms/netlify.svg
Executable file
|
After Width: | Height: | Size: 6.8 KiB |
46
src/icons/platforms/render.svg
Executable file
@ -0,0 +1,46 @@
|
||||
<svg viewBox="0 0 190 190" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M113.3 0H111.3V2V20.5996V22.5996H113.3H131.9H133.9V20.5996V2V0H131.9H113.3Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M53.5 0C46.3 0 39.3002 1.4002 32.7002 4.2002C26.3002 6.9002 20.6002 10.8002 15.7002 15.7002C10.8002 20.6002 6.9002 26.3002 4.2002 32.7002C1.4002 39.3002 0 46.3 0 53.5V131.9V133.9H2H20.5996H22.5996V131.9V53.2002C22.9996 45.1002 26.3996 37.5004 32.0996 31.9004C37.8996 26.2004 45.4996 22.8996 53.5996 22.5996H94.7998H96.7998V20.5996V2V0H94.7998H53.5Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M150.4 74.2002H148.4V76.2002V94.7998V96.7998H150.4H169H171V94.7998V76.2002V74.2002H169H150.4Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M150.4 37.0996H148.4V39.0996V57.7002V59.7002H150.4H169H171V57.7002V39.0996V37.0996H169H150.4Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M169 0H150.4H148.4V2V20.5996V22.5996H150.4H169H171V20.5996V2V0H169Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M150.4 111.3H148.4V113.3V131.9V133.9H150.4H169H171V131.9V113.3V111.3H169H150.4Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M150.4 148.4H148.4V150.4V169V171H150.4H169H171V169V150.4V148.4H169H150.4Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M113.3 148.4H111.3V150.4V169V171H113.3H131.9H133.9V169V150.4V148.4H131.9H113.3Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M76.2002 148.4H74.2002V150.4V169V171H76.2002H94.7998H96.7998V169V150.4V148.4H94.7998H76.2002Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M39.0996 148.4H37.0996V150.4V169V171H39.0996H57.7002H59.7002V169V150.4V148.4H57.7002H39.0996Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M2 148.4H0V150.4V169V171H2H20.5996H22.5996V169V150.4V148.4H20.5996H2Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
3
src/icons/platforms/vercel.svg
Executable file
@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 190 190" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M94.9998 13L190 177.546H0L94.9998 13Z" fill="currentColor" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 155 B |
22
src/icons/wordmark.svg
Executable file
@ -0,0 +1,22 @@
|
||||
<svg viewBox="0 0 1847 457" fill="none">
|
||||
<path
|
||||
d="M134.148 456.833C202.08 456.833 253.03 432.665 273.93 391.516C273.93 411.111 275.23 431.36 278.5 447.036H390.19C384.97 424.173 382.36 392.82 382.36 351.671V251.081C382.36 155.717 326.18 110.648 201.43 110.648C92.3441 110.648 19.188 155.717 10.697 229.527H126.963C130.882 197.521 157.66 179.885 201.43 179.885C244.53 179.885 268.7 197.521 268.7 234.1V243.896L150.48 254.347C92.997 260.227 60.338 270.023 37.477 285.7C13.31 302.028 0.898987 326.851 0.898987 357.549C0.898987 418.948 51.847 456.833 134.148 456.833ZM177.26 388.902C139.37 388.902 116.512 373.88 116.512 349.712C116.512 324.892 135.45 311.827 183.14 305.949L270.66 296.805V316.4C270.66 360.163 232.78 388.902 177.26 388.902Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M625.77 456.833C739.43 456.833 797.56 414.377 797.56 345.793C797.56 288.966 764.9 257.613 685.87 247.162L587.23 236.059C559.15 232.138 547.39 224.953 547.39 209.277C547.39 190.336 566.33 181.844 609.44 181.844C668.88 181.844 710.03 195.561 743.35 222.342L796.25 169.434C759.67 131.55 696.32 110.648 617.94 110.648C507.55 110.648 446.15 149.838 446.15 215.809C446.15 273.289 484.03 305.295 562.41 315.745L651.25 326.196C686.52 330.769 696.97 337.302 696.97 354.283C696.97 373.88 677.37 384.331 631.65 384.331C563.72 384.331 518 366.041 487.3 332.076L427.21 381.717C467.05 431.36 534.98 456.833 625.77 456.833Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M889.78 194.255V332.076C889.78 413.07 935.5 454.221 1033.48 454.221C1063.53 454.221 1087.04 450.955 1109.25 444.423V359.508C1097.49 362.122 1083.12 364.734 1064.18 364.734C1023.03 364.734 1002.78 346.446 1002.78 307.908V194.255H1109.9V120.445H1002.78V0.914001L889.78 42.717V120.445H816.62V194.255H889.78Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M1272.13 120.445H1168.93V447.036H1281.93V324.892C1281.93 289.618 1289.77 257.613 1311.33 237.364C1328.31 221.687 1352.48 213.198 1386.44 213.198C1398.85 213.198 1408.65 214.502 1419.75 215.809V113.26C1412.57 111.954 1407.34 111.954 1398.2 111.954C1333.53 111.954 1289.77 149.185 1272.13 209.932V120.445Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M1643.05 456.833C1762.59 456.833 1846.85 393.475 1846.85 283.088C1846.85 173.353 1762.59 110.648 1643.05 110.648C1522.87 110.648 1438.61 173.353 1438.61 283.088C1438.61 393.475 1522.87 456.833 1643.05 456.833ZM1643.05 381.717C1588.19 381.717 1553.57 346.446 1553.57 283.088C1553.57 219.728 1588.19 185.763 1643.05 185.763C1697.27 185.763 1731.89 219.728 1731.89 283.088C1731.89 346.446 1697.27 381.717 1643.05 381.717Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
74
src/pages/index.astro
Normal file
@ -0,0 +1,74 @@
|
||||
---
|
||||
import "@fontsource-variable/inter";
|
||||
import Compatibility from "~/components/compatibility.astro";
|
||||
import Features from "~/components/features.astro";
|
||||
import Footer from "~/components/footer.astro";
|
||||
import Header from "~/components/header.astro";
|
||||
import Intro from "~/components/intro.astro";
|
||||
import Showcase from "~/components/showcase.astro";
|
||||
import Splash from "~/components/splash.astro";
|
||||
import "~/styles/index.css";
|
||||
|
||||
const { generator, site } = Astro;
|
||||
const image = new URL("social.jpg", site);
|
||||
const description =
|
||||
"Build fast websites, faster. Astro is a new kind of site builder for the modern web. Lightning-fast performance meets powerful developer experience.";
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en" class="h-full motion-safe:scroll-smooth" data-theme="dark">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
||||
<meta name="generator" content={generator} />
|
||||
|
||||
<title>Astro Landing Page</title>
|
||||
<meta name="description" content={description} />
|
||||
|
||||
<!-- social media -->
|
||||
<meta property="og:title" content="Astro" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={image} />
|
||||
<meta property="og:url" content={site} />
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
|
||||
<!-- initialize theme -->
|
||||
<script is:inline>
|
||||
const themeSaved = localStorage.getItem("theme");
|
||||
|
||||
if (themeSaved) {
|
||||
document.documentElement.dataset.theme = themeSaved;
|
||||
} else {
|
||||
const prefersDark = window.matchMedia(
|
||||
"(prefers-color-scheme: dark)",
|
||||
).matches;
|
||||
document.documentElement.dataset.theme = prefersDark ? "dark" : "light";
|
||||
}
|
||||
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", (event) => {
|
||||
if (!localStorage.getItem("theme")) {
|
||||
document.documentElement.dataset.theme = event.matches
|
||||
? "dark"
|
||||
: "light";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body
|
||||
class="h-full overflow-x-hidden bg-default text-default text-base selection:bg-secondary selection:text-white"
|
||||
>
|
||||
<Header />
|
||||
<Splash />
|
||||
<div class="space-y-24 px-8 py-32">
|
||||
<Intro />
|
||||
<Features />
|
||||
<Compatibility />
|
||||
<Showcase />
|
||||
</div>
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
12
src/styles/global.css
Normal file
@ -0,0 +1,12 @@
|
||||
/* TODO: consider creating <Button> and <GradientText> components */
|
||||
a,
|
||||
.btn {
|
||||
@apply transition-colors duration-200;
|
||||
@apply hover:text-secondary;
|
||||
@apply focus:outline-none focus:ring-2 focus:ring-secondary focus:ring-offset-2 focus:ring-offset-transparent;
|
||||
}
|
||||
|
||||
.gradient-text {
|
||||
@apply bg-clip-text text-transparent;
|
||||
@apply bg-gradient-to-br from-indigo-500 via-fuchsia-500 to-pink-500;
|
||||
}
|
||||
2
src/styles/index.css
Normal file
@ -0,0 +1,2 @@
|
||||
@import "global.css";
|
||||
@import "theme.css";
|
||||
19
src/styles/theme.css
Normal file
@ -0,0 +1,19 @@
|
||||
[data-theme="light"] {
|
||||
--color-primary: theme("colors.pink.500");
|
||||
--color-secondary: theme("colors.indigo.500");
|
||||
--color-text: theme("colors.gray.900");
|
||||
--color-text-offset: theme("colors.gray.600");
|
||||
--color-background: theme("colors.gray.50");
|
||||
--color-background-offset: theme("colors.gray.100");
|
||||
--color-border: theme("colors.gray.900" / 10%);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
--color-primary: theme("colors.pink.400");
|
||||
--color-secondary: theme("colors.indigo.400");
|
||||
--color-text: theme("colors.gray.50");
|
||||
--color-text-offset: theme("colors.gray.400");
|
||||
--color-background: theme("colors.gray.900");
|
||||
--color-background-offset: theme("colors.gray.800");
|
||||
--color-border: theme("colors.gray.50" / 10%);
|
||||
}
|
||||
22
src/types.ts
Normal file
@ -0,0 +1,22 @@
|
||||
export interface CompatibilityItem {
|
||||
icon: string;
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface FeatureItem {
|
||||
description: string;
|
||||
icon: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface FooterLink {
|
||||
description: string;
|
||||
icon: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface NavItem {
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
31
tailwind.config.cjs
Normal file
@ -0,0 +1,31 @@
|
||||
const defaultTheme = require("tailwindcss/defaultTheme");
|
||||
|
||||
module.exports = {
|
||||
content: ["./src/**/*.{astro,html,js,jsx,svelte,ts,tsx,vue}"],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ["Inter Variable", ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
colors: {
|
||||
primary: "var(--color-primary)",
|
||||
secondary: "var(--color-secondary)",
|
||||
},
|
||||
textColor: {
|
||||
default: "var(--color-text)",
|
||||
offset: "var(--color-text-offset)",
|
||||
},
|
||||
backgroundColor: {
|
||||
default: "var(--color-background)",
|
||||
offset: "var(--color-background-offset)",
|
||||
},
|
||||
borderColor: {
|
||||
default: "var(--color-border)",
|
||||
},
|
||||
},
|
||||
},
|
||||
corePlugins: {
|
||||
fontSize: false,
|
||||
},
|
||||
plugins: [require("tailwindcss-fluid-type")],
|
||||
};
|
||||
10
tsconfig.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"compilerOptions": {
|
||||
// Alias `src` to `~`
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"~/*": ["src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||