main
adb-sh 5 months ago
commit 17a815d185

29
.gitignore vendored

@ -0,0 +1,29 @@
dist
.solid
.output
.vercel
.netlify
netlify
.vinxi
# Environment
.env
.env*.local
# dependencies
/node_modules
# IDEs and editors
/.idea
.project
.classpath
*.launch
.settings/
# Temp
gitignore
# System Files
.DS_Store
Thumbs.db

@ -0,0 +1,11 @@
FROM node:alpine
EXPOSE 3000
WORKDIR /app
ADD . .
RUN npm ci\
&& npm run build
CMD ["npm", "run", "start"]

@ -0,0 +1,32 @@
# SolidStart
Everything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com);
## Creating a project
```bash
# create a new project in the current directory
npm init solid@latest
# create a new project in my-app
npm init solid@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
## Building
Solid apps are built with _presets_, which optimise your project for deployment to different environments.
By default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different preset, add it to the `devDependencies` in `package.json` and specify in your `app.config.js`.
## This project was created with the [Solid CLI](https://solid-cli.netlify.app)

@ -0,0 +1,19 @@
// app.config.ts
import { defineConfig } from "@solidjs/start/config";
import pkg from "@vinxi/plugin-mdx";
var { default: mdx } = pkg;
var app_config_default = defineConfig({
extensions: ["mdx", "md"],
vite: {
plugins: [
mdx.withImports({})({
jsx: true,
jsxImportSource: "solid-js",
providerImportSource: "solid-mdx"
})
]
}
});
export {
app_config_default as default
};

@ -0,0 +1,19 @@
// app.config.ts
import { defineConfig } from "@solidjs/start/config";
import pkg from "@vinxi/plugin-mdx";
var { default: mdx } = pkg;
var app_config_default = defineConfig({
extensions: ["mdx", "md"],
vite: {
plugins: [
mdx.withImports({})({
jsx: true,
jsxImportSource: "solid-js",
providerImportSource: "solid-mdx"
})
]
}
});
export {
app_config_default as default
};

@ -0,0 +1,17 @@
import { defineConfig } from "@solidjs/start/config";
/* @ts-ignore */
import pkg from "@vinxi/plugin-mdx";
const { default: mdx } = pkg;
export default defineConfig({
extensions: ["mdx", "md"],
vite: {
plugins: [
mdx.withImports({})({
jsx: true,
jsxImportSource: "solid-js",
providerImportSource: "solid-mdx",
}),
],
},
});

10290
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,27 @@
{
"name": "example-with-tailwindcss",
"type": "module",
"scripts": {
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start"
},
"dependencies": {
"@mdx-js/mdx": "^2.3.0",
"@solidjs/router": "^0.13.3",
"@solidjs/start": "^1.0.0-rc.1",
"@vinxi/plugin-mdx": "^3.7.1",
"apexcharts": "^3.49.1",
"autoprefixer": "^10.4.19",
"daisyui": "^4.11.1",
"postcss": "^8.4.38",
"solid-apexcharts": "^0.3.4",
"solid-js": "^1.8.17",
"solid-mdx": "^0.0.7",
"tailwindcss": "^3.4.3",
"vinxi": "^0.3.11"
},
"engines": {
"node": ">=18"
}
}

@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

@ -0,0 +1,16 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
h1 {
@apply text-5xl font-bold;
}
h2 {
@apply text-4xl font-bold;
}
h3 {
@apply text-3xl font-bold;
}
h3 {
@apply text-2xl font-bold;
}

@ -0,0 +1,27 @@
import { Router } from "@solidjs/router";
import { FileRoutes } from "@solidjs/start/router";
import { Suspense } from "solid-js";
import Nav from "~/components/Nav";
import Footer from "./components/Footer";
import "./app.css";
import "./fonts.css";
export default function App() {
return (
<Router
root={(props) => (
<>
<div class="min-h-screen flex flex-col justify-between">
<div>
<Nav />
<Suspense>{props.children}</Suspense>
</div>
<Footer />
</div>
</>
)}
>
<FileRoutes />
</Router>
);
}

@ -0,0 +1,13 @@
import { createSignal } from "solid-js";
export default function Counter() {
const [count, setCount] = createSignal(0);
return (
<button
class="w-[200px] rounded-full bg-gray-100 border-2 border-gray-300 focus:border-gray-400 active:border-gray-400 px-[2rem] py-[1rem]"
onClick={() => setCount(count() + 1)}
>
Clicks: {count()}
</button>
);
}

@ -0,0 +1,54 @@
import { SolidApexCharts } from "solid-apexcharts";
export default ({ data }) => {
return (
<SolidApexCharts
type="area"
options={{
yaxis: {
labels: {
formatter: (val) => (val).toFixed(0),
},
title: {
text: "Queries/s",
},
logarithmic: true,
forceNiceScale: true,
},
xaxis: {
min: data.start,
max: data.end,
type: "datetime",
},
chart: {
toolbar: {
show: false,
},
},
dataLabels: {
enabled: false
},
fill: {
type: "gradient",
gradient: {
type: "horizontal",
shadeIntensity: 1,
inverseColors: false,
opacityFrom: 0.5,
opacityTo: 0,
stops: [0, 90, 100],
},
},
}}
series={[
{
name: "Traffic",
data: data.data.map(([time, value]) => [time * 1000, value]),
color: "#209680",
type: "area",
},
]}
/>
// <div>{JSON.stringify(data)}</div>
);
};

@ -0,0 +1,33 @@
import { useLocation } from "@solidjs/router";
import { A } from "@solidjs/router";
export default function Footer() {
return (
<footer class="footer p-10 bg-base-300 text-base-content">
<aside>
<img src="/assets/ddix-logo.svg" class="h-16" />
<p>© 2024 DD-IX Dresden Internet Exchange e.V.</p>
</aside>
<nav>
<h6 class="footer-title">Services</h6>
<a class="link link-hover">Branding</a>
<a class="link link-hover">Design</a>
<a class="link link-hover">Marketing</a>
<a class="link link-hover">Advertisement</a>
</nav>
<nav>
<h6 class="footer-title">Company</h6>
<a class="link link-hover">About us</a>
<a class="link link-hover">Contact</a>
<a class="link link-hover">Jobs</a>
<a class="link link-hover">Press kit</a>
</nav>
<nav>
<h6 class="footer-title">Legal</h6>
<a class="link link-hover">Terms of use</a>
<a class="link link-hover">Privacy policy</a>
<a class="link link-hover">Cookie policy</a>
</nav>
</footer>
);
}

@ -0,0 +1,72 @@
import { useLocation } from "@solidjs/router";
import { A } from "@solidjs/router";
export default function Nav() {
const location = useLocation();
const active = (path: string) =>
path == location.pathname
? "border-sky-600"
: "border-transparent hover:border-sky-600";
return (
<header class="p-4 fixed w-full top-0 z-10">
<div class="navbar backdrop-blur-md bg-base-200/50 shadow-xl">
<div class="navbar-start">
<div class="dropdown">
<div tabindex="0" role="button" class="btn btn-ghost lg:hidden">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h8m-8 6h16"
/>
</svg>
</div>
<ul
tabindex="0"
class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-52"
>
<li>
<a>Item 1</a>
</li>
<li>
<a>Parent</a>
<ul class="p-2">
<li>
<a>Submenu 1</a>
</li>
<li>
<a>Submenu 2</a>
</li>
</ul>
</li>
<li>
<a>Item 3</a>
</li>
</ul>
</div>
<A class="btn btn-ghost text-xl" href="/">
<img src="/assets/ddix-logo.svg" class="h-full p-2" />
</A>
</div>
<div class="navbar-end">
<A class="btn btn-ghost mr-2" href="/statistics">
Stats
</A>
<A class="btn btn-ghost mr-2" href="/news">
News
</A>
<A class="btn btn-ghost" href="/network">
Network
</A>
</div>
</div>
</header>
);
}

@ -0,0 +1,49 @@
import { createSignal, For, Show } from "solid-js";
import { cache, createAsync, A, type RouteDefinition } from "@solidjs/router";
const getNewsList = cache(async () => {
"use server";
return await fetch("https://content.dd-ix.net/news/en").then((data) =>
data.json()
);
}, "news-list");
const getNewsTags = cache(async () => {
"use server";
return await fetch("https://content.dd-ix.net/news/keywords").then((data) =>
data.json()
);
}, "news-tags");
export const route = {
load: () => {
getNewsList();
getNewsTags();
},
} satisfies RouteDefinition;
export const NewsList = ({ limit }: { limit: number }) => {
const newsList = createAsync(() => getNewsList());
const tags = createAsync(() => getNewsTags());
return (
<For each={newsList()?.slice(0, limit)}>
{(post) => (
<A href={`/news/${post.slug}`}>
<figure class="card md:card-side bg-base-100 shadow-xl mt-4">
<img
src={`https://content.dd-ix.net/news/assets/${post.image}`}
alt={post.title}
class="md:w-48 object-cover"
/>
<div class="card-body">
<h2 class="card-title">{post.title}</h2>
<p>{post.published}</p>
<p>{post.description}</p>
</div>
</figure>
</A>
)}
</For>
);
};

@ -0,0 +1,54 @@
import { SolidApexCharts } from "solid-apexcharts";
export default ({ data }) => {
return (
<SolidApexCharts
type="line"
options={{
yaxis: {
labels: {
formatter: (val) => (val / 1000).toFixed(0),
},
title: {
text: "Traffic in kb/s",
},
logarithmic: true,
forceNiceScale: true,
},
xaxis: {
min: data.start,
max: data.end,
type: "datetime",
},
chart: {
toolbar: {
show: false,
},
},
dataLabels: {
enabled: false
},
fill: {
type: "gradient",
gradient: {
type: "horizontal",
shadeIntensity: 1,
inverseColors: false,
opacityFrom: 0.5,
opacityTo: 0,
stops: [0, 90, 100],
},
},
}}
series={[
{
name: "Traffic",
data: data.data.map(([time, value]) => [time * 1000, value]),
color: "#209680",
type: "area",
},
]}
/>
// <div>{JSON.stringify(data)}</div>
);
};

@ -0,0 +1,4 @@
// @refresh reload
import { mount, StartClient } from "@solidjs/start/client";
mount(() => <StartClient />, document.getElementById("app")!);

@ -0,0 +1,21 @@
// @refresh reload
import { createHandler, StartServer } from "@solidjs/start/server";
export default createHandler(() => (
<StartServer
document={({ assets, children, scripts }) => (
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
{assets}
</head>
<body>
<div id="app">{children}</div>
{scripts}
</body>
</html>
)}
/>
));

@ -0,0 +1,71 @@
/* ubuntu-300 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Ubuntu";
font-style: normal;
font-weight: 300;
src: url("/fonts/ubuntu-v20-latin-300.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* ubuntu-300italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Ubuntu";
font-style: italic;
font-weight: 300;
src: url("/fonts/ubuntu-v20-latin-300italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* ubuntu-regular - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Ubuntu";
font-style: normal;
font-weight: 400;
src: url("/fonts/ubuntu-v20-latin-regular.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* ubuntu-italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Ubuntu";
font-style: italic;
font-weight: 400;
src: url("/fonts/ubuntu-v20-latin-italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* ubuntu-500 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Ubuntu";
font-style: normal;
font-weight: 500;
src: url("/fonts/ubuntu-v20-latin-500.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* ubuntu-500italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Ubuntu";
font-style: italic;
font-weight: 500;
src: url("/fonts/ubuntu-v20-latin-500italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* ubuntu-700 - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Ubuntu";
font-style: normal;
font-weight: 700;
src: url("/fonts/ubuntu-v20-latin-700.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}
/* ubuntu-700italic - latin */
@font-face {
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
font-family: "Ubuntu";
font-style: italic;
font-weight: 700;
src: url("/fonts/ubuntu-v20-latin-700italic.woff2") format("woff2"); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
}

1
src/global.d.ts vendored

@ -0,0 +1 @@
/// <reference types="@solidjs/start/env" />

@ -0,0 +1,9 @@
import { A } from "@solidjs/router";
export default function NotFound() {
return (
<main class="text-center p-4">
<h1>Not Found :/</h1>
</main>
);
}

@ -0,0 +1,25 @@
import { A } from "@solidjs/router";
import Counter from "~/components/Counter";
export default function About() {
return (
<main class="text-center mx-auto text-gray-700 p-4">
<h1 class="max-6-xs text-6xl text-sky-700 font-thin uppercase my-16">About Page</h1>
<Counter />
<p class="mt-8">
Visit{" "}
<a href="https://solidjs.com" target="_blank" class="text-sky-600 hover:underline">
solidjs.com
</a>{" "}
to learn how to build Solid apps.
</p>
<p class="my-4">
<A href="/" class="text-sky-600 hover:underline">
Home
</A>
{" - "}
<span>About Page</span>
</p>
</main>
);
}

@ -0,0 +1,68 @@
import { A } from "@solidjs/router";
import { NewsList } from "~/components/NewsList"
<main>
<div
class="hero h-[70vh] min-h-96"
style="background-image: url(/dresden.webp);"
>
<div class="hero-overlay bg-opacity-40 backdrop-blur-sm"></div>
<div class="hero-content text-center text-neutral-content">
<div class="max-w-xl">
<h1 class="text-5xl md:text-7xl">Keep Local<br/>Traffic Local</h1>
<div class="divider"></div>
<div class="flex gap-2 justify-center">
<A href="/peering" class="btn btn-primary">Start Peering</A>
<A href="" class="btn btn-outline">Support Us</A>
</div>
</div>
</div>
</div>
<section class="container mx-auto p-4">
<div class="flex flex-col md:flex-row mx-8 justify-center min-h-[40vh]">
<div class="grow p-8">
<div class="flex items-center sticky top-[40vh] text-5xl relative">
<h2>Internet Exchange</h2>
<div class="circle bg-primary h-5 w-5 rounded-full absolute left-[-2.5rem] md:left-auto md:right-[-2.75rem]"></div>
</div>
</div>
<div class="grow flex flex-col justify-center gap-4 p-8 border-primary" style="border-bottom-width: 0.25rem; border-left-width: 0.25rem;">
<p class="text-xl">DD-IX is an Internet exchange for Dresden and whole Saxony. As a non-commercial platform, we are open to all Internet stakeholders that are interested in multilateral exchange of Internet traffic.</p>
<A href="" class="btn btn-outline w-fit">Learn More</A>
</div>
</div>
<div class="flex flex-col-reverse md:flex-row mx-8 mt-[-0.25rem] justify-center min-h-[40vh]">
<div class="grow flex flex-col justify-center gap-4 p-8 border-primary" style="border-bottom-width: 0.25rem; border-right-width: 0.25rem">
<p class="text-xl">The DD-IX is operated by committed people of the DD-IX Dresden Internet Exchange e.V. The DD-IX Dresden Internet Exchange e.V. is a registered association under German law. Our mission is the economical, ecological, and robust exchange of data over the Internet. To enable direct data delivery between source and destination, we leverage the unique advantages of an Internet Exchage Point (IXP).</p>
<A href="" class="btn btn-outline w-fit">Support Us</A>
</div>
<div class="grow p-8 border-transparent md:border-base-100" style="border-top-width: 0.25rem;">
<div class="flex items-center sticky top-[40vh] text-5xl relative">
<div class="circle bg-primary h-5 w-5 rounded-full absolute right-[-2.5rem] md:right-auto md:left-[-2.75rem]"></div>
<h2>Association</h2>
</div>
</div>
</div>
<div class="flex flex-col md:flex-row mx-8 mt-[-0.25rem] justify-center min-h-[40vh]">
<div class="grow p-8 border-transparent md:border-base-100" style="border-top-width: 0.25rem">
<div class="flex items-center sticky top-[40vh] text-5xl relative">
<h2>Support</h2>
<div class="circle bg-primary h-5 w-5 rounded-full absolute left-[-2.5rem] md:left-auto md:right-[-2.75rem]"></div>
</div>
</div>
<div class="grow flex flex-col justify-center gap-4 p-8 border-primary" style="border-bottom-width: 0.25rem; border-left-width: 0.25rem;">
<p class="text-xl">Join us for an exciting journey. As peer, sponsor, or member of the association you will be part of the development of the DD-IX - the catalyst for the digital future in Saxony!</p>
<A href="" class="btn btn-outline w-fit">Support Us</A>
</div>
</div>
<h2 class="mt-40 mb-16 text-5xl">News</h2>
<NewsList limit={3} />
<A href="/news" class="btn btn-primary mt-4">View More</A>
</section>
</main>

@ -0,0 +1,48 @@
<section class="container mx-auto p-4">
<h1 class="mb-12 mt-40">Network</h1>
Currently there are 3 participants. Have a look at the list below for more information.
<div class="overflow-x-auto">
<table class="table">
<thead>
<tr>
<th></th>
<th>Member</th>
<th>Name</th>
<th>ASN</th>
<th>Connections</th>
<th>RSv4</th>
<th>RSv6</th>
</tr>
</thead>
<tbody>
<tr>
<th>1</th>
<td>no</td>
<td>AS112 Reverse DNS</td>
<td>112</td>
<td>1Gbit</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<th>2</th>
<td>yes</td>
<td>hair of Distributed and Networked Systems at TUD</td>
</tr>
<tr>
<th>3</th>
<td>yes</td>
<td>IBH IT-Service GmbH</td>
<td>15372</td>
<td>10Gbit</td>
<td>yes</td>
<td>yes</td>
</tr>
</tbody>
</table>
</div>
</section>

@ -0,0 +1,45 @@
import { createSignal, For, Show } from "solid-js";
import {
cache,
createAsync,
A,
type RouteDefinition,
useParams,
} from "@solidjs/router";
const getPost = cache(async (slug) => {
"use server";
return await fetch(`https://content.dd-ix.net/news/en/${slug}`).then((data) =>
data.json()
);
}, "news-post");
export const route = {
load: ({ params }) => {
getPost(params.slug);
},
} satisfies RouteDefinition;
export default () => {
const params = useParams();
const post = createAsync(() => getPost(params.slug));
return (
<main>
<div class="relative">
<img
src={`https://content.dd-ix.net/news/assets/${post()?.image}`}
alt={post()?.title}
class="min-h-[30vh] max-h-[70vh] w-full object-cover"
/>
{/* <h1 class="absolute bottom-0 left-0 p-4 backdrop-blur text-white drop-shadow-md bg-gray-800/40">{post()?.title}</h1> */}
</div>
<section class="container mx-auto p-4">
<h1 class="my-12">{post()?.title}</h1>
<p>{post()?.published}</p>
<p>{post()?.authors.join(", ")}</p>
<div innerHTML={post()?.body} />
</section>
</main>
);
};

@ -0,0 +1,59 @@
import { createSignal, For, Show } from "solid-js";
import { cache, createAsync, A, type RouteDefinition } from "@solidjs/router";
const getNewsList = cache(async () => {
"use server";
return await fetch("https://content.dd-ix.net/news/en").then((data) =>
data.json()
);
}, "news-list");
const getNewsTags = cache(async () => {
"use server";
return await fetch("https://content.dd-ix.net/news/keywords").then((data) =>
data.json()
);
}, "news-tags");
export const route = {
load: () => {
getNewsList();
getNewsTags();
},
} satisfies RouteDefinition;
export default () => {
const newsList = createAsync(() => getNewsList());
const tags = createAsync(() => getNewsTags());
return (
<main class="container mx-auto p-4">
<h1 class="mb-12 mt-40">News</h1>
<div class="flex flex-wrap gap-2">
<For each={tags()}>
{(tag) => (
<button class="btn btn-sm">{tag}</button>
)}
</For>
</div>
<For each={newsList()}>
{(post) => (
<A href={`/news/${post.slug}`}>
<figure class="card md:card-side bg-base-100 shadow-xl mt-4">
<img
src={`https://content.dd-ix.net/news/assets/${post.image}`}
alt={post.title}
class="md:w-48 object-cover"
/>
<div class="card-body">
<h2 class="card-title">{post.title}</h2>
<p>{post.published}</p>
<p>{post.description}</p>
</div>
</figure>
</A>
)}
</For>
</main>
);
};

@ -0,0 +1,18 @@
<section class="container mx-auto p-4">
<h1 class="mb-12 mt-40">Peering</h1>
## What is peering?
Peering is a term from network technology. It enables ISPs (Internet Service Providers) or network operators to easily exchange data with each other. This data transfer between peering partners is free of charge and offers numerous advantages.
## Why should I peer?
The aim of peering is to route traffic between the participating networks more efficiently and to avoid bottlenecks. Through peering connections provided by DD-IX, we enable all participants to route network packets among each other shorter and faster.
Optimal network packet forwarding is an important aspect of building a robust and efficient Internet. Peering with an IXP allows access to content and services provided by other network operators or ISPs without the need to establish many direct peerings among each other.
---
An IXP also enables better resilience, as traffic can be transmitted even if a link to a particular network fails, as long as there are routes through alternative peering partners.
Peering through an IXP like the DD-IX reduces the need for expensive Internet transit services. Because only the connection are paid for and not the data volume used.
</section>

@ -0,0 +1,146 @@
import { createSignal, For, Show } from "solid-js";
import { cache, createAsync, A, type RouteDefinition } from "@solidjs/router";
import { clientOnly } from "@solidjs/start";
const TrafficChart = clientOnly(() => import("~/components/TrafficChart"));
const DNSChart = clientOnly(() => import("~/components/DNSChart"));
const getTraffic = cache(async () => {
"use server";
return await fetch("https://content.dd-ix.net/stats/traffic").then((data) =>
data.json()
);
}, "stats-traffic");
const getQueries = cache(async () => {
"use server";
return await fetch("https://content.dd-ix.net/stats/as112").then((data) =>
data.json()
);
}, "stats-queries");
export const route = {
load: () => {
getTraffic();
getQueries();
},
} satisfies RouteDefinition;
export default () => {
const traffic = createAsync(() => getTraffic());
const queries = createAsync(() => getQueries());
return (
<section class="container mx-auto p-4">
<h1 class="mb-12 mt-40">Statistics</h1>
<h2>Traffic</h2>
<div role="tablist" class="tabs tabs-lifted">
<input
type="radio"
name="my_tabs_2"
role="tab"
class="tab"
aria-label="Two&nbsp;days"
checked
/>
<div
role="tabpanel"
class="tab-content bg-base-100 border-base-300 rounded-box p-6"
>
<TrafficChart
data={traffic()?.two_days}
fallback={<div>Loading</div>}
/>
</div>
<input
type="radio"
name="my_tabs_2"
role="tab"
class="tab"
aria-label="Week"
/>
<div
role="tabpanel"
class="tab-content bg-base-100 border-base-300 rounded-box p-6"
>
<TrafficChart
data={traffic()?.seven_days}
fallback={<div>Loading</div>}
/>
</div>
<input
type="radio"
name="my_tabs_2"
role="tab"
class="tab"
aria-label="Month"
/>
<div
role="tabpanel"
class="tab-content bg-base-100 border-base-300 rounded-box p-6"
>
<TrafficChart
data={traffic()?.month}
fallback={<div>Loading</div>}
/>
</div>
</div>
<h2>DNS Queries</h2>
<div role="tablist" class="tabs tabs-lifted">
<input
type="radio"
name="my_tabs_3"
role="tab"
class="tab"
aria-label="Two&nbsp;days"
checked
/>
<div
role="tabpanel"
class="tab-content bg-base-100 border-base-300 rounded-box p-6"
>
<DNSChart
data={queries()?.two_days}
fallback={<div>Loading</div>}
/>
</div>
<input
type="radio"
name="my_tabs_3"
role="tab"
class="tab"
aria-label="Week"
/>
<div
role="tabpanel"
class="tab-content bg-base-100 border-base-300 rounded-box p-6"
>
<DNSChart
data={queries()?.seven_days}
fallback={<div>Loading</div>}
/>
</div>
<input
type="radio"
name="my_tabs_3"
role="tab"
class="tab"
aria-label="Month"
/>
<div
role="tabpanel"
class="tab-content bg-base-100 border-base-300 rounded-box p-6"
>
<DNSChart
data={queries()?.month}
fallback={<div>Loading</div>}
/>
</div>
</div>
</section>
);
};

@ -0,0 +1,33 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{html,js,jsx,ts,tsx,mdx,md}"],
plugins: [require("daisyui")],
theme: {
fontFamily: {
sans: ["Ubuntu", "sans-serif"],
},
},
daisyui: {
themes: [
{
light: {
...require("daisyui/src/theming/themes")["corporate"],
primary: "#209680",
"primary-focus": "#6ce0ca",
secondary: "#ccff00",
"secondary-focus": "#88b100",
},
},
{
dark: {
...require("daisyui/src/theming/themes")["business"],
primary: "#209680",
"primary-focus": "#6ce0ca",
secondary: "#ccff00",
"secondary-focus": "#88b100",
},
},
],
darkTheme: "dark",
},
};

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"allowJs": true,
"noEmit": true,
"strict": true,
"types": ["vinxi/types/client"],
"isolatedModules": true,
"paths": {
"~/*": ["./src/*"]
}
}
}
Loading…
Cancel
Save