Update layout to be a svelte monorepo with shadcn-svelte

Also: add the start of a.starrysky.fyi
diff --git a/packages/components/.eslintignore b/packages/components/.eslintignore
new file mode 100644
index 0000000..3897265
--- /dev/null
+++ b/packages/components/.eslintignore
@@ -0,0 +1,13 @@
+.DS_Store
+node_modules
+/build
+/.svelte-kit
+/package
+.env
+.env.*
+!.env.example
+
+# Ignore files for PNPM, NPM and YARN
+pnpm-lock.yaml
+package-lock.json
+yarn.lock
diff --git a/packages/components/.eslintrc.cjs b/packages/components/.eslintrc.cjs
new file mode 100644
index 0000000..ebc1958
--- /dev/null
+++ b/packages/components/.eslintrc.cjs
@@ -0,0 +1,30 @@
+module.exports = {
+	root: true,
+	extends: [
+		'eslint:recommended',
+		'plugin:@typescript-eslint/recommended',
+		'plugin:svelte/recommended',
+		'prettier'
+	],
+	parser: '@typescript-eslint/parser',
+	plugins: ['@typescript-eslint'],
+	parserOptions: {
+		sourceType: 'module',
+		ecmaVersion: 2020,
+		extraFileExtensions: ['.svelte']
+	},
+	env: {
+		browser: true,
+		es2017: true,
+		node: true
+	},
+	overrides: [
+		{
+			files: ['*.svelte'],
+			parser: 'svelte-eslint-parser',
+			parserOptions: {
+				parser: '@typescript-eslint/parser'
+			}
+		}
+	]
+};
diff --git a/packages/components/.gitignore b/packages/components/.gitignore
new file mode 100644
index 0000000..ac7211b
--- /dev/null
+++ b/packages/components/.gitignore
@@ -0,0 +1,11 @@
+.DS_Store
+node_modules
+/build
+/dist
+/.svelte-kit
+/package
+.env
+.env.*
+!.env.example
+vite.config.js.timestamp-*
+vite.config.ts.timestamp-*
diff --git a/packages/components/.npmrc b/packages/components/.npmrc
new file mode 100644
index 0000000..0c05da4
--- /dev/null
+++ b/packages/components/.npmrc
@@ -0,0 +1,2 @@
+engine-strict=true
+resolution-mode=highest
diff --git a/packages/components/.prettierignore b/packages/components/.prettierignore
new file mode 100644
index 0000000..3897265
--- /dev/null
+++ b/packages/components/.prettierignore
@@ -0,0 +1,13 @@
+.DS_Store
+node_modules
+/build
+/.svelte-kit
+/package
+.env
+.env.*
+!.env.example
+
+# Ignore files for PNPM, NPM and YARN
+pnpm-lock.yaml
+package-lock.json
+yarn.lock
diff --git a/packages/components/.prettierrc b/packages/components/.prettierrc
new file mode 100644
index 0000000..a77fdde
--- /dev/null
+++ b/packages/components/.prettierrc
@@ -0,0 +1,9 @@
+{
+	"useTabs": true,
+	"singleQuote": true,
+	"trailingComma": "none",
+	"printWidth": 100,
+	"plugins": ["prettier-plugin-svelte"],
+	"pluginSearchDirs": ["."],
+	"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
+}
diff --git a/packages/components/README.md b/packages/components/README.md
new file mode 100644
index 0000000..4fee31f
--- /dev/null
+++ b/packages/components/README.md
@@ -0,0 +1,58 @@
+# create-svelte
+
+Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
+
+Read more about creating a library [in the docs](https://kit.svelte.dev/docs/packaging).
+
+## Creating a project
+
+If you're seeing this, you've probably already done this step. Congrats!
+
+```bash
+# create a new project in the current directory
+npm create svelte@latest
+
+# create a new project in my-app
+npm create svelte@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
+```
+
+Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
+
+## Building
+
+To build your library:
+
+```bash
+npm run package
+```
+
+To create a production version of your showcase app:
+
+```bash
+npm run build
+```
+
+You can preview the production build with `npm run preview`.
+
+> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
+
+## Publishing
+
+Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).
+
+To publish your library to [npm](https://www.npmjs.com):
+
+```bash
+npm publish
+```
diff --git a/packages/components/package.json b/packages/components/package.json
new file mode 100644
index 0000000..50246bc
--- /dev/null
+++ b/packages/components/package.json
@@ -0,0 +1,68 @@
+{
+	"name": "components",
+	"version": "0.0.1",
+	"scripts": {
+		"dev": "vite dev",
+		"build": "vite build && npm run package",
+		"preview": "vite preview",
+		"package": "svelte-kit sync && svelte-package && publint",
+		"prepublishOnly": "npm run package",
+		"test": "playwright test",
+		"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+		"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
+		"test:unit": "vitest",
+		"lint": "prettier --plugin-search-dir . --check . && eslint .",
+		"format": "prettier --plugin-search-dir . --write ."
+	},
+	"exports": {
+		".": {
+			"types": "./dist/index.d.ts",
+			"svelte": "./dist/index.js"
+		}
+	},
+	"files": [
+		"dist",
+		"!dist/**/*.test.*",
+		"!dist/**/*.spec.*"
+	],
+	"peerDependencies": {
+		"svelte": "^3.54.0"
+	},
+	"devDependencies": {
+		"@playwright/test": "^1.28.1",
+		"@sveltejs/adapter-auto": "^2.0.0",
+		"@sveltejs/kit": "^1.5.0",
+		"@sveltejs/package": "^2.0.0",
+		"@types/seedrandom": "^3.0.5",
+		"@typescript-eslint/eslint-plugin": "^5.45.0",
+		"@typescript-eslint/parser": "^5.45.0",
+		"autoprefixer": "^10.4.14",
+		"eslint": "^8.28.0",
+		"eslint-config-prettier": "^8.5.0",
+		"eslint-plugin-svelte": "^2.26.0",
+		"postcss": "^8.4.23",
+		"postcss-load-config": "^4.0.1",
+		"prettier": "^2.8.0",
+		"prettier-plugin-svelte": "^2.8.1",
+		"publint": "^0.1.9",
+		"svelte": "^3.54.0",
+		"svelte-check": "^3.0.1",
+		"svelte-preprocess": "^5.0.3",
+		"tailwindcss": "^3.3.1",
+		"tslib": "^2.4.1",
+		"typescript": "^5.0.0",
+		"vite": "^4.3.0",
+		"vitest": "^0.25.3"
+	},
+	"svelte": "./dist/index.js",
+	"types": "./dist/index.d.ts",
+	"type": "module",
+	"dependencies": {
+		"class-variance-authority": "^0.6.0",
+		"clsx": "^1.2.1",
+		"lucide-svelte": "^0.229.0",
+		"seedrandom": "^3.0.5",
+		"tailwind-merge": "^1.12.0",
+		"tailwindcss-animate": "^1.0.5"
+	}
+}
diff --git a/packages/components/playwright.config.ts b/packages/components/playwright.config.ts
new file mode 100644
index 0000000..1c5d7a1
--- /dev/null
+++ b/packages/components/playwright.config.ts
@@ -0,0 +1,12 @@
+import type { PlaywrightTestConfig } from '@playwright/test';
+
+const config: PlaywrightTestConfig = {
+	webServer: {
+		command: 'npm run build && npm run preview',
+		port: 4173
+	},
+	testDir: 'tests',
+	testMatch: /(.+\.)?(test|spec)\.[jt]s/
+};
+
+export default config;
diff --git a/packages/components/postcss.config.cjs b/packages/components/postcss.config.cjs
new file mode 100644
index 0000000..04e27fe
--- /dev/null
+++ b/packages/components/postcss.config.cjs
@@ -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,
+		autoprefixer
+	]
+};
+
+module.exports = config;
diff --git a/packages/components/src/app.d.ts b/packages/components/src/app.d.ts
new file mode 100644
index 0000000..f59b884
--- /dev/null
+++ b/packages/components/src/app.d.ts
@@ -0,0 +1,12 @@
+// See https://kit.svelte.dev/docs/types#app
+// for information about these interfaces
+declare global {
+	namespace App {
+		// interface Error {}
+		// interface Locals {}
+		// interface PageData {}
+		// interface Platform {}
+	}
+}
+
+export {};
diff --git a/packages/components/src/app.html b/packages/components/src/app.html
new file mode 100644
index 0000000..d2fc6b0
--- /dev/null
+++ b/packages/components/src/app.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<link rel="icon" href="%sveltekit.assets%/favicon.png" />
+		<meta name="viewport" content="width=device-width, initial-scale=1" />
+		%sveltekit.head%
+	</head>
+	<body data-sveltekit-preload-data="hover">
+		<div>%sveltekit.body%</div>
+	</body>
+</html>
diff --git a/packages/components/src/app.postcss b/packages/components/src/app.postcss
new file mode 100644
index 0000000..1a7b7cf
--- /dev/null
+++ b/packages/components/src/app.postcss
@@ -0,0 +1,4 @@
+/* Write your global styles here, in PostCSS syntax */
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/packages/components/src/index.test.ts b/packages/components/src/index.test.ts
new file mode 100644
index 0000000..e07cbbd
--- /dev/null
+++ b/packages/components/src/index.test.ts
@@ -0,0 +1,7 @@
+import { describe, it, expect } from 'vitest';
+
+describe('sum test', () => {
+	it('adds 1 + 2 to equal 3', () => {
+		expect(1 + 2).toBe(3);
+	});
+});
diff --git a/packages/components/src/lib/decoration/BackgroundStars/BackgroundStars.svelte b/packages/components/src/lib/decoration/BackgroundStars/BackgroundStars.svelte
new file mode 100644
index 0000000..7d69c57
--- /dev/null
+++ b/packages/components/src/lib/decoration/BackgroundStars/BackgroundStars.svelte
@@ -0,0 +1,64 @@
+<script lang="ts">
+	import seedrandom from 'seedrandom';
+
+	let random = seedrandom('backgroundstars');
+
+	let parts: [number, number][] = Array(50)
+		.fill(0)
+		.map(() => {
+			return [random(), random()];
+		});
+</script>
+
+<div class="star-container">
+	{#each parts as part}
+		<div
+			class="bg-amber-400 star"
+			style="top: {part[0] * 100}vh; left: {part[1] * 100}vw; animation-delay: {(part[0] +
+				part[1]) *
+				2500}ms;"
+		/>
+	{/each}
+</div>
+
+<style>
+	@keyframes twinkle {
+		0% {
+			opacity: 0;
+		}
+		50% {
+			opacity: 1;
+		}
+		100% {
+			opacity: 0;
+		}
+	}
+
+	@keyframes rotate {
+		0% {
+			transform: rotate(0deg);
+		}
+		100% {
+			transform: rotate(360deg);
+		}
+	}
+
+	div.star {
+		position: absolute;
+		width: 1px;
+		height: 1px;
+		transition: top 0.5s ease-in-out, left 0.5s ease-in-out;
+		animation: twinkle 10s infinite;
+		opacity: 0;
+	}
+
+	div.star-container {
+		position: fixed;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+		animation: rotate 240s infinite linear;
+		z-index: -1;
+	}
+</style>
diff --git a/packages/components/src/lib/decoration/BackgroundStars/index.ts b/packages/components/src/lib/decoration/BackgroundStars/index.ts
new file mode 100644
index 0000000..81fab75
--- /dev/null
+++ b/packages/components/src/lib/decoration/BackgroundStars/index.ts
@@ -0,0 +1 @@
+export { default as BackgroundStars } from './BackgroundStars.svelte';
diff --git a/packages/components/src/lib/index.js b/packages/components/src/lib/index.js
new file mode 100644
index 0000000..47d3c46
--- /dev/null
+++ b/packages/components/src/lib/index.js
@@ -0,0 +1 @@
+// Reexport your entry components here
diff --git a/packages/components/src/lib/ui/button/Button.svelte b/packages/components/src/lib/ui/button/Button.svelte
new file mode 100644
index 0000000..c65bd1d
--- /dev/null
+++ b/packages/components/src/lib/ui/button/Button.svelte
@@ -0,0 +1,33 @@
+<script lang="ts">
+	import type { VariantProps } from "class-variance-authority";
+	import type {
+		HTMLAnchorAttributes,
+		HTMLButtonAttributes
+	} from "svelte/elements";
+	import { cn } from "$lib/utils";
+	import { buttonVariants } from ".";
+
+	let className: string | undefined | null = undefined;
+	export { className as class };
+	export let href: HTMLAnchorAttributes["href"] = undefined;
+	export let type: HTMLButtonAttributes["type"] = undefined;
+	export let variant: VariantProps<typeof buttonVariants>["variant"] =
+		"default";
+	export let size: VariantProps<typeof buttonVariants>["size"] = "default";
+</script>
+
+<svelte:element
+	this={href ? "a" : "button"}
+	type={href ? undefined : type}
+	{href}
+	class={cn(buttonVariants({ variant, size, className }))}
+	{...$$restProps}
+	on:click
+	on:change
+	on:keydown
+	on:keyup
+	on:mouseenter
+	on:mouseleave
+>
+	<slot />
+</svelte:element>
diff --git a/packages/components/src/lib/ui/button/index.ts b/packages/components/src/lib/ui/button/index.ts
new file mode 100644
index 0000000..32393a4
--- /dev/null
+++ b/packages/components/src/lib/ui/button/index.ts
@@ -0,0 +1,32 @@
+import { cva } from "class-variance-authority";
+
+export { default as Button } from "./Button.svelte";
+
+export const buttonVariants = cva(
+	"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none ring-offset-background",
+	{
+		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 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: "underline-offset-4 hover:underline text-primary"
+			},
+			size: {
+				default: "h-10 py-2 px-4",
+				sm: "h-9 px-3 rounded-md",
+				lg: "h-11 px-8 rounded-md"
+			}
+		},
+		defaultVariants: {
+			variant: "default",
+			size: "default"
+		}
+	}
+);
diff --git a/packages/components/src/lib/ui/input/Input.svelte b/packages/components/src/lib/ui/input/Input.svelte
new file mode 100644
index 0000000..40b1ac9
--- /dev/null
+++ b/packages/components/src/lib/ui/input/Input.svelte
@@ -0,0 +1,30 @@
+<script lang="ts">
+	import type { HTMLInputAttributes } from "svelte/elements";
+	import { cn } from "$lib/utils";
+
+	let className: string | undefined | null = undefined;
+
+	export let value: HTMLInputAttributes["value"] = undefined;
+	export { className as class };
+</script>
+
+<input
+	class={cn(
+		"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
+		className
+	)}
+	bind:value
+	on:blur
+	on:change
+	on:click
+	on:focus
+	on:keydown
+	on:keypress
+	on:keyup
+	on:mouseover
+	on:mouseenter
+	on:mouseleave
+	on:paste
+	on:input
+	{...$$restProps}
+/>
diff --git a/packages/components/src/lib/ui/input/index.ts b/packages/components/src/lib/ui/input/index.ts
new file mode 100644
index 0000000..06f880b
--- /dev/null
+++ b/packages/components/src/lib/ui/input/index.ts
@@ -0,0 +1 @@
+export { default as Input } from "./Input.svelte";
diff --git a/packages/components/src/lib/utils.ts b/packages/components/src/lib/utils.ts
new file mode 100644
index 0000000..256f86f
--- /dev/null
+++ b/packages/components/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { type ClassValue, clsx } from 'clsx';
+import { twMerge } from 'tailwind-merge';
+
+export function cn(...inputs: ClassValue[]) {
+	return twMerge(clsx(inputs));
+}
diff --git a/packages/components/src/routes/+layout.svelte b/packages/components/src/routes/+layout.svelte
new file mode 100644
index 0000000..d93b258
--- /dev/null
+++ b/packages/components/src/routes/+layout.svelte
@@ -0,0 +1,6 @@
+<script>
+	import '../app.postcss';
+	import '../app.postcss';
+</script>
+
+<slot />
diff --git a/packages/components/src/routes/+page.svelte b/packages/components/src/routes/+page.svelte
new file mode 100644
index 0000000..0a45b69
--- /dev/null
+++ b/packages/components/src/routes/+page.svelte
@@ -0,0 +1,3 @@
+<h1>Welcome to your library project</h1>
+<p>Create your package using @sveltejs/package and preview/showcase your work with SvelteKit</p>
+<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
diff --git a/packages/components/static/favicon.png b/packages/components/static/favicon.png
new file mode 100644
index 0000000..825b9e6
--- /dev/null
+++ b/packages/components/static/favicon.png
Binary files differ
diff --git a/packages/components/svelte.config.js b/packages/components/svelte.config.js
new file mode 100644
index 0000000..e45fed0
--- /dev/null
+++ b/packages/components/svelte.config.js
@@ -0,0 +1,24 @@
+import preprocess from 'svelte-preprocess';
+import adapter from '@sveltejs/adapter-auto';
+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(),
+		preprocess({
+			postcss: true
+		})
+	],
+	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()
+	},
+	shadcn: {
+		componentPath: './src/lib/ui'
+	}
+};
+export default config;
diff --git a/packages/components/tailwind.config.cjs b/packages/components/tailwind.config.cjs
new file mode 100644
index 0000000..a2629b6
--- /dev/null
+++ b/packages/components/tailwind.config.cjs
@@ -0,0 +1,12 @@
+/** @type {import('tailwindcss').Config}*/
+const config = {
+	content: ['./src/**/*.{html,js,svelte,ts}'],
+
+	theme: {
+		extend: {}
+	},
+
+	plugins: []
+};
+
+module.exports = config;
diff --git a/packages/components/tests/test.ts b/packages/components/tests/test.ts
new file mode 100644
index 0000000..5816be4
--- /dev/null
+++ b/packages/components/tests/test.ts
@@ -0,0 +1,6 @@
+import { expect, test } from '@playwright/test';
+
+test('index page has expected h1', async ({ page }) => {
+	await page.goto('/');
+	await expect(page.getByRole('heading', { name: 'Welcome to SvelteKit' })).toBeVisible();
+});
diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json
new file mode 100644
index 0000000..f56aae6
--- /dev/null
+++ b/packages/components/tsconfig.json
@@ -0,0 +1,14 @@
+{
+	"extends": "./.svelte-kit/tsconfig.json",
+	"compilerOptions": {
+		"allowJs": true,
+		"checkJs": true,
+		"esModuleInterop": true,
+		"forceConsistentCasingInFileNames": true,
+		"resolveJsonModule": true,
+		"skipLibCheck": true,
+		"sourceMap": true,
+		"strict": true,
+		"moduleResolution": "NodeNext"
+	}
+}
diff --git a/packages/components/vite.config.ts b/packages/components/vite.config.ts
new file mode 100644
index 0000000..37b6a84
--- /dev/null
+++ b/packages/components/vite.config.ts
@@ -0,0 +1,9 @@
+import { sveltekit } from '@sveltejs/kit/vite';
+import { defineConfig } from 'vitest/config';
+
+export default defineConfig({
+	plugins: [sveltekit()],
+	test: {
+		include: ['src/**/*.{test,spec}.{js,ts}']
+	}
+});