chore: add basic layout

This commit is contained in:
Mathias Schopmans
2024-02-12 14:41:29 +01:00
committed by Mathias Schopmans
parent f3979f2a2f
commit 57cdb91ec7
25 changed files with 2176 additions and 430 deletions

View File

@@ -1,3 +1,6 @@
{
"extends": "next/core-web-vitals"
"extends": "next/core-web-vitals",
"rules": {
"@next/next/no-img-element": "off"
}
}

View File

@@ -1,5 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "export",
// basePath: '/techradar',
reactStrictMode: true,
};

1767
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,10 @@
"prepare": "husky"
},
"dependencies": {
"clsx": "^2.1.0",
"next": "14.1.0",
"postcss-nested": "^6.0.1",
"postcss-preset-env": "^9.3.0",
"react": "^18",
"react-dom": "^18"
},

23
postcss.config.js Normal file
View File

@@ -0,0 +1,23 @@
module.exports = {
plugins:
process.env.NODE_ENV === "production"
? [
"postcss-nested",
[
"postcss-preset-env",
{
autoprefixer: {
flexbox: "no-2009",
},
stage: 3,
features: {
"custom-properties": false,
},
},
],
]
: [
// No transformations in development
// because it won't affect turbo
],
};

1
public/logo.svg Normal file
View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 150 60" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"><rect id="ArtBoard1" x="0" y="0" width="150" height="60" style="fill:none;"/><g><path d="M82.126,28.638c0.058,0.171 -0.042,0.309 -0.22,0.309l-5.318,0c-0.179,0 -0.276,-0.138 -0.217,-0.306l2.817,-8.047c0.059,-0.168 0.155,-0.168 0.212,0l2.726,8.044Zm-6.583,-16.289c-0.179,0 -0.375,0.139 -0.436,0.305l-10.103,27.727c-0.061,0.168 0.035,0.307 0.214,0.307l7.316,0c0.179,0 0.366,-0.141 0.415,-0.312l1.329,-4.609c0.05,-0.173 0.236,-0.311 0.415,-0.311l9.059,0c0.179,0 0.366,0.138 0.415,0.311l1.33,4.609c0.05,0.171 0.236,0.312 0.415,0.312l7.681,0c0.179,0 0.274,-0.139 0.213,-0.304l-10.216,-27.73c-0.062,-0.166 -0.259,-0.305 -0.437,-0.305l-7.61,0Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M107.736,34.36c-3.471,0 -4.925,-1.103 -4.925,-7.937c0,-7.088 1.565,-7.865 4.888,-7.865c3.322,0 4.887,0.777 4.887,7.865c0,6.834 -1.429,7.937 -4.85,7.937Zm-0.037,-22.373c-8.632,0 -12.481,4.453 -12.481,14.436c0,9.897 3.965,14.508 12.481,14.508c8.725,0 12.448,-4.338 12.448,-14.508c0,-9.983 -3.84,-14.436 -12.448,-14.436Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M124.72,40.35c0,0.175 0.142,0.318 0.317,0.318l21.646,0c0.174,0 0.317,-0.143 0.317,-0.318l0,-5.934c0,-0.175 -0.143,-0.319 -0.317,-0.319l-21.646,0c-0.175,0 -0.317,0.144 -0.317,0.319l0,5.934Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M125.032,12.349c-0.175,0 -0.318,0.144 -0.318,0.319l0,5.934c0,0.175 0.143,0.317 0.318,0.317l21.645,0c0.175,0 0.318,-0.142 0.318,-0.317l0,-5.934c0,-0.175 -0.143,-0.319 -0.318,-0.319l-21.645,0Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M124.714,29.476c0,0.175 0.143,0.319 0.318,0.319l21.645,0c0.175,0 0.318,-0.144 0.318,-0.319l0,-5.934c0,-0.175 -0.143,-0.319 -0.318,-0.319l-21.645,0c-0.175,0 -0.318,0.144 -0.318,0.319l0,5.934Z" style="fill:#fff;fill-rule:nonzero;"/><path d="M29.494,9.418c-0.34,-0.148 -0.896,-0.148 -1.237,-0.002l-16.929,7.333c-0.341,0.146 -0.357,0.421 -0.036,0.609l16.962,9.88c0.321,0.188 0.583,0.643 0.584,1.016l0.01,19.427c0,0.372 0.246,0.496 0.545,0.277l14.717,-10.737c0.3,-0.217 0.58,-0.699 0.623,-1.067l2.132,-18.436c0.043,-0.367 -0.201,-0.791 -0.541,-0.94l-16.83,-7.36Zm25.668,2.35c0.343,0.141 0.581,0.557 0.529,0.922l-3.888,27.472c-0.052,0.368 -0.334,0.855 -0.626,1.084l-21.793,17.038c-0.292,0.229 -0.77,0.229 -1.063,0l-21.79,-17.038c-0.293,-0.229 -0.575,-0.716 -0.627,-1.084l-3.897,-27.472c-0.052,-0.365 0.187,-0.781 0.53,-0.922l25.714,-10.509c0.343,-0.141 0.905,-0.141 1.248,0l25.663,10.509Z" style="fill:#fff;"/></g></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

127
public/messages.json Normal file
View File

@@ -0,0 +1,127 @@
{
"radarName": "AOE Technology Radar",
"footerFootnote": "AOE is a leading global provider of services for digital transformation and digital business models. AOE relies exclusively on established Enterprise Open Source technologies. This leads to innovative solutions, digital products and portals in agile software projects, and helps build long-lasting, strategic partnerships with our customers.",
"legalInformationLabel": "Legal Information",
"legalInformationLink": "https://www.aoe.com/en/imprint.html",
"pageHelp": {
"headlinePrefix": "How to use the",
"paragraphs": [
{
"headline": "Introduction",
"values": [
"Technology is moving fast and new technologies and innovations appear continuously.",
"It's essential for a development and technology company such as AOE to constantly improve and keep track with the latest useful innovations. It is important to openly look for innovations and new technologies and to question established technologies and methods every now and then.",
"But, it is also important to wisely choose which technologies to use in our daily work and in the different projects we are carrying out. As we all know: There is no silver bullet."
]
},
{
"headline": "What is the AOE Technology Radar",
"values": [
"The Tech Radar is an overview of different technologies - from languages, frameworks, tools and patterns to platforms - that we consider \"new or mentionable\". The radar therefore doesn't provide an overview of all established technologies - but it focuses on items that have recently gained in importance or changed."
]
},
{
"headline": "How it is created",
"values": [
"The items in the technology radar are raised by the different teams and therefore a lot of the items are related to the work and challenges the teams face in the different projects. In fact, we don't include anything on the radar, which we haven't already tried ourselves at least once.",
"There have been a lot of valuable discussions in different expert groups about the classification and details of each of technologies and innovations. And the result of all this can be found in the latest technology radar."
]
},
{
"headline": "How should it be used",
"values": [
"The radar acts as an overview of technologies that we think everyone in the teams should currently know about.",
"Its goal is to act as a guide and inspiration for the daily work in the teams. Its purpose is also to provide helpful information and a bird's-eye perspective - so that decisions can be taken with a much deeper understanding of the subject matter. This results in more-informed and better-aligned decisions.",
"We also hope that developers outside of AOE find the information in our technology overview inspirational.",
"We group or categorize the items in 4 quadrants - (sometimes, when it's not 100% clear where a item belongs, we choose the best fit)."
]
}
],
"quadrants": [
{
"description": "We've placed development languages (such as Scala or Golang) here, as well as more low-level development frameworks (such as Play or Symfony), which are useful for implementing custom software of all kinds.",
"name": "Languages and Frameworks"
},
{
"description": "Here we put different software tools - from small helpers to bigger software projects.",
"name": "Tools"
},
{
"description": "Patterns are so important, and a lot of them are valid for a long time (compared to some tools or frameworks). So, this is the category where we put information on methods and patterns concerning development, continuous x, testing, organization, architecture, etc.",
"name": "Methods and Patterns"
},
{
"description": "(including AOE internal Services): Here we include infrastructure platforms and services. We also use this category to communicate news about AOE services that we want all AOE teams to be aware of.",
"name": "Platforms and Operations"
}
],
"quadrantsPreDescription": "The quadrants are:",
"rings": [
{
"description": "We can clearly recommend this technology. We have used it for longer period of time in many teams and it has proven to be stable and useful.",
"name": "Adopt"
},
{
"description": "We have used it with success and recommend to have a closer look at the technology in this ring. The goal of items here is to look at them more closely, with the goal to bring them to the adopt level.",
"name": "Trial"
},
{
"description": "We have tried it out and we find it promising. We recommend having a look at these items when you face a specific need for the technology in your project.",
"name": "Assess"
},
{
"description": "This category is a bit special. Unlike the others, we recommend to stop doing or using something. That does not mean that they are bad and it often might be ok to use them in existing projects. But we move things here if we think we shouldn't do them anymore - because we see better options or alternatives now.",
"name": "Hold"
}
],
"ringsPreDescription": "Each of the items is classified in one of these rings:",
"sourcecodeLink": {
"description": "Contributions and source code of the AOE Tech Radar are on github:",
"href": "https://github.com/AOEpeople/aoe_technology_radar",
"name": "AOE Tech Radar on Github"
}
},
"pageIndex": {
"publishedLabel": "Quadrant Overview"
},
"pageItem": {
"quadrantOverview": "Quadrant Overview"
},
"pageOverview": {
"title": "Technologies Overview"
},
"revisionsText": "Revisions:",
"searchLabel": "Search",
"searchPlaceholder": "What are you looking for?",
"socialLinks": [
{
"href": "https://www.facebook.com/aoepeople",
"iconName": "facebook"
},
{
"href": "https://twitter.com/aoepeople",
"iconName": "twitter"
},
{
"href": "https://www.linkedin.com/company/aoe",
"iconName": "linkedIn"
},
{
"href": "https://www.xing.com/company/aoe",
"iconName": "xing"
},
{
"href": "https://www.instagram.com/aoepeople",
"iconName": "instagram"
},
{
"href": "https://www.youtube.com/user/aoepeople",
"iconName": "youtube"
},
{
"href": "https://github.com/aoepeople",
"iconName": "github"
}
],
"socialLinksLabel": "Follow us:"
}

View File

View File

@@ -0,0 +1,9 @@
import styles from "Footer.module.css";
export function Footer() {
return (
<div className={styles.footer}>
<div className={styles.branding}></div>
</div>
);
}

View File

@@ -0,0 +1,23 @@
.layout {
min-height: 100vh;
}
.container {
max-width: var(--max-width);
margin: 0 auto;
padding: 20px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
.layout.default {
.content {
max-width: var(--max-width);
margin: 0 auto;
padding: 20px;
}
}

View File

@@ -0,0 +1,35 @@
import { Roboto } from "next/font/google";
import type { FC, ReactNode } from "react";
import styles from "./Layout.module.css";
import { Logo } from "@/components/Logo/Logo";
import { Navigation } from "@/components/Navigation/Navigation";
import { cn } from "@/lib/utils";
const font = Roboto({ weight: ["400", "700"], subsets: ["latin"] });
export type LayoutClass = "default" | "full";
interface LayoutProps {
children: ReactNode;
layoutClass?: LayoutClass;
}
export const Layout: FC<LayoutProps> = ({
children,
layoutClass = "default",
}) => {
return (
<div className={cn(styles.layout, font.className, styles[layoutClass])}>
<header className={cn(styles.container, styles.header)}>
<Logo />
<Navigation />
</header>
<main className={cn(styles.content)}>{children}</main>
<footer className={cn(styles.container, styles.header)}>
<h2>Footer</h2>
</footer>
</div>
);
};

View File

@@ -0,0 +1,50 @@
.logo {
position: relative;
display: flex;
justify-content: flex-start;
align-items: center;
min-height: 60px;
gap: 16px;
transition: padding-left 200ms ease-in-out;
&:before {
content: "";
display: block;
position: absolute;
left: 0;
width: 22px;
height: 22px;
background: url("../../icons/back.svg") no-repeat 50% 50%;
opacity: 0;
transition: opacity 200ms ease-in-out;
}
}
.src {
width: 150px;
transition: width 200ms ease-in-out;
}
.subline {
position: relative;
top: -2px;
font-size: 18px;
opacity: 0;
transition: opacity 200ms ease-in-out;
}
.logo.small {
.subline {
opacity: 0.8;
}
.src {
width: 75px;
}
&:hover {
padding-left: 30px;
&:before {
opacity: 1;
}
}
}

View File

@@ -0,0 +1,21 @@
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import logo from "../../../public/logo.svg";
import styles from "./Logo.module.css";
import { getAppName } from "@/lib/config";
import { cn } from "@/lib/utils";
export function Logo() {
const pathname = usePathname();
const appName = getAppName();
return (
<Link href="/" className={cn(styles.logo, pathname != "/" && styles.small)}>
<img src={logo.src} className={cn(styles.src)} alt={appName} />
<span className={styles.subline}>{appName}</span>
</Link>
);
}

View File

@@ -0,0 +1,6 @@
.list {
list-style: none;
display: flex;
gap: 16px;
font-size: 14px;
}

View File

@@ -0,0 +1,24 @@
import Link from "next/link";
import styles from "./Navigation.module.css";
import { getAppName } from "@/lib/config";
export function Navigation() {
return (
<nav className={styles.nav}>
<ul className={styles.list}>
<li className={styles.item}>
<Link href="/help-and-about-tech-radar">
How to use {getAppName()}?
</Link>
</li>
<li className={styles.item}>Filter</li>
<li className={styles.item}>
<Link href="/overview">Technologies Overview</Link>
</li>
<li className={styles.item}>Search</li>
</ul>
</nav>
);
}

3
src/icons/back.svg Normal file
View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421"
viewBox="0 0 30 21"><path d="M4.012 11.427h24.704a1.134 1.134 0 0 0 0-2.267H3.729l7.224-7.225A1.133 1.133 0 1 0 9.35.332L.332 9.35a1.134 1.134 0 0 0-.106 1.481c.099.182.245.335.423.439l8.701 8.701a1.133 1.133 0 1 0 1.603-1.603l-6.941-6.941Z" style="fill:#fff"/></svg>

After

Width:  |  Height:  |  Size: 424 B

5
src/lib/config.ts Normal file
View File

@@ -0,0 +1,5 @@
import messages from "../../public/messages.json";
export function getAppName() {
return messages.radarName;
}

5
src/lib/data.ts Normal file
View File

@@ -0,0 +1,5 @@
import messages from "../../public/messages.json";
export function getMessages() {
return messages;
}

5
src/lib/utils.ts Normal file
View File

@@ -0,0 +1,5 @@
import { type ClassValue, clsx } from "clsx";
export function cn(...inputs: ClassValue[]) {
return clsx(inputs);
}

View File

@@ -1,7 +1,21 @@
import { NextPage } from "next";
import type { AppProps } from "next/app";
import { Layout, type LayoutClass } from "@/components/Layout/Layout";
import "@/styles/globals.css";
export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
export type CustomPage<P = {}, IP = P> = NextPage<P, IP> & {
layoutClass?: LayoutClass;
};
type CustomAppProps = AppProps & {
Component: CustomPage;
};
export default function App({ Component, pageProps, router }: CustomAppProps) {
return (
<Layout layoutClass={Component.layoutClass}>
<Component {...pageProps} key={router.asPath} />
</Layout>
);
}

View File

@@ -1,13 +0,0 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next";
type Data = {
name: string;
};
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>,
) {
res.status(200).json({ name: "John Doe" });
}

View File

@@ -0,0 +1,19 @@
import Head from "next/head";
import { CustomPage } from "@/pages/_app";
const HelpAndAbout: CustomPage = () => {
return (
<>
<Head>
<title>Help and About</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<h1>Help and about</h1>
</>
);
};
export default HelpAndAbout;

View File

@@ -1,12 +1,8 @@
import { Inter } from "next/font/google";
import Head from "next/head";
import Image from "next/image";
import styles from "@/styles/Home.module.css";
import { CustomPage } from "@/pages/_app";
const inter = Inter({ subsets: ["latin"] });
export default function Home() {
const Home: CustomPage = () => {
return (
<>
<Head>
@@ -15,101 +11,10 @@ export default function Home() {
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={`${styles.main} ${inter.className}`}>
<div className={styles.description}>
<p>
Get started by editing&nbsp;
<code className={styles.code}>src/pages/index.tsx</code>
</p>
<div>
<a
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
By{" "}
<Image
src="/vercel.svg"
alt="Vercel Logo"
className={styles.vercelLogo}
width={100}
height={24}
priority
/>
</a>
</div>
</div>
<div className={styles.center}>
<Image
className={styles.logo}
src="/next.svg"
alt="Next.js Logo"
width={180}
height={37}
priority
/>
</div>
<div className={styles.grid}>
<a
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Docs <span>-&gt;</span>
</h2>
<p>
Find in-depth information about Next.js features and&nbsp;API.
</p>
</a>
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Learn <span>-&gt;</span>
</h2>
<p>
Learn about Next.js in an interactive course with&nbsp;quizzes!
</p>
</a>
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Templates <span>-&gt;</span>
</h2>
<p>
Discover and deploy boilerplate example Next.js&nbsp;projects.
</p>
</a>
<a
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Deploy <span>-&gt;</span>
</h2>
<p>
Instantly deploy your Next.js site to a shareable URL
with&nbsp;Vercel.
</p>
</a>
</div>
</main>
<h1>Hello world.</h1>
</>
);
}
};
export default Home;

View File

@@ -1,235 +0,0 @@
.main {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 6rem;
min-height: 100vh;
}
.description {
display: inherit;
justify-content: inherit;
align-items: inherit;
font-size: 0.85rem;
max-width: var(--max-width);
width: 100%;
z-index: 2;
font-family: var(--font-mono);
}
.description a {
display: flex;
justify-content: center;
align-items: center;
gap: 0.5rem;
}
.description p {
position: relative;
margin: 0;
padding: 1rem;
background-color: rgba(var(--callout-rgb), 0.5);
border: 1px solid rgba(var(--callout-border-rgb), 0.3);
border-radius: var(--border-radius);
}
.code {
font-weight: 700;
font-family: var(--font-mono);
}
.grid {
display: grid;
grid-template-columns: repeat(4, minmax(25%, auto));
max-width: 100%;
width: var(--max-width);
}
.card {
padding: 1rem 1.2rem;
border-radius: var(--border-radius);
background: rgba(var(--card-rgb), 0);
border: 1px solid rgba(var(--card-border-rgb), 0);
transition:
background 200ms,
border 200ms;
}
.card span {
display: inline-block;
transition: transform 200ms;
}
.card h2 {
font-weight: 600;
margin-bottom: 0.7rem;
}
.card p {
margin: 0;
opacity: 0.6;
font-size: 0.9rem;
line-height: 1.5;
max-width: 30ch;
}
.center {
display: flex;
justify-content: center;
align-items: center;
position: relative;
padding: 4rem 0;
}
.center::before {
background: var(--secondary-glow);
border-radius: 50%;
width: 480px;
height: 360px;
margin-left: -400px;
}
.center::after {
background: var(--primary-glow);
width: 240px;
height: 180px;
z-index: -1;
}
.center::before,
.center::after {
content: "";
left: 50%;
position: absolute;
filter: blur(45px);
transform: translateZ(0);
}
.logo {
position: relative;
}
/* Enable hover only on non-touch devices */
@media (hover: hover) and (pointer: fine) {
.card:hover {
background: rgba(var(--card-rgb), 0.1);
border: 1px solid rgba(var(--card-border-rgb), 0.15);
}
.card:hover span {
transform: translateX(4px);
}
}
@media (prefers-reduced-motion) {
.card:hover span {
transform: none;
}
}
/* Mobile */
@media (max-width: 700px) {
.content {
padding: 4rem;
}
.grid {
grid-template-columns: 1fr;
margin-bottom: 120px;
max-width: 320px;
text-align: center;
}
.card {
padding: 1rem 2.5rem;
}
.card h2 {
margin-bottom: 0.5rem;
}
.center {
padding: 8rem 0 6rem;
}
.center::before {
transform: none;
height: 300px;
}
.description {
font-size: 0.8rem;
}
.description a {
padding: 1rem;
}
.description p,
.description div {
display: flex;
justify-content: center;
position: fixed;
width: 100%;
}
.description p {
align-items: center;
inset: 0 0 auto;
padding: 2rem 1rem 1.4rem;
border-radius: 0;
border: none;
border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);
background: linear-gradient(
to bottom,
rgba(var(--background-start-rgb), 1),
rgba(var(--callout-rgb), 0.5)
);
background-clip: padding-box;
backdrop-filter: blur(24px);
}
.description div {
align-items: flex-end;
pointer-events: none;
inset: auto 0 0;
padding: 2rem;
height: 200px;
background: linear-gradient(
to bottom,
transparent 0%,
rgb(var(--background-end-rgb)) 40%
);
z-index: 1;
}
}
/* Tablet and Smaller Desktop */
@media (min-width: 701px) and (max-width: 1120px) {
.grid {
grid-template-columns: repeat(2, 50%);
}
}
@media (prefers-color-scheme: dark) {
.vercelLogo {
filter: invert(1);
}
.logo {
filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);
}
}
@keyframes rotate {
from {
transform: rotate(360deg);
}
to {
transform: rotate(0deg);
}
}
#lore {
display: block;
}

View File

@@ -1,76 +1,12 @@
:root {
--max-width: 1100px;
--max-width: 1200px;
--border-radius: 12px;
--font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
"Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
"Fira Mono", "Droid Sans Mono", "Courier New", monospace;
--foreground-rgb: 0, 0, 0;
--background-start-rgb: 214, 219, 220;
--background-end-rgb: 255, 255, 255;
--primary-glow: conic-gradient(
from 180deg at 50% 50%,
#16abff33 0deg,
#0885ff33 55deg,
#54d6ff33 120deg,
#0071ff33 160deg,
transparent 360deg
);
--secondary-glow: radial-gradient(
rgba(255, 255, 255, 1),
rgba(255, 255, 255, 0)
);
--tile-start-rgb: 239, 245, 249;
--tile-end-rgb: 228, 232, 233;
--tile-border: conic-gradient(
#00000080,
#00000040,
#00000030,
#00000020,
#00000010,
#00000010,
#00000080
);
--callout-rgb: 238, 240, 241;
--callout-border-rgb: 172, 175, 176;
--card-rgb: 180, 185, 188;
--card-border-rgb: 131, 134, 135;
}
@media (prefers-color-scheme: dark) {
:root {
--foreground-rgb: 255, 255, 255;
--background-start-rgb: 0, 0, 0;
--background-end-rgb: 0, 0, 0;
--primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
--secondary-glow: linear-gradient(
to bottom right,
rgba(1, 65, 255, 0),
rgba(1, 65, 255, 0),
rgba(1, 65, 255, 0.3)
);
--tile-start-rgb: 2, 13, 46;
--tile-end-rgb: 2, 5, 19;
--tile-border: conic-gradient(
#ffffff80,
#ffffff40,
#ffffff30,
#ffffff20,
#ffffff10,
#ffffff10,
#ffffff80
);
--callout-rgb: 20, 20, 20;
--callout-border-rgb: 108, 108, 108;
--card-rgb: 100, 100, 100;
--card-border-rgb: 200, 200, 200;
}
--foreground: #fff;
--background: #173d7a;
}
* {
@@ -86,13 +22,8 @@ body {
}
body {
color: rgb(var(--foreground-rgb));
background: linear-gradient(
to bottom,
transparent,
rgb(var(--background-end-rgb))
)
rgb(var(--background-start-rgb));
color: var(--foreground);
background: var(--background);
}
a {
@@ -100,8 +31,21 @@ a {
text-decoration: none;
}
@media (prefers-color-scheme: dark) {
html {
color-scheme: dark;
p {
margin-bottom: 1em;
}
img {
max-width: 100%;
height: auto;
}
svg {
display: block;
}
.container {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 1rem;
}