Compare commits
3 Commits
0064ad3182
...
feature/qr
| Author | SHA1 | Date | |
|---|---|---|---|
|
4439d0996d
|
|||
|
32ab4104a7
|
|||
|
923c24a93e
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||||
146
src/app.css
146
src/app.css
@@ -3,98 +3,106 @@
|
|||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
:root {
|
:root {
|
||||||
--background: 0 0% 90%;
|
--background: 0 0% 90%;
|
||||||
--foreground: 222.2 84% 4.9%;
|
--foreground: 222.2 84% 4.9%;
|
||||||
|
|
||||||
--muted: 210 40% 96.1%;
|
--muted: 210 40% 96.1%;
|
||||||
--muted-foreground: 215.4 16.3% 46.9%;
|
--muted-foreground: 215.4 16.3% 46.9%;
|
||||||
|
|
||||||
--popover: 0 0% 90%;
|
--popover: 0 0% 90%;
|
||||||
--popover-foreground: 222.2 84% 4.9%;
|
--popover-foreground: 222.2 84% 4.9%;
|
||||||
|
|
||||||
--card: 0 0% 90%;
|
--card: 0 0% 90%;
|
||||||
--card-foreground: 222.2 84% 4.9%;
|
--card-foreground: 222.2 84% 4.9%;
|
||||||
|
|
||||||
--border: 214.3 31.8% 91.4%;
|
--border: 214.3 31.8% 91.4%;
|
||||||
--input: 214.3 31.8% 91.4%;
|
--input: 214.3 31.8% 91.4%;
|
||||||
|
|
||||||
--primary: 222.2 47.4% 11.2%;
|
--primary: 222.2 47.4% 11.2%;
|
||||||
--primary-foreground: 210 40% 98%;
|
--primary-foreground: 210 40% 98%;
|
||||||
|
|
||||||
--secondary: 210 26% 86%;
|
--secondary: 210 26% 86%;
|
||||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
--accent: 210 26% 86%;
|
--accent: 210 26% 86%;
|
||||||
--accent-light: 210 26% 86%;
|
--accent-light: 210 26% 86%;
|
||||||
--accent-foreground: 222.2 47.4% 11.2%;
|
--accent-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
--destructive: 0 72.2% 50.6%;
|
--destructive: 0 72.2% 50.6%;
|
||||||
--destructive-foreground: 210 40% 98%;
|
--destructive-foreground: 210 40% 98%;
|
||||||
|
|
||||||
--ring: 222.2 84% 4.9%;
|
--ring: 222.2 84% 4.9%;
|
||||||
|
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
|
|
||||||
--sidebar-background: 0 0% 98%;
|
--sidebar-background: 0 0% 98%;
|
||||||
--sidebar-foreground: 240 5.3% 26.1%;
|
--sidebar-foreground: 240 5.3% 26.1%;
|
||||||
--sidebar-primary: 240 5.9% 10%;
|
--sidebar-primary: 240 5.9% 10%;
|
||||||
--sidebar-primary-foreground: 0 0% 98%;
|
--sidebar-primary-foreground: 0 0% 98%;
|
||||||
--sidebar-accent: 240 4.8% 95.9%;
|
--sidebar-accent: 240 4.8% 95.9%;
|
||||||
--sidebar-accent-foreground: 240 5.9% 10%;
|
--sidebar-accent-foreground: 240 5.9% 10%;
|
||||||
--sidebar-border: 220 13% 91%;
|
--sidebar-border: 220 13% 91%;
|
||||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
:root {
|
||||||
--background: 222.2 84% 4.9%;
|
--background: 222.2 84% 4.9%;
|
||||||
--foreground: 210 40% 90%;
|
--foreground: 210 40% 90%;
|
||||||
|
|
||||||
--muted: 217.2 32.6% 17.5%;
|
--muted: 217.2 32.6% 17.5%;
|
||||||
--muted-foreground: 215 20.2% 65.1%;
|
--muted-foreground: 215 20.2% 65.1%;
|
||||||
|
|
||||||
--popover: 222.2 84% 4.9%;
|
--popover: 222.2 84% 4.9%;
|
||||||
--popover-foreground: 210 40% 90%;
|
--popover-foreground: 210 40% 90%;
|
||||||
|
|
||||||
--card: 222.2 84% 4.9%;
|
--card: 222.2 84% 4.9%;
|
||||||
--card-foreground: 210 40% 90%;
|
--card-foreground: 210 40% 90%;
|
||||||
|
|
||||||
--border: 217.2 32.6% 17.5%;
|
--border: 217.2 32.6% 17.5%;
|
||||||
--input: 217.2 32.6% 17.5%;
|
--input: 217.2 32.6% 17.5%;
|
||||||
|
|
||||||
--primary: 210 40% 90%;
|
--primary: 210 40% 90%;
|
||||||
--primary-foreground: 222.2 47.4% 11.2%;
|
--primary-foreground: 222.2 47.4% 11.2%;
|
||||||
|
|
||||||
--secondary: 217.2 32.6% 17.5%;
|
--secondary: 217.2 32.6% 17.5%;
|
||||||
--secondary-foreground: 210 40% 90%;
|
--secondary-foreground: 210 40% 90%;
|
||||||
|
|
||||||
--accent: 217.2 32.6% 17.5%;
|
--accent: 217.2 32.6% 17.5%;
|
||||||
--accent-foreground: 210 40% 90%;
|
--accent-foreground: 210 40% 90%;
|
||||||
|
|
||||||
--destructive: 0 62.8% 30.6%;
|
--destructive: 0 62.8% 30.6%;
|
||||||
--destructive-foreground: 210 40% 90%;
|
--destructive-foreground: 210 40% 90%;
|
||||||
|
|
||||||
--ring: 212.7 26.8% 83.9%;
|
--ring: 212.7 26.8% 83.9%;
|
||||||
|
|
||||||
--sidebar-background: 240 5.9% 10%;
|
--sidebar-background: 240 5.9% 10%;
|
||||||
--sidebar-foreground: 240 4.8% 95.9%;
|
--sidebar-foreground: 240 4.8% 95.9%;
|
||||||
--sidebar-primary: 224.3 76.3% 48%;
|
--sidebar-primary: 224.3 76.3% 48%;
|
||||||
--sidebar-primary-foreground: 0 0% 100%;
|
--sidebar-primary-foreground: 0 0% 100%;
|
||||||
--sidebar-accent: 240 3.7% 15.9%;
|
--sidebar-accent: 240 3.7% 15.9%;
|
||||||
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
--sidebar-accent-foreground: 240 4.8% 95.9%;
|
||||||
--sidebar-border: 240 3.7% 15.9%;
|
--sidebar-border: 240 3.7% 15.9%;
|
||||||
--sidebar-ring: 217.2 91.2% 59.8%;
|
--sidebar-ring: 217.2 91.2% 59.8%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
* {
|
* {
|
||||||
@apply border-border;
|
@apply border-border;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
ol > li {
|
||||||
|
@apply flex flex-wrap gap-x-2;
|
||||||
|
counter-increment: counterName;
|
||||||
|
}
|
||||||
|
ol > li:before {
|
||||||
|
content: counter(counterName) '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,10 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body data-sveltekit-preload-data="hover">
|
<body
|
||||||
<div class="flex flex-col min-h-screen">%sveltekit.body%</div>
|
data-sveltekit-preload-data="hover"
|
||||||
|
class="flex min-h-screen flex-col items-center gap-8 p-4 max-sm:px-2"
|
||||||
|
>
|
||||||
|
%sveltekit.body%
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
BIN
src/lib/assets/GetItOnGooglePlay_Badge_Web_color_English.png
Normal file
BIN
src/lib/assets/GetItOnGooglePlay_Badge_Web_color_English.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
BIN
src/lib/assets/guide-client.mp4
(Stored with Git LFS)
Normal file
BIN
src/lib/assets/guide-client.mp4
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -22,10 +22,9 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="relative max-w-fit overflow-x-hidden rounded-lg bg-accent">
|
<div class="relative flex-grow overflow-x-hidden rounded-lg bg-accent">
|
||||||
<div class="flex items-start overflow-x-auto p-2">
|
<div class="flex items-start overflow-x-auto p-2">
|
||||||
<pre><code>{data}</code></pre>
|
<pre><code>{data}</code></pre>
|
||||||
|
|
||||||
{#if copy || download}
|
{#if copy || download}
|
||||||
<!--Copy button-->
|
<!--Copy button-->
|
||||||
<!--Flex reverse for peer hover to work properly-->
|
<!--Flex reverse for peer hover to work properly-->
|
||||||
|
|||||||
5
src/lib/components/app/wireguard-guide/index.ts
Normal file
5
src/lib/components/app/wireguard-guide/index.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import WireguardGuide from "./wireguard-guide.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
WireguardGuide
|
||||||
|
};
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import * as Tabs from '$lib/components/ui/tabs';
|
||||||
|
import * as Card from '$lib/components/ui/card';
|
||||||
|
import getItOnGooglePlay from '$lib/assets/GetItOnGooglePlay_Badge_Web_color_English.png';
|
||||||
|
import guideVideo from '$lib/assets/guide-client.mp4';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Tabs.Root value="android">
|
||||||
|
<Tabs.List class="grid w-full grid-cols-3">
|
||||||
|
<Tabs.Trigger value="android">Android</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger value="windows">Windows</Tabs.Trigger>
|
||||||
|
<Tabs.Trigger value="other">Other</Tabs.Trigger>
|
||||||
|
</Tabs.List>
|
||||||
|
<Tabs.Content value="android">
|
||||||
|
<Card.Root>
|
||||||
|
<Card.Header class="max-sm:px-4 max-sm:pt-4">
|
||||||
|
<Card.Title>WireGuard on Android</Card.Title>
|
||||||
|
</Card.Header>
|
||||||
|
<Card.Content class="max-sm:p-4">
|
||||||
|
<ol class="flex flex-col gap-2">
|
||||||
|
<li>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
Install the WireGuard app
|
||||||
|
<a
|
||||||
|
class="contents"
|
||||||
|
href="https://play.google.com/store/apps/details?id=com.wireguard.android"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
<img class="size-min" alt="Get it on google play" src={getItOnGooglePlay} />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="flex flex-col gap-2">
|
||||||
|
<p>Download the configuration file and import it</p>
|
||||||
|
<aside>Alternatively, you can scan the QR code with the WireGuard app</aside>
|
||||||
|
<video autoplay loop controls muted preload="metadata" class="max-h-screen">
|
||||||
|
<source src={guideVideo} type="video/mp4" />
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</Card.Content>
|
||||||
|
</Card.Root>
|
||||||
|
</Tabs.Content>
|
||||||
|
<Tabs.Content value="windows">
|
||||||
|
<Card.Root>
|
||||||
|
<Card.Header>
|
||||||
|
<Card.Title>WireGuard on Windows</Card.Title>
|
||||||
|
</Card.Header>
|
||||||
|
<Card.Content>
|
||||||
|
<p>
|
||||||
|
<a
|
||||||
|
class="underline"
|
||||||
|
href="https://download.wireguard.com/windows-client/wireguard-installer.exe"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Download WireGuard
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
</Card.Content>
|
||||||
|
</Card.Root>
|
||||||
|
</Tabs.Content>
|
||||||
|
<Tabs.Content value="other">
|
||||||
|
<Card.Root>
|
||||||
|
<Card.Header>
|
||||||
|
<Card.Title>WireGuard on Other Platforms</Card.Title>
|
||||||
|
</Card.Header>
|
||||||
|
<Card.Content>
|
||||||
|
<p>
|
||||||
|
You can download the WireGuard client from the <a
|
||||||
|
class="underline"
|
||||||
|
href="https://www.wireguard.com/install/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
official website
|
||||||
|
</a>.
|
||||||
|
</p>
|
||||||
|
</Card.Content>
|
||||||
|
</Card.Root>
|
||||||
|
</Tabs.Content>
|
||||||
|
</Tabs.Root>
|
||||||
@@ -14,10 +14,12 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="p-4 sm:flex">
|
<header class="flex w-full flex-wrap justify-between gap-x-6 gap-y-4 xl:max-w-screen-xl">
|
||||||
<span class=" mr-6 font-bold sm:inline-block">VPGen</span>
|
<a href="/" class="contents">
|
||||||
<nav>
|
<span class="font-bold sm:inline-block">VPGen</span>
|
||||||
<ul class="flex items-center gap-6 text-sm">
|
</a>
|
||||||
|
<nav class="max-w-full">
|
||||||
|
<ul class="flex items-center gap-6 overflow-x-auto text-sm">
|
||||||
<li><a href="/" class={getNavClass(/^\/$/)}>Home</a></li>
|
<li><a href="/" class={getNavClass(/^\/$/)}>Home</a></li>
|
||||||
{#if user}
|
{#if user}
|
||||||
<li><a href="/user" class={getNavClass(/^\/user$/)}>Profile</a></li>
|
<li><a href="/user" class={getNavClass(/^\/user$/)}>Profile</a></li>
|
||||||
@@ -27,13 +29,16 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
<main class="flex flex-grow flex-col p-4">
|
<main class="flex min-w-full max-w-full flex-grow flex-col gap-4 xl:min-w-[1280px]">
|
||||||
{@render children()}
|
{@render children()}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<!--https://github.com/sveltejs/kit/discussions/7585#discussioncomment-9997936-->
|
<!--https://github.com/sveltejs/kit/discussions/7585#discussioncomment-9997936-->
|
||||||
<!--Some shenanings needed to be done to get the footer position to stick correctly,
|
<!--Some shenanings needed to be done to get the footer position to stick correctly,
|
||||||
didn't work with display: contents-->
|
didn't work with display: contents-->
|
||||||
<footer class="relative inset-x-0 bottom-0 p-4 text-center">
|
<footer class="inset-x-0 bottom-0 w-full text-center">
|
||||||
<p>© 2024</p>
|
<p>© 2024</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { AuthForm } from '$lib/components/app/auth-form';
|
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
|
import { AuthForm } from '$lib/components/app/auth-form';
|
||||||
|
|
||||||
const { data } = $props();
|
const { data } = $props();
|
||||||
const { user } = data;
|
const { user } = data;
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<title>VPGen</title>
|
<title>VPGen</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<h1 class="mb-2 scroll-m-20 text-3xl font-extrabold tracking-tight lg:text-4xl">
|
<h1 class="mb-2 scroll-m-20 text-center text-3xl font-extrabold tracking-tight lg:text-4xl">
|
||||||
Welcome to VPGen
|
Welcome to VPGen
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@@ -21,16 +21,35 @@
|
|||||||
<section id="get-started" class="border-l-2 pl-6">
|
<section id="get-started" class="border-l-2 pl-6">
|
||||||
<p>
|
<p>
|
||||||
To get started,
|
To get started,
|
||||||
<Button class="ml-2 p-2" href="/clients?add=New+Client">Create a New Client</Button>
|
<Button class="ml-2" href="/clients?add=New+Client">Create a New Client</Button>
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
<!-- <section id="using-wireguard">-->
|
||||||
|
<!-- <details class="mt-10">-->
|
||||||
|
<!-- <summary class="relative flex flex-col gap-2 pl-10">-->
|
||||||
|
<!-- <h2 class="text-xl font-semibold">Using WireGuard</h2>-->
|
||||||
|
<!-- To use VPGen, you need to install the WireGuard app on your device.-->
|
||||||
|
<!-- </summary>-->
|
||||||
|
<!-- <WireguardGuide />-->
|
||||||
|
<!-- </details>-->
|
||||||
|
<!-- </section>-->
|
||||||
{:else}
|
{:else}
|
||||||
<AuthForm class="p-4" />
|
<AuthForm />
|
||||||
<p>VPGen is a VPN generator that allows you to create and manage VPN connections.</p>
|
<!-- <p>VPGen is a VPN generator that allows you to create and manage VPN connections.</p>-->
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
p {
|
p {
|
||||||
@apply my-2;
|
@apply my-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
summary::before {
|
||||||
|
content: '▶';
|
||||||
|
@apply absolute -left-0;
|
||||||
|
}
|
||||||
|
details[open] summary::before {
|
||||||
|
content: '▼';
|
||||||
|
}
|
||||||
|
*/
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -61,34 +61,33 @@
|
|||||||
</Table.Root>
|
</Table.Root>
|
||||||
|
|
||||||
<!--Floating action button for adding a new client-->
|
<!--Floating action button for adding a new client-->
|
||||||
<!--Not sure if this is the best place for the input field, will think about it later-->
|
<Dialog.Root bind:open={dialogOpen}>
|
||||||
<div class="mt-auto flex self-end pt-4">
|
<div class="mt-auto flex self-end pt-4">
|
||||||
<Dialog.Root bind:open={dialogOpen}>
|
<Dialog.Trigger class={buttonVariants({ variant: 'default' }) + ' flex gap-4'}>
|
||||||
<Dialog.Trigger class={buttonVariants({ variant: "default" }) + "flex gap-4"}>
|
|
||||||
<LucidePlus />
|
<LucidePlus />
|
||||||
Add Client
|
New Client
|
||||||
</Dialog.Trigger>
|
</Dialog.Trigger>
|
||||||
<Dialog.Content class="max-w-xs">
|
</div>
|
||||||
<form class="contents" method="post" action="?/create">
|
<Dialog.Content class="max-w-xs">
|
||||||
<Dialog.Header class="">
|
<form class="contents" method="post" action="?/create">
|
||||||
<Dialog.Title>Create a new client</Dialog.Title>
|
<Dialog.Header class="">
|
||||||
</Dialog.Header>
|
<Dialog.Title>Create a new client</Dialog.Title>
|
||||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
</Dialog.Header>
|
||||||
<Label for="name">Name</Label>
|
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||||
<Input
|
<Label for="name">Name</Label>
|
||||||
bind:value={dialogVal}
|
<Input
|
||||||
required
|
bind:value={dialogVal}
|
||||||
pattern=".*[^\s]+.*"
|
required
|
||||||
type="text"
|
pattern=".*[^\s]+.*"
|
||||||
name="name"
|
type="text"
|
||||||
placeholder="New Client"
|
name="name"
|
||||||
class="max-w-[20ch]"
|
placeholder="New Client"
|
||||||
/>
|
class="max-w-[20ch]"
|
||||||
</div>
|
/>
|
||||||
<Dialog.Footer>
|
</div>
|
||||||
<Button type="submit">Create</Button>
|
<Dialog.Footer>
|
||||||
</Dialog.Footer>
|
<Button type="submit">Create</Button>
|
||||||
</form>
|
</Dialog.Footer>
|
||||||
</Dialog.Content>
|
</form>
|
||||||
</Dialog.Root>
|
</Dialog.Content>
|
||||||
</div>
|
</Dialog.Root>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import QRCode from 'qrcode-svg';
|
import QRCode from 'qrcode-svg';
|
||||||
import { CodeSnippet } from '$lib/components/app/code-snippet';
|
import { CodeSnippet } from '$lib/components/app/code-snippet';
|
||||||
|
import { WireguardGuide } from '$lib/components/app/wireguard-guide';
|
||||||
|
|
||||||
const { data }: { data: PageData } = $props();
|
const { data }: { data: PageData } = $props();
|
||||||
|
|
||||||
@@ -15,19 +16,64 @@
|
|||||||
content: data.config,
|
content: data.config,
|
||||||
join: true,
|
join: true,
|
||||||
background: 'hsl(var(--accent-light))',
|
background: 'hsl(var(--accent-light))',
|
||||||
|
xmlDeclaration: false,
|
||||||
|
// predefined: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const modules = qrCode.qrcode.modules;
|
||||||
|
const length = modules.length;
|
||||||
|
|
||||||
|
const s = 1;
|
||||||
|
|
||||||
|
// Rectangles representing modules
|
||||||
|
// let pathData = '';
|
||||||
|
//
|
||||||
|
// for (let y = 0; y < length; y++) {
|
||||||
|
// for (let x = 0; x < length; x++) {
|
||||||
|
// let module = modules[x][y];
|
||||||
|
// if (module) {
|
||||||
|
// pathData += `M${x*s},${y*s} h${s} v${s} h-${s} Z `
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const path = modules.reduce((acc, row, y) => {
|
||||||
|
// return acc + row.reduce((rowAcc, module, x) => {
|
||||||
|
// return module ? rowAcc + `M${x*s},${y*s} h${s} v${s} h-${s} Z ` : rowAcc;
|
||||||
|
// }, '');
|
||||||
|
// }, '');
|
||||||
|
const path = modules.flat().reduce((acc, module, i) => {
|
||||||
|
const x = Math.floor(i / length)
|
||||||
|
const y = i % length;
|
||||||
|
return module ? acc + `M${x*s},${y*s} h${s} v${s} h-${s} Z ` : acc;
|
||||||
|
}, '');
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title></title>
|
<title>{data.client.name}</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<h1 class="mb-4 w-fit rounded-lg bg-accent p-2 text-lg">{data.client.name}</h1>
|
<h1 class="w-fit rounded-lg bg-accent p-2 text-lg">{data.client.name}</h1>
|
||||||
|
|
||||||
<div class="flex flex-wrap gap-4">
|
<section id="client-configuration" class="flex flex-wrap justify-center gap-4">
|
||||||
<CodeSnippet data={data.config} filename={clientWgCleanedName} copy download />
|
<CodeSnippet data={data.config} filename={clientWgCleanedName} copy download />
|
||||||
|
|
||||||
<div class="overflow-hidden rounded-lg">
|
<div class="overflow-hidden rounded-lg">
|
||||||
{@html qrCode.svg()}
|
{@html qrCode.svg()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<!--{qrCode.svg({ container: 'none' })}-->
|
||||||
|
<!--{qrCode.sv}-->
|
||||||
|
<div class="aspect-square min-h-64 p-3 bg-white rounded-lg">
|
||||||
|
<svg viewBox="0 0 {length*s*0.5} {length*s*0.5}" shape-rendering="crispEdges" image-rendering="optimizeQuality">
|
||||||
|
<path transform="scale(0.5)" d={path} />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<!--{pathdata}-->
|
||||||
|
</section>
|
||||||
|
<section id="usage" class="flex w-full flex-col gap-2">
|
||||||
|
<h2 class="text-xl font-semibold">Usage</h2>
|
||||||
|
<p>To use VPGen, you need to install the WireGuard app on your device.</p>
|
||||||
|
<WireguardGuide />
|
||||||
|
</section>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { Config } from "tailwindcss";
|
|||||||
import tailwindcssAnimate from "tailwindcss-animate";
|
import tailwindcssAnimate from "tailwindcss-animate";
|
||||||
|
|
||||||
const config: Config = {
|
const config: Config = {
|
||||||
darkMode: ["class"],
|
darkMode: ["media"],
|
||||||
content: ["./src/**/*.{html,js,svelte,ts}"],
|
content: ["./src/**/*.{html,js,svelte,ts}"],
|
||||||
safelist: ["dark"],
|
safelist: ["dark"],
|
||||||
theme: {
|
theme: {
|
||||||
|
|||||||
Reference in New Issue
Block a user