add tailwindcss and shadcn

This commit is contained in:
Shahrad Elahi 2023-11-02 16:32:33 +03:30
parent 686172b27b
commit 414538daf6
21 changed files with 435 additions and 88 deletions

View File

@ -1,3 +1,3 @@
.idea
node_modules
.ignore
assets

View File

@ -1,5 +1,6 @@
FROM node:alpine as base
WORKDIR /app
FROM oven/bun:alpine as base
LABEL Maintainer="Shahrad Elahi <https://github.com/shahradelahi>"
WORKDIR /usr/src/app
ENV TZ=UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
@ -7,51 +8,58 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY --from=chriswayg/tor-alpine:latest /usr/local/bin/obfs4proxy /usr/local/bin/obfs4proxy
COPY --from=chriswayg/tor-alpine:latest /usr/local/bin/meek-server /usr/local/bin/meek-server
# Set the mirror list
RUN echo "https://uk.alpinelinux.org/alpine/latest-stable/main" > /etc/apk/repositories && \
echo "https://mirror.bardia.tech/alpine/latest-stable/main" >> /etc/apk/repositories && \
echo "https://uk.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories &&\
echo "https://mirror.bardia.tech/alpine/latest-stable/community" >> /etc/apk/repositories
# Update and upgrade packages
RUN apk update && apk upgrade
# Install required packages
RUN apk add -U --no-cache \
iproute2 iptables net-tools \
screen vim curl bash \
wireguard-tools \
openssl \
dumb-init \
tor \
redis
iproute2 iptables net-tools \
screen vim curl bash \
wireguard-tools \
openssl \
dumb-init \
tor \
redis
# Clear cache
RUN rm -rf /var/cache/apk/*
FROM node:alpine as builder
WORKDIR /app
FROM base AS deps
COPY /src/package.json /src/package-lock.json ./
RUN npm install
RUN mkdir -p /temp/dev
COPY web/package.json web/bun.lockb /temp/dev/
RUN cd /temp/dev && bun install --frozen-lockfile
RUN mkdir -p /temp/prod
COPY web/package.json web/bun.lockb /temp/prod/
RUN cd /temp/prod && bun install --frozen-lockfile --production
FROM base AS build
COPY --from=deps /temp/dev/node_modules node_modules
COPY web .
# build
ENV NODE_ENV=production
COPY /src/ .
RUN npm run build
RUN bun run build
FROM base
WORKDIR /app
FROM base AS release
COPY --from=deps /temp/prod/node_modules node_modules
COPY --from=build /usr/src/app/build .
COPY --from=build /usr/src/app/package.json .
ENV NODE_ENV=production
LABEL Maintainer="Shahrad Elahi <https://github.com/shahradelahi>"
COPY /config/torrc /etc/tor/torrc
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/next.config.js ./next.config.js
COPY --from=builder /app/public ./public
COPY /src/package.json /src/package-lock.json ./
RUN npm install --omit dev
# run the app
USER bun
EXPOSE 3000/tcp
HEALTHCHECK --interval=60s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://127.0.0.1:3000/api/healthcheck || exit 1
COPY docker-entrypoint.sh /usr/bin/entrypoint
RUN chmod +x /usr/bin/entrypoint
ENTRYPOINT ["/usr/bin/entrypoint"]
CMD ["npm", "run", "start"]
CMD [ "bun", "start" ]

View File

@ -8,45 +8,41 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY --from=chriswayg/tor-alpine:latest /usr/local/bin/obfs4proxy /usr/local/bin/obfs4proxy
COPY --from=chriswayg/tor-alpine:latest /usr/local/bin/meek-server /usr/local/bin/meek-server
# Set the mirror list
RUN echo "https://uk.alpinelinux.org/alpine/latest-stable/main" > /etc/apk/repositories && \
echo "https://mirror.bardia.tech/alpine/latest-stable/main" >> /etc/apk/repositories && \
echo "https://uk.alpinelinux.org/alpine/latest-stable/community" >> /etc/apk/repositories &&\
echo "https://mirror.bardia.tech/alpine/latest-stable/community" >> /etc/apk/repositories
# Update and upgrade packages
RUN apk update && apk upgrade
# Install required packages
RUN apk add -U --no-cache \
iproute2 iptables net-tools \
screen vim curl bash \
wireguard-tools \
openssl \
dumb-init \
tor \
redis
iproute2 iptables net-tools \
screen vim curl bash \
wireguard-tools \
openssl \
dumb-init \
tor \
redis
# Clear cache
RUN rm -rf /var/cache/apk/*
FROM base AS deps
RUN mkdir -p /temp/dev
COPY web/package.json web/bun.lockb /temp/dev/
COPY web/package.json web/bun.lockb web/node_modules* /temp/dev/
RUN cd /temp/dev && bun install --frozen-lockfile
RUN mkdir -p /temp/prod
COPY web/package.json web/bun.lockb /temp/prod/
RUN cd /temp/prod && bun install --frozen-lockfile --production
FROM base AS runner
FROM install AS build
COPY --from=deps /temp/dev/node_modules node_modules
COPY web .
# build
ENV NODE_ENV=production
RUN bun run build
FROM base AS release
COPY --from=deps /temp/prod/node_modules node_modules
COPY --from=build /usr/src/app/build .
COPY --from=build /usr/src/app/package.json .
ENV NODE_ENV=production
# run the app
USER bun
EXPOSE 3000/tcp
CMD [ "bun", "start" ]
# run the appc
EXPOSE 5173/tcp
CMD [ "bun", "dev", "--host" ]

View File

@ -3,7 +3,9 @@ services:
wireadmin:
image: wireadmin
volumes:
- ./src/:/app/
- ./web/:/usr/src/app/
ports:
- "5173:5173"
environment:
- UI_PASSWORD=password
- WG_HOST=192.168.1.102

View File

@ -4,7 +4,7 @@
"description": "",
"scripts": {
"dev:image": "DOCKER_BUILDKIT=1 docker build --tag wireadmin -f Dockerfile-Dev .",
"dev": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml up; docker rm -f wireadmin"
"dev": "docker compose rm -fsv && docker compose -f docker-compose.yml -f docker-compose.dev.yml up && docker compose rm -fsv"
},
"keywords": [],
"author": "Shahrad Elahi <https://github.com/shahradelahi>",

5
pnpm-lock.yaml Normal file
View File

@ -0,0 +1,5 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false

View File

@ -1,5 +1,5 @@
{
"useTabs": false,
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
@ -9,7 +9,6 @@
"pluginSearchDirs": [
"."
],
"tabWidth": 2,
"overrides": [
{
"files": "*.svelte",

Binary file not shown.

13
web/components.json Normal file
View File

@ -0,0 +1,13 @@
{
"$schema": "https://shadcn-svelte.com/schema.json",
"style": "default",
"tailwind": {
"config": "tailwind.config.js",
"css": "src/app.postcss",
"baseColor": "gray"
},
"aliases": {
"components": "$lib/components",
"utils": "$lib/utils"
}
}

View File

@ -8,20 +8,32 @@
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"test": "vitest",
"lint": "prettier --plugin-search-dir . --check .",
"format": "prettier --plugin-search-dir . --write .",
"start": "bun ./build/index.js"
"format": "prettier --plugin-search-dir . --write ."
},
"devDependencies": {
"@sveltejs/adapter-auto": "^2.0.0",
"@sveltejs/kit": "^1.20.4",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.24",
"postcss-load-config": "^4.0.1",
"prettier": "^2.8.0",
"prettier-plugin-svelte": "^2.10.1",
"svelte": "^4.0.5",
"svelte-check": "^3.4.3",
"tailwindcss": "^3.3.2",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^4.4.2"
"vite": "^4.4.2",
"vitest": "^0.34.0"
},
"type": "module"
}
"type": "module",
"dependencies": {
"bits-ui": "^0.9.0",
"clsx": "^2.0.0",
"lucide-svelte": "^0.292.0",
"tailwind-merge": "^2.0.0",
"tailwind-variants": "^0.1.18"
}
}

13
web/postcss.config.cjs Normal file
View File

@ -0,0 +1,13 @@
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
const config = {
plugins: [
//Some plugins, like tailwindcss/nesting, need to run before Tailwind,
tailwindcss(),
//But others, like autoprefixer, need to run after,
autoprefixer
]
};
module.exports = config;

78
web/src/app.postcss Normal file
View File

@ -0,0 +1,78 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--muted: 220 14.3% 95.9%;
--muted-foreground: 220 8.9% 46.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--card: 0 0% 100%;
--card-foreground: 224 71.4% 4.1%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
--accent: 220 14.3% 95.9%;
--accent-foreground: 220.9 39.3% 11%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 20% 98%;
--ring: 224 71.4% 4.1%;
--radius: 0.5rem;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--muted: 215 27.9% 16.9%;
--muted-foreground: 217.9 10.6% 64.9%;
--popover: 224 71.4% 4.1%;
--popover-foreground: 210 20% 98%;
--card: 224 71.4% 4.1%;
--card-foreground: 210 20% 98%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--secondary: 215 27.9% 16.9%;
--secondary-foreground: 210 20% 98%;
--accent: 215 27.9% 16.9%;
--accent-foreground: 210 20% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 20% 98%;
--ring: 216 12.2% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}

7
web/src/index.test.ts Normal file
View File

@ -0,0 +1,7 @@
import { describe, expect, it } from 'vitest';
describe('sum test', () => {
it('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
});

View File

@ -0,0 +1,24 @@
<script lang="ts">
import { cn } from '$lib/utils';
import { buttonVariants, type Events, type Props } from '.';
type $$Props = Props;
type $$Events = Events;
let className: $$Props['class'] = undefined;
export let variant: $$Props['variant'] = 'default';
export let size: $$Props['size'] = 'default';
export let builders: $$Props['builders'] = [];
export { className as class };
</script>
<ButtonPrimitive.Root
{builders}
class={cn(buttonVariants({ variant, size, className }))}
type="button"
{...$$restProps}
on:click
on:keydown
>
<slot />
</ButtonPrimitive.Root>

View File

@ -0,0 +1,51 @@
import Root from './button.svelte';
import { tv, type VariantProps } from 'tailwind-variants';
import type { Button as ButtonPrimitive } from 'bits-ui';
const buttonVariants = tv({
base: 'inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive:
'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline:
'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
secondary:
'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline'
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10'
}
},
defaultVariants: {
variant: 'default',
size: 'default'
}
});
type Variant = VariantProps<typeof buttonVariants>['variant'];
type Size = VariantProps<typeof buttonVariants>['size'];
type Props = ButtonPrimitive.Props & {
variant?: Variant;
size?: Size;
};
type Events = ButtonPrimitive.Events;
export {
Root,
type Props,
type Events,
//
Root as Button,
type Props as ButtonProps,
type Events as ButtonEvents,
buttonVariants
};

62
web/src/lib/utils.ts Normal file
View File

@ -0,0 +1,62 @@
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
import { cubicOut } from 'svelte/easing';
import type { TransitionConfig } from 'svelte/transition';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
type FlyAndScaleParams = {
y?: number;
x?: number;
start?: number;
duration?: number;
};
export const flyAndScale = (
node: Element,
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
): TransitionConfig => {
const style = getComputedStyle(node);
const transform = style.transform === 'none' ? '' : style.transform;
const scaleConversion = (
valueA: number,
scaleA: [ number, number ],
scaleB: [ number, number ]
) => {
const [ minA, maxA ] = scaleA;
const [ minB, maxB ] = scaleB;
const percentage = (valueA - minA) / (maxA - minA);
const valueB = percentage * (maxB - minB) + minB;
return valueB;
};
const styleToString = (
style: Record<string, number | string | undefined>
): string => {
return Object.keys(style).reduce((str, key) => {
if (style[key] === undefined) return str;
return str + `${key}:${style[key]};`;
}, '');
};
return {
duration: params.duration ?? 200,
delay: 0,
css: (t) => {
const y = scaleConversion(t, [ 0, 1 ], [ params.y ?? 5, 0 ]);
const x = scaleConversion(t, [ 0, 1 ], [ params.x ?? 0, 0 ]);
const scale = scaleConversion(t, [ 0, 1 ], [ params.start ?? 0.95, 1 ]);
return styleToString({
transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
opacity: t
});
},
easing: cubicOut
};
};

View File

@ -0,0 +1 @@
<script>import '../app.postcss';</script><slot></slot>

View File

@ -1,2 +1,8 @@
<script lang="ts">
import { Button } from '$lib/components/ui/button';
</script>
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
<Button variant="outline">Button</Button>

View File

@ -3,16 +3,19 @@ import { vitePreprocess } from '@sveltejs/kit/vite';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: [ vitePreprocess({}) ],
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
}
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(),
alias: {
$lib: './src/lib'
}
}
};
export default config;

64
web/tailwind.config.js Normal file
View File

@ -0,0 +1,64 @@
import { fontFamily } from 'tailwindcss/defaultTheme';
/** @type {import('tailwindcss').Config} */
const config = {
darkMode: [ 'class' ],
content: [ './src/**/*.{html,js,svelte,ts}' ],
safelist: [ 'dark' ],
theme: {
container: {
center: true,
padding: '2rem',
screens: {
'2xl': '1400px'
}
},
extend: {
colors: {
border: 'hsl(var(--border) / <alpha-value>)',
input: 'hsl(var(--input) / <alpha-value>)',
ring: 'hsl(var(--ring) / <alpha-value>)',
background: 'hsl(var(--background) / <alpha-value>)',
foreground: 'hsl(var(--foreground) / <alpha-value>)',
primary: {
DEFAULT: 'hsl(var(--primary) / <alpha-value>)',
foreground: 'hsl(var(--primary-foreground) / <alpha-value>)'
},
secondary: {
DEFAULT: 'hsl(var(--secondary) / <alpha-value>)',
foreground: 'hsl(var(--secondary-foreground) / <alpha-value>)'
},
destructive: {
DEFAULT: 'hsl(var(--destructive) / <alpha-value>)',
foreground: 'hsl(var(--destructive-foreground) / <alpha-value>)'
},
muted: {
DEFAULT: 'hsl(var(--muted) / <alpha-value>)',
foreground: 'hsl(var(--muted-foreground) / <alpha-value>)'
},
accent: {
DEFAULT: 'hsl(var(--accent) / <alpha-value>)',
foreground: 'hsl(var(--accent-foreground) / <alpha-value>)'
},
popover: {
DEFAULT: 'hsl(var(--popover) / <alpha-value>)',
foreground: 'hsl(var(--popover-foreground) / <alpha-value>)'
},
card: {
DEFAULT: 'hsl(var(--card) / <alpha-value>)',
foreground: 'hsl(var(--card-foreground) / <alpha-value>)'
}
},
borderRadius: {
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)'
},
fontFamily: {
sans: [ ...fontFamily.sans ]
}
}
}
};
export default config;

View File

@ -1,6 +1,9 @@
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { defineConfig } from 'vitest/config';
export default defineConfig({
plugins: [ sveltekit() ]
plugins: [ sveltekit() ],
test: {
include: [ 'src/**/*.{test,spec}.{js,ts}' ]
}
});