initial commit

This commit is contained in:
2024-05-11 12:42:46 +02:00
commit cdbd1801fd
28 changed files with 8444 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
node_modules
.vite
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/plugins
!.yarn/releases
!.yarn/sdks

BIN
.yarn/install-state.gz Normal file

Binary file not shown.

894
.yarn/releases/yarn-4.2.2.cjs vendored Executable file

File diff suppressed because one or more lines are too long

3
.yarnrc.yml Normal file
View File

@@ -0,0 +1,3 @@
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.2.2.cjs

29
README.md Normal file
View File

@@ -0,0 +1,29 @@
This app has been created with [Bati](https://batijs.dev) using the following flags: `--react`
# About this app
This app is ready to start. It's powered by [Vike](https://vike.dev) and [React](https://react.dev/learn).
### `/pages/+config.ts`
Such files are [the interface](https://vike.dev/config) between Vike and your code. It defines:
- A default [`<Layout>` component](https://vike.dev/Layout) (that wraps your [`<Page>` components](https://vike.dev/Page)).
- A default [`title`](https://vike.dev/head).
- Default [`<head>` tags](https://vike.dev/head).
### Routing
[Vike's built-in router](https://vike.dev/routing) lets you choose between:
- [Filesystem Routing](https://vike.dev/filesystem-routing) (the URL of a page is determined based on where its `+Page.jsx` file is located on the filesystem)
- [Route Strings](https://vike.dev/route-string)
- [Route Functions](https://vike.dev/route-function)
### `/pages/_error/+Page.jsx`
The [error page](https://vike.dev/error-page) which is rendered when errors occur.
### `/pages/+onPageTransitionStart.ts` and `/pages/+onPageTransitionEnd.ts`
The [`onPageTransitionStart()` hook](https://vike.dev/onPageTransitionStart), together with [`onPageTransitionEnd()`](https://vike.dev/onPageTransitionEnd), enables you to implement page transition animations.
### SSR
SSR is enabled by default. You can [disable it](https://vike.dev/ssr) for all your pages or only for some pages.
### HTML Streaming
You can enable/disable [HTML streaming](https://vike.dev/streaming) for all your pages, or only for some pages while still using it for others.

36
assets/logo.svg Normal file
View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="175" height="175" fill="none" version="1.1" viewBox="0 0 175 175" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<defs>
<linearGradient id="linearGradient880" x1="108.64" x2="115.51" y1="88.726" y2="136.2" gradientTransform="matrix(1.0498 0 0 1.0498 -2.9171 -2.9658)" gradientUnits="userSpaceOnUse">
<stop stop-color="#ffea83" offset="0"/>
<stop stop-color="#FFDD35" offset=".083333"/>
<stop stop-color="#FFA800" offset="1"/>
</linearGradient>
<linearGradient id="paint2_linear" x1="48.975" x2="61.299" y1="3.9232" y2="158.04" gradientTransform="translate(-2.832e-5)" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFEA83" offset="0"/>
<stop stop-color="#FFDD35" offset=".083333"/>
<stop stop-color="#FFA800" offset="1"/>
</linearGradient>
<linearGradient id="paint0_linear-6" x1="-1.4492" x2="116.62" y1="-5.8123" y2="137.08" gradientTransform="translate(-2.832e-5)" gradientUnits="userSpaceOnUse">
<stop stop-color="#41D1FF" offset="0"/>
<stop stop-color="#BD34FE" offset="1"/>
</linearGradient>
</defs>
<circle cx="87.5" cy="87.5" r="87.5" fill="#c4c4c4"/>
<circle cx="87.5" cy="87.5" r="87.5" fill="url(#paint0_linear-6)"/>
<g transform="translate(632.92 54.355)" fill="#d38787" stroke-width="1.0614">
<path d="m-549.75 68.457c-5.7533-3.1217-6.1166-5.2295-6.1166-35.489 0-30.458 0.35464-32.448 6.3339-35.54 3.9943-2.0655 24.279-2.2805 26.735-0.28333 0.89718 0.72974 6.7203 6.6637 12.94 13.187l11.309 11.86v19.575c0 18.473-0.12956 19.74-2.3011 22.5-4.0223 5.1136-7.558 5.8565-27.65 5.8099-14.15-0.03287-19.008-0.40294-21.25-1.6191zm42.473-6.3594c2.27-1.59 2.359-2.2909 2.359-18.575v-16.923h-6.9521c-12.443 0-16.4-4.0845-16.4-16.93v-7.4828h-8.9464c-6.7178 0-9.3619 0.41549-10.614 1.668-2.5031 2.5031-2.5031 55.724 0 58.228 2.4502 2.4502 37.058 2.4636 40.553 0.01609zm-1.8867-42.165c0-0.16422-2.8659-3.1346-6.3686-6.6008l-6.3686-6.3022v4.9328c0 6.3185 1.8955 8.2687 8.0366 8.2687 2.5854 0 4.7007-0.13434 4.7007-0.29859zm-57.57 44.279c-5.6185-3.0486-6.1166-5.593-6.1166-31.243 0-18.891 0.31331-24.063 1.6101-26.571 1.809-3.4981 6.5048-6.3339 10.489-6.3339 2.4847 0 2.5814 0.19984 1.541 3.1843-0.61054 1.7514-1.7457 3.1843-2.5226 3.1843-0.77686 0-2.1631 0.75059-3.0805 1.668-2.4923 2.4923-2.4923 47.244 0 49.736 0.91739 0.9174 2.3036 1.668 3.0805 1.668 0.77688 0 1.912 1.4329 2.5226 3.1843 1.0562 3.0298 0.97108 3.1822-1.7537 3.1418-1.575-0.02331-4.1713-0.75194-5.7694-1.6191zm-16.983-4.2458c-5.4392-2.9512-6.1166-5.9415-6.1166-26.997 0-15.096 0.345-19.878 1.6101-22.325 1.7476-3.3796 6.4758-6.3339 10.137-6.3339 1.8666 0 2.1789 0.44955 1.6594 2.3882-0.35184 1.3135-0.64655 2.7465-0.65453 3.1843-8e-3 0.43784-0.69682 0.79608-1.5308 0.79608-0.83399 0-2.2669 0.75059-3.1843 1.668-2.4767 2.4767-2.4767 38.768 0 41.244 0.91741 0.91739 2.2946 1.668 3.0605 1.668 1.196 0 2.6402 2.995 2.6871 5.5726 0.0241 1.3294-4.5804 0.80962-7.6676-0.8655z" style="mix-blend-mode:lighten"/>
<path d="m-552.2 68.911c-5.7533-3.1217-6.1166-5.2295-6.1166-35.489 0-30.458 0.35463-32.448 6.3339-35.54 3.9943-2.0655 24.279-2.2805 26.735-0.28333 0.89718 0.72974 6.7203 6.6637 12.94 13.187l11.309 11.86v19.575c0 18.473-0.12957 19.74-2.3011 22.5-4.0223 5.1136-7.558 5.8565-27.65 5.8099-14.15-0.03287-19.008-0.40294-21.25-1.6191zm42.473-6.3594c2.27-1.59 2.359-2.2909 2.359-18.575v-16.923h-6.952c-12.443 0-16.4-4.0845-16.4-16.93v-7.4828h-8.9464c-6.7179 0-9.3619 0.41549-10.614 1.668-2.5031 2.5031-2.5031 55.724 0 58.228 2.4502 2.4502 37.058 2.4636 40.553 0.01609zm-1.8867-42.165c0-0.16422-2.8659-3.1346-6.3686-6.6008l-6.3686-6.3022v4.9328c0 6.3185 1.8955 8.2688 8.0366 8.2688 2.5854 0 4.7007-0.13434 4.7007-0.29859zm-57.57 44.279c-5.6185-3.0486-6.1166-5.593-6.1166-31.243 0-18.891 0.31331-24.063 1.6101-26.571 1.809-3.4981 6.5048-6.3339 10.489-6.3339 2.4847 0 2.5814 0.19984 1.541 3.1843-0.61054 1.7514-1.7457 3.1843-2.5226 3.1843-0.77687 0-2.1631 0.75059-3.0805 1.668-2.4923 2.4923-2.4923 47.244 0 49.736 0.91741 0.91739 2.3036 1.668 3.0805 1.668 0.77686 0 1.912 1.4329 2.5226 3.1843 1.0562 3.0298 0.97107 3.1822-1.7537 3.1418-1.575-0.02331-4.1713-0.75194-5.7694-1.6191zm-16.983-4.2458c-5.4392-2.9512-6.1166-5.9415-6.1166-26.997 0-15.096 0.34502-19.878 1.6101-22.325 1.7476-3.3796 6.4758-6.3339 10.137-6.3339 1.8666 0 2.1789 0.44955 1.6594 2.3882-0.35182 1.3135-0.64653 2.7465-0.65452 3.1843-8e-3 0.43784-0.69683 0.79608-1.5308 0.79608-0.83397 0-2.2669 0.75059-3.1843 1.668-2.4767 2.4767-2.4767 38.768 0 41.245 0.9174 0.91739 2.2946 1.668 3.0605 1.668 1.196 0 2.6402 2.995 2.6871 5.5726 0.0241 1.3294-4.5804 0.80962-7.6676-0.8655z" fill-opacity=".47466" style="mix-blend-mode:lighten"/>
</g>
<path d="m128.48 88.913-24.027 4.6784c-0.39475 0.07685-0.68766 0.40944-0.71076 0.80849l-1.4782 24.805c-0.0347 0.58371 0.50497 1.0372 1.0792 0.90602l6.6886-1.5338c0.62676-0.14383 1.1916 0.40419 1.0635 1.0299l-1.9874 9.6702c-0.13438 0.65091 0.48084 1.2073 1.1202 1.0142l4.1322-1.2472c0.64041-0.19317 1.2556 0.36535 1.1202 1.0162l-3.158 15.191c-0.19842 0.95011 1.074 1.4677 1.6042 0.653l0.35485-0.54382 19.578-38.827c0.32755-0.64985-0.23727-1.391-0.95641-1.2535l-6.8849 1.3207c-0.6467 0.12389-1.1979-0.47453-1.0152-1.1034l4.4944-15.482c0.18266-0.63012-0.36955-1.2295-1.0173-1.1034z" fill="url(#linearGradient880)" stroke-width="1.0498"/>
<rect x="3" y="3" width="169" height="169" rx="84.5" stroke="url(#paint2_linear)" stroke-width="6" style="mix-blend-mode:soft-light"/>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

13
components/Link.tsx Normal file
View File

@@ -0,0 +1,13 @@
import React from "react";
import { usePageContext } from "vike-react/usePageContext";
export function Link({ href, children }: { href: string; children: string }) {
const pageContext = usePageContext();
const { urlPathname } = pageContext;
const isActive = href === "/" ? urlPathname === href : urlPathname.startsWith(href);
return (
<a href={href} className={isActive ? "is-active" : undefined}>
{children}
</a>
);
}

14
layouts/HeadDefault.tsx Normal file
View File

@@ -0,0 +1,14 @@
import React from "react";
import logoUrl from "../assets/logo.svg";
// Default <head> (can be overridden by pages)
export default function HeadDefault() {
return (
<>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Demo showcasing Vike" />
<link rel="icon" href={logoUrl} />
</>
);
}

79
layouts/LayoutDefault.tsx Normal file
View File

@@ -0,0 +1,79 @@
import "./style.css";
import React from "react";
import logoUrl from "../assets/logo.svg";
import { Link } from "../components/Link.js";
export default function LayoutDefault({
children,
}: {
children: React.ReactNode;
}) {
return (
<div
style={{
display: "flex",
maxWidth: 900,
margin: "auto",
}}
>
<Sidebar>
<Logo />
<Link href="/">Welcome</Link>
<Link href="/star-wars">Data Fetching</Link>
</Sidebar>
<Content>{children}</Content>
</div>
);
}
function Sidebar({ children }: { children: React.ReactNode }) {
return (
<div
id="sidebar"
style={{
padding: 20,
flexShrink: 0,
display: "flex",
flexDirection: "column",
lineHeight: "1.8em",
borderRight: "2px solid #eee",
}}
>
{children}
</div>
);
}
function Content({ children }: { children: React.ReactNode }) {
return (
<div id="page-container">
<div
id="page-content"
style={{
padding: 20,
paddingBottom: 50,
minHeight: "100vh",
}}
>
{children}
</div>
</div>
);
}
function Logo() {
return (
<div
style={{
marginTop: 20,
marginBottom: 10,
}}
>
<a href="/">
<img src={logoUrl} height={64} width={64} alt="logo" />
</a>
</div>
);
}

29
layouts/style.css Normal file
View File

@@ -0,0 +1,29 @@
/* Links */
a {
text-decoration: none;
}
#sidebar a {
padding: 2px 10px;
margin-left: -10px;
}
#sidebar a.is-active {
background-color: #eee;
}
/* Reset */
body {
margin: 0;
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
/* Page Transition Animation */
#page-content {
opacity: 1;
transition: opacity 0.3s ease-in-out;
}
body.page-is-transitioning #page-content {
opacity: 0;
}

31
package.json Normal file
View File

@@ -0,0 +1,31 @@
{
"name": "my-app",
"version": "0.0.1",
"description": "",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"keywords": [],
"author": "",
"devDependencies": {
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"react-native": "^0.74.1",
"typescript": "^5.4.5",
"vite": "^5.2.11",
"vite-plugin-react-native-web": "^1.0.2"
},
"dependencies": {
"@vitejs/plugin-react": "^4.2.1",
"cross-fetch": "^4.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-native-web": "^0.19.11",
"vike": "^0.4.171",
"vike-react": "^0.4.8"
},
"packageManager": "yarn@4.2.2"
}

13
pages/+config.ts Normal file
View File

@@ -0,0 +1,13 @@
import vikeReact from "vike-react/config";
import type { Config } from "vike/types";
import Head from "../layouts/HeadDefault.js";
import Layout from "../layouts/LayoutDefault.js";
// Default config (can be overridden by pages)
export default {
Layout,
Head,
// <title>
title: "My Vike App",
extends: vikeReact,
} satisfies Config;

View File

@@ -0,0 +1,6 @@
import type { OnPageTransitionEndAsync } from "vike/types";
export const onPageTransitionEnd: OnPageTransitionEndAsync = async () => {
console.log("Page transition end");
document.querySelector("body")!.classList.remove("page-is-transitioning");
};

View File

@@ -0,0 +1,6 @@
import type { OnPageTransitionStartAsync } from "vike/types";
export const onPageTransitionStart: OnPageTransitionStartAsync = async () => {
console.log("Page transition start");
document.querySelector("body")!.classList.add("page-is-transitioning");
};

21
pages/_error/+Page.tsx Normal file
View File

@@ -0,0 +1,21 @@
import React from "react";
import { usePageContext } from "vike-react/usePageContext";
export default function Page() {
const { is404 } = usePageContext();
if (is404) {
return (
<>
<h1>404 Page Not Found</h1>
<p>This page could not be found.</p>
</>
);
} else {
return (
<>
<h1>500 Internal Server Error</h1>
<p>Something went wrong.</p>
</>
);
}
}

20
pages/index/+Page.tsx Normal file
View File

@@ -0,0 +1,20 @@
import React from "react";
import { Counter } from "./Counter.js";
import { Text } from "react-native";
export default function Page() {
return (
<>
<h1>My Vike app</h1>
This page is:
<ul>
<li>
<Text>Rendered to HTML.</Text>
</li>
<li>
Interactive. <Counter />
</li>
</ul>
</>
);
}

11
pages/index/Counter.tsx Normal file
View File

@@ -0,0 +1,11 @@
import React, { useState } from "react";
export function Counter() {
const [count, setCount] = useState(0);
return (
<button type="button" onClick={() => setCount((count) => count + 1)}>
Counter {count}
</button>
);
}

View File

@@ -0,0 +1,17 @@
import React from "react";
import { useData } from "vike-react/useData";
import type { Data } from "./+data.js";
export default function Page() {
const movie = useData<Data>();
return (
<>
<h1>{movie.title}</h1>
Release Date: {movie.release_date}
<br />
Director: {movie.director}
<br />
Producer: {movie.producer}
</>
);
}

View File

@@ -0,0 +1,22 @@
// https://vike.dev/data
import fetch from "cross-fetch";
import type { PageContextServer } from "vike/types";
import type { MovieDetails } from "../types.js";
export type Data = Awaited<ReturnType<typeof data>>;
export const data = async (pageContext: PageContextServer) => {
const response = await fetch(`https://brillout.github.io/star-wars/api/films/${pageContext.routeParams.id}.json`);
let movie = (await response.json()) as MovieDetails;
// We remove data we don't need because the data is passed to
// the client; we should minimize what is sent over the network.
movie = minimize(movie);
return movie;
};
function minimize(movie: MovieDetails): MovieDetails {
const { id, title, release_date, director, producer } = movie;
movie = { id, title, release_date, director, producer };
return movie;
}

View File

@@ -0,0 +1,7 @@
import type { PageContext } from "vike/types";
import type { Data } from "./+data.js";
export function title(pageContext: PageContext<Data>) {
const movie = pageContext.data;
return movie.title;
}

View File

@@ -0,0 +1,22 @@
import React from "react";
import { useData } from "vike-react/useData";
import type { Data } from "./+data.js";
export default function Page() {
const movies = useData<Data>();
return (
<>
<h1>Star Wars Movies</h1>
<ol>
{movies.map(({ id, title, release_date }) => (
<li key={id}>
<a href={`/star-wars/${id}`}>{title}</a> ({release_date})
</li>
))}
</ol>
<p>
Source: <a href="https://brillout.github.io/star-wars">brillout.github.io/star-wars</a>.
</p>
</>
);
}

View File

@@ -0,0 +1,22 @@
// https://vike.dev/data
import fetch from "cross-fetch";
import type { Movie, MovieDetails } from "../types.js";
export type Data = Awaited<ReturnType<typeof data>>;
export const data = async () => {
const response = await fetch("https://brillout.github.io/star-wars/api/films.json");
const moviesData = (await response.json()) as MovieDetails[];
// We remove data we don't need because the data is passed to the client; we should
// minimize what is sent over the network.
const movies = minimize(moviesData);
return movies;
};
function minimize(movies: MovieDetails[]): Movie[] {
return movies.map((movie) => {
const { title, release_date, id } = movie;
return { title, release_date, id };
});
}

View File

@@ -0,0 +1,7 @@
import type { PageContext } from "vike/types";
import type { Data } from "./+data.js";
export function title(pageContext: PageContext<Data>) {
const movies = pageContext.data;
return `${movies.length} Star Wars Movies`;
}

10
pages/star-wars/types.ts Normal file
View File

@@ -0,0 +1,10 @@
export type Movie = {
id: string;
title: string;
release_date: string;
};
export type MovieDetails = Movie & {
director: string;
producer: string;
};

42
shell.nix Normal file
View File

@@ -0,0 +1,42 @@
{pkgs ? import <nixpkgs> {}}: let
python = pkgs.python312.withPackages (ps:
with ps; [
guessit
aiohttp
jsons
watchfiles
pika
aio-pika
requests
dataclasses-json
msgspec
]);
dotnet = with pkgs.dotnetCorePackages;
combinePackages [
sdk_8_0
aspnetcore_8_0
aspnetcore_6_0
];
in
pkgs.mkShell {
packages = with pkgs; [
nodejs-18_x
nodePackages.yarn
nodePackages.eas-cli
nodePackages.expo-cli
dotnet
csharpier
python
ruff
go
wgo
mediainfo
libmediainfo
ffmpeg-full
postgresql_15
pgformatter
biome
];
DOTNET_ROOT = "${dotnet}";
}

30
tsconfig.json Normal file
View File

@@ -0,0 +1,30 @@
{
"compilerOptions": {
"strict": true,
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"module": "ESNext",
"noEmit": true,
"moduleResolution": "Bundler",
"target": "ES2022",
"lib": [
"DOM",
"DOM.Iterable",
"ESNext"
],
"types": [
"vite/client",
"vike-react"
],
"jsx": "preserve",
"jsxImportSource": "react"
},
"exclude": [
"dist"
]
}

8
vite.config.ts Normal file
View File

@@ -0,0 +1,8 @@
import ssr from "vike/plugin";
import react from "@vitejs/plugin-react";
import reactNativeWeb from "vite-plugin-react-native-web";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [react({}), ssr({}), reactNativeWeb()],
});

7042
yarn.lock Normal file

File diff suppressed because it is too large Load Diff