mirror of
https://github.com/fallout2-ce/fallout2-ce.github.io.git
synced 2026-07-27 16:47:19 -07:00
Merge pull request #7 from fallout2-ce/feat/main
This commit is contained in:
@@ -5,6 +5,12 @@
|
||||
<link rel="icon" type="image/x-icon" href="./fallout2-ce.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Fallout 2 Community Edition</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Exo+2:ital,wght@0,100..900;1,100..900&family=Orbitron:wght@400..900&display=swap"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
<body class="dark">
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||
"@radix-ui/react-slot": "^1.2.3",
|
||||
"@tailwindcss/vite": "^4.1.12",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
|
||||
Generated
+38
@@ -11,6 +11,9 @@ importers:
|
||||
'@radix-ui/react-dropdown-menu':
|
||||
specifier: ^2.1.16
|
||||
version: 2.1.16(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-scroll-area':
|
||||
specifier: ^1.2.10
|
||||
version: 1.2.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-slot':
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.3(@types/react@19.1.12)(react@19.1.1)
|
||||
@@ -434,6 +437,9 @@ packages:
|
||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||
engines: {node: '>= 8'}
|
||||
|
||||
'@radix-ui/number@1.1.1':
|
||||
resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==}
|
||||
|
||||
'@radix-ui/primitive@1.1.3':
|
||||
resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==}
|
||||
|
||||
@@ -625,6 +631,19 @@ packages:
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-scroll-area@1.2.10':
|
||||
resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-slot@1.2.3':
|
||||
resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==}
|
||||
peerDependencies:
|
||||
@@ -2070,6 +2089,8 @@ snapshots:
|
||||
'@nodelib/fs.scandir': 2.1.5
|
||||
fastq: 1.19.1
|
||||
|
||||
'@radix-ui/number@1.1.1': {}
|
||||
|
||||
'@radix-ui/primitive@1.1.3': {}
|
||||
|
||||
'@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
@@ -2253,6 +2274,23 @@ snapshots:
|
||||
'@types/react': 19.1.12
|
||||
'@types/react-dom': 19.1.9(@types/react@19.1.12)
|
||||
|
||||
'@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/number': 1.1.1
|
||||
'@radix-ui/primitive': 1.1.3
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1)
|
||||
'@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.1)
|
||||
'@radix-ui/react-direction': 1.1.1(@types/react@19.1.12)(react@19.1.1)
|
||||
'@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)
|
||||
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.1)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.1)
|
||||
react: 19.1.1
|
||||
react-dom: 19.1.1(react@19.1.1)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.1.12
|
||||
'@types/react-dom': 19.1.9(@types/react@19.1.12)
|
||||
|
||||
'@radix-ui/react-slot@1.2.3(@types/react@19.1.12)(react@19.1.1)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1)
|
||||
|
||||
+39
-2
@@ -1,7 +1,44 @@
|
||||
import useLang from "@/lib/hooks/useLang";
|
||||
import { translations } from "@/locale";
|
||||
import Introduction from "@/components/Introduction";
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
||||
function App() {
|
||||
const { currLang } = useLang();
|
||||
return (
|
||||
<div className="w-full max-w-4xl p-4 lg:my-8">
|
||||
<h1>Title</h1>
|
||||
<div className="w-full max-w-4xl p-4 lg:my-8 gap-8 flex flex-col">
|
||||
<h1 className="text-primary text-5xl lg:text-6xl font-extrabold italic max-w-2/3 orbitron tracking-tighter">
|
||||
{translations[currLang].title}
|
||||
</h1>
|
||||
<p className="text-2xl font-bold italic">
|
||||
{translations[currLang].subtitle}
|
||||
</p>
|
||||
<Introduction />
|
||||
<div className="flex w-full lg:w-1/2 gap-6">
|
||||
<a
|
||||
className="w-full flex-1"
|
||||
href="https://fallout2-ce.github.io/fallout2-ce"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Button
|
||||
className="w-full rounded-full text-lg py-4 h-14 lg:py-6 px-6"
|
||||
variant="outline"
|
||||
>
|
||||
{translations[currLang].webDemo}
|
||||
</Button>
|
||||
</a>
|
||||
<a
|
||||
className="w-full flex-1"
|
||||
href="https://github.com/fallout2-ce/fallout2-ce/releases"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Button className="w-full rounded-full text-lg py-4 h-14 lg:py-6 px-8">
|
||||
{translations[currLang].download}
|
||||
</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import useLang from "@/lib/hooks/useLang";
|
||||
import translations from "@/locale";
|
||||
import { translations } from "@/locale";
|
||||
import { SiDiscord, SiTelegram } from "react-icons/si";
|
||||
|
||||
// TODO: plz update the links
|
||||
@@ -8,7 +8,7 @@ const Footer = () => {
|
||||
const { currLang } = useLang();
|
||||
return (
|
||||
<footer className="w-full h-16 lg:h-12 shrink-0 flex items-center justify-center bg-background/10 sticky bottom-0 z-20 backdrop-blur-xs border-t-background">
|
||||
<div className="w-full max-w-4xl justify-between p-4 items-center flex flex-col lg:flex-row gap-2 my-2 text-sm">
|
||||
<div className="w-full max-w-4xl justify-between p-4 items-center flex flex-col lg:flex-row gap-2 my-2 text-sm text-muted-foreground">
|
||||
<div className="flex gap-6">
|
||||
<a
|
||||
href="https://discord.gg/"
|
||||
|
||||
@@ -3,7 +3,7 @@ import LangToggle from "@/components/LangToggle";
|
||||
|
||||
const Header = () => (
|
||||
<header className="w-full h-16 shrink-0 flex items-center justify-center bg-background/20 sticky top-0 z-20 backdrop-blur-xs border-b-background">
|
||||
<div className="w-full max-w-4xl flex justify-between p-4 items-center">
|
||||
<div className="w-full max-w-4xl flex justify-between p-4 items-center text-muted-foreground">
|
||||
<Link to="/">
|
||||
<img
|
||||
src="/logo.png"
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import useLang from "@/lib/hooks/useLang";
|
||||
import { transIntro, translations } from "@/locale";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
|
||||
const Introduction = () => {
|
||||
const { currLang } = useLang();
|
||||
return (
|
||||
<div>
|
||||
<h3 className="font-semibold orbitron">
|
||||
{translations[currLang].features}:
|
||||
</h3>
|
||||
<ScrollArea className="mt-2 relative">
|
||||
<div className="ml-2">
|
||||
<ul className="flex flex-col gap-2 text-base text-muted-foreground list-disc w-full p-4 max-h-[5.5rem] lg:max-h-[8rem]">
|
||||
{transIntro[currLang].map((item) => (
|
||||
<li key={item}>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Introduction;
|
||||
@@ -32,7 +32,7 @@ const LangToggle = () => {
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost">
|
||||
<Globe className="h-6 w-6" />
|
||||
<Globe />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import * as React from "react";
|
||||
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
function ScrollArea({
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
||||
return (
|
||||
<ScrollAreaPrimitive.Root
|
||||
data-slot="scroll-area"
|
||||
className={cn("relative", className)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.Viewport
|
||||
data-slot="scroll-area-viewport"
|
||||
className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
|
||||
>
|
||||
{children}
|
||||
</ScrollAreaPrimitive.Viewport>
|
||||
<ScrollBar />
|
||||
<ScrollAreaPrimitive.Corner />
|
||||
</ScrollAreaPrimitive.Root>
|
||||
);
|
||||
}
|
||||
|
||||
function ScrollBar({
|
||||
className,
|
||||
orientation = "vertical",
|
||||
...props
|
||||
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
|
||||
return (
|
||||
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
||||
data-slot="scroll-area-scrollbar"
|
||||
orientation={orientation}
|
||||
className={cn(
|
||||
"flex touch-none p-px transition-colors select-none",
|
||||
orientation === "vertical" &&
|
||||
"h-full w-2.5 border-l border-l-transparent",
|
||||
orientation === "horizontal" &&
|
||||
"h-2.5 flex-col border-t border-t-transparent",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<ScrollAreaPrimitive.ScrollAreaThumb
|
||||
data-slot="scroll-area-thumb"
|
||||
className="bg-border relative flex-1 rounded-full"
|
||||
/>
|
||||
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
||||
);
|
||||
}
|
||||
|
||||
export { ScrollArea, ScrollBar };
|
||||
+15
-6
@@ -28,7 +28,7 @@
|
||||
--secondary: oklch(0.968 0.007 247.896);
|
||||
--secondary-foreground: oklch(0.208 0.042 265.755);
|
||||
--muted: oklch(0.968 0.007 247.896);
|
||||
--muted-foreground: oklch(0.554 0.046 257.417);
|
||||
--muted-foreground: oklch(87.2% 0.01 258.338);
|
||||
--accent: oklch(0.968 0.007 247.896);
|
||||
--accent-foreground: oklch(0.208 0.042 265.755);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
@@ -90,17 +90,17 @@
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.129 0.042 264.695);
|
||||
--foreground: oklch(0.984 0.003 247.858);
|
||||
--foreground: oklch(96.7% 0.001 286.375);
|
||||
--card: oklch(0.208 0.042 265.755);
|
||||
--card-foreground: oklch(0.984 0.003 247.858);
|
||||
--popover: oklch(0.208 0.042 265.755);
|
||||
--popover-foreground: oklch(0.984 0.003 247.858);
|
||||
--primary: oklch(0.929 0.013 255.508);
|
||||
--primary: oklch(85.2% 0.199 91.936);
|
||||
--primary-foreground: oklch(0.208 0.042 265.755);
|
||||
--secondary: oklch(0.279 0.041 260.031);
|
||||
--secondary-foreground: oklch(0.984 0.003 247.858);
|
||||
--muted: oklch(0.279 0.041 260.031);
|
||||
--muted-foreground: oklch(0.704 0.04 256.788);
|
||||
--muted-foreground: oklch(70.8% 0 0);
|
||||
--accent: oklch(0.279 0.041 260.031);
|
||||
--accent-foreground: oklch(0.984 0.003 247.858);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
@@ -122,8 +122,17 @@
|
||||
--sidebar-ring: oklch(0.551 0.027 264.364);
|
||||
}
|
||||
|
||||
@layer utilities {
|
||||
.exo-2 {
|
||||
font-family: "Exo 2", sans-serif;
|
||||
}
|
||||
.orbitron {
|
||||
font-family: "Orbitron", sans-serif;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply m-0 p-0 text-foreground;
|
||||
html body {
|
||||
@apply m-0 p-0 text-foreground exo-2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,12 @@ import { useEffect, useMemo } from "react";
|
||||
|
||||
const getLangFromSys = (): Lang => {
|
||||
const navLang = navigator.language;
|
||||
const langs = SupportedLangs.filter((l) => l != "sys");
|
||||
const langs = SupportedLangs.filter((l) => l != "System");
|
||||
return langs.find((l) => navLang.startsWith(l)) || "en";
|
||||
};
|
||||
|
||||
const resolveLang = (lang: LangWithSys): Lang => {
|
||||
return lang === "sys" ? getLangFromSys() : lang;
|
||||
return lang === "System" ? getLangFromSys() : lang;
|
||||
};
|
||||
|
||||
const useLang = () => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { atomWithStorage } from "jotai/utils";
|
||||
|
||||
const SupportedLangs = ["sys", "en"] as const;
|
||||
const SupportedLangs = ["System", "en"] as const;
|
||||
type LangWithSys = (typeof SupportedLangs)[number];
|
||||
type Lang = Exclude<LangWithSys, "sys">;
|
||||
type Lang = Exclude<LangWithSys, "System">;
|
||||
|
||||
const langAtom = atomWithStorage<LangWithSys>("lang", "sys");
|
||||
const langAtom = atomWithStorage<LangWithSys>("lang", "System");
|
||||
|
||||
export default langAtom;
|
||||
|
||||
|
||||
+25
-2
@@ -1,13 +1,36 @@
|
||||
import type { Lang } from "@/lib/stores/langStore";
|
||||
|
||||
type TranslationKey = "developedBy" | "title";
|
||||
type TranslationKey =
|
||||
| "developedBy"
|
||||
| "title"
|
||||
| "subtitle"
|
||||
| "webDemo"
|
||||
| "download"
|
||||
| "features";
|
||||
|
||||
const translations: Record<Lang, Record<TranslationKey, string>> = {
|
||||
en: {
|
||||
developedBy: "Developed with ❤️ by",
|
||||
title: "Fallout 2 Community Edition",
|
||||
subtitle: "A fully working re-implementation",
|
||||
webDemo: "Try in browser",
|
||||
download: "Download",
|
||||
features: "Features",
|
||||
},
|
||||
};
|
||||
|
||||
export default translations;
|
||||
const transIntro: Record<Lang, string[]> = {
|
||||
en: [
|
||||
"High resolution support",
|
||||
"Increased pathfinding nodes 5x for more accurate pathfinding",
|
||||
"Ctrl-click to quickly move items when bartering, looting, or stealing",
|
||||
"Press 'a' to select all when choosing item quantity",
|
||||
"Press 'a' to Take All when looting",
|
||||
"When bartering, caps default to the right amount to balance the trade (if possible)",
|
||||
"Music continues playing between maps (requires config)",
|
||||
"Auto open doors (requires config)",
|
||||
],
|
||||
};
|
||||
|
||||
export { transIntro, translations };
|
||||
export type { TranslationKey };
|
||||
|
||||
Reference in New Issue
Block a user