commit 33aaf78f7d82606dd82c5df3455825219e0cb394 Author: Chris Kruining Date: Tue Sep 16 15:54:26 2025 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..751513c --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +dist +.wrangler +.output +.vercel +.netlify +.vinxi +app.config.timestamp_*.js + +# Environment +.env +.env*.local + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +*.launch +.settings/ + +# Temp +gitignore + +# System Files +.DS_Store +Thumbs.db diff --git a/README.md b/README.md new file mode 100644 index 0000000..9337430 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +# SolidStart + +Everything you need to build a Solid project, powered by [`solid-start`](https://start.solidjs.com); + +## Creating a project + +```bash +# create a new project in the current directory +npm init solid@latest + +# create a new project in my-app +npm init solid@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 +``` + +## Building + +Solid apps are built with _presets_, which optimise your project for deployment to different environments. + +By default, `npm run build` will generate a Node app that you can run with `npm start`. To use a different preset, add it to the `devDependencies` in `package.json` and specify in your `app.config.js`. + +## This project was created with the [Solid CLI](https://github.com/solidjs-community/solid-cli) diff --git a/app.config.ts b/app.config.ts new file mode 100644 index 0000000..de7f831 --- /dev/null +++ b/app.config.ts @@ -0,0 +1,3 @@ +import { defineConfig } from "@solidjs/start/config"; + +export default defineConfig({}); diff --git a/bun.lockb b/bun.lockb new file mode 100644 index 0000000..dae0047 Binary files /dev/null and b/bun.lockb differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..684ad2f --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "example-basic", + "type": "module", + "scripts": { + "dev": "vinxi dev", + "build": "vinxi build", + "start": "vinxi start", + "version": "vinxi version" + }, + "dependencies": { + "@solid-primitives/context": "^0.3.2", + "@solid-primitives/event-listener": "^2.4.3", + "@solidjs/meta": "^0.29.4", + "@solidjs/router": "^0.15.0", + "@solidjs/start": "^1.1.0", + "better-auth": "^1.3.11", + "open-props": "^1.7.16", + "solid-icons": "^1.1.0", + "solid-js": "^1.9.5", + "vinxi": "^0.5.7" + }, + "engines": { + "node": ">=22" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..fb282da Binary files /dev/null and b/public/favicon.ico differ diff --git a/src/app.tsx b/src/app.tsx new file mode 100644 index 0000000..37274a7 --- /dev/null +++ b/src/app.tsx @@ -0,0 +1,23 @@ +import { MetaProvider, Title } from "@solidjs/meta"; +import { Router } from "@solidjs/router"; +import { FileRoutes } from "@solidjs/start/router"; +import { Suspense } from "solid-js"; +import { ThemeContextProvider } from "./features/theme"; +import "./app.css"; + +export default function App() { + return ( + ( + + Amarth Portal + + {props.children} + + + )} + > + + + ); +} diff --git a/src/components/Counter.css b/src/components/Counter.css new file mode 100644 index 0000000..220e179 --- /dev/null +++ b/src/components/Counter.css @@ -0,0 +1,21 @@ +.increment { + font-family: inherit; + font-size: inherit; + padding: 1em 2em; + color: #335d92; + background-color: rgba(68, 107, 158, 0.1); + border-radius: 2em; + border: 2px solid rgba(68, 107, 158, 0); + outline: none; + width: 200px; + font-variant-numeric: tabular-nums; + cursor: pointer; +} + +.increment:focus { + border: 2px solid #335d92; +} + +.increment:active { + background-color: rgba(68, 107, 158, 0.2); +} \ No newline at end of file diff --git a/src/components/Counter.tsx b/src/components/Counter.tsx new file mode 100644 index 0000000..091fc5d --- /dev/null +++ b/src/components/Counter.tsx @@ -0,0 +1,11 @@ +import { createSignal } from "solid-js"; +import "./Counter.css"; + +export default function Counter() { + const [count, setCount] = createSignal(0); + return ( + + ); +} diff --git a/src/entry-client.tsx b/src/entry-client.tsx new file mode 100644 index 0000000..0ca4e3c --- /dev/null +++ b/src/entry-client.tsx @@ -0,0 +1,4 @@ +// @refresh reload +import { mount, StartClient } from "@solidjs/start/client"; + +mount(() => , document.getElementById("app")!); diff --git a/src/entry-server.tsx b/src/entry-server.tsx new file mode 100644 index 0000000..401eff8 --- /dev/null +++ b/src/entry-server.tsx @@ -0,0 +1,21 @@ +// @refresh reload +import { createHandler, StartServer } from "@solidjs/start/server"; + +export default createHandler(() => ( + ( + + + + + + {assets} + + +
{children}
+ {scripts} + + + )} + /> +)); diff --git a/src/features/theme/context.ts b/src/features/theme/context.ts new file mode 100644 index 0000000..a419644 --- /dev/null +++ b/src/features/theme/context.ts @@ -0,0 +1,88 @@ +import { + ContextProviderProps, + createContextProvider, +} from "@solid-primitives/context"; +import { action, createAsyncStore, query, useAction } from "@solidjs/router"; +import { createStore } from "solid-js/store"; +import { useSession } from "vinxi/http"; + +export enum ColorScheme { + Auto = "light dark", + Light = "light", + Dark = "dark", +} + +export interface State { + colorScheme: ColorScheme; + hue: number; +} + +const getSession = async () => { + "use server"; + + return useSession({ + password: process.env.SESSION_SECRET!, + }); +}; + +export const getState = query(async () => { + "use server"; + + const session = await getSession(); + + if (Object.getOwnPropertyNames(session.data).length === 0) { + await session.update({ + colorScheme: ColorScheme.Auto, + hue: 0, + }); + } + + return session.data; +}, "color-scheme"); + +const setState = action(async (state: State) => { + "use server"; + + const session = await getSession(); + await session.update((prev) => ({ ...prev, ...state })); +}, "color-scheme"); + +interface ThemeContextType { + readonly theme: State; + setColorScheme(colorScheme: ColorScheme): void; + setHue(colorScheme: number): void; +} + +const [ThemeContextProvider, useTheme] = createContextProvider< + ThemeContextType, + ContextProviderProps +>( + (props) => { + const updateState = useAction(setState); + const state = createAsyncStore(() => getState()); + + return { + get theme() { + return state.latest ?? { colorScheme: null }; + }, + + setColorScheme(colorScheme) { + // updateState({ colorScheme, hue: state.latest!.hue }); + }, + setHue(hue) { + // updateState({ hue, colorScheme: state.latest!.colorScheme }); + }, + }; + }, + { + theme: { + colorScheme: ColorScheme.Auto, + hue: 180, + }, + + setColorScheme(colorScheme) {}, + setHue(hue) {}, + }, +); + +export { ThemeContextProvider, useTheme }; diff --git a/src/features/theme/index.ts b/src/features/theme/index.ts new file mode 100644 index 0000000..561afbd --- /dev/null +++ b/src/features/theme/index.ts @@ -0,0 +1,4 @@ + + +export { ThemeContextProvider, useTheme } from './context'; +export { ColorSchemePicker } from './picker'; \ No newline at end of file diff --git a/src/features/theme/picker.module.css b/src/features/theme/picker.module.css new file mode 100644 index 0000000..66baa23 --- /dev/null +++ b/src/features/theme/picker.module.css @@ -0,0 +1,9 @@ +.picker { + grid-template-columns: auto 1fr; +} + +.hue { + display: flex; + flex-flow: row; + align-items: center; +} \ No newline at end of file diff --git a/src/features/theme/picker.tsx b/src/features/theme/picker.tsx new file mode 100644 index 0000000..2e9f1c8 --- /dev/null +++ b/src/features/theme/picker.tsx @@ -0,0 +1,69 @@ +import { + WiMoonAltFirstQuarter, + WiMoonAltFull, + WiMoonAltNew, +} from "solid-icons/wi"; +import { + Component, + createEffect, + For, + Match, + on, + Setter, + Switch, +} from "solid-js"; +import { ColorScheme, useTheme } from "./context"; +import css from "./picker.module.css"; +import { Select } from "~/components/select"; + +const colorSchemes: Record = + Object.fromEntries( + Object.entries(ColorScheme).map(([k, v]) => [v, k]) + ) as any; + +export const ColorSchemePicker: Component = (props) => { + const themeContext = useTheme(); + + const setScheme: Setter = (next) => { + if (typeof next === "function") { + next = next(); + } + + themeContext.setColorScheme(next); + }; + + return ( + <> + + + {/* */} + + ); +}; diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..dc6f10c --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1 @@ +/// diff --git a/src/routes/(shell).tsx b/src/routes/(shell).tsx new file mode 100644 index 0000000..3e4767c --- /dev/null +++ b/src/routes/(shell).tsx @@ -0,0 +1,41 @@ +import { Meta } from "@solidjs/meta"; +import { query, createAsync } from "@solidjs/router"; +import { createEffect, on, ParentProps } from "solid-js"; +import { getRequestEvent } from "solid-js/web"; +import { auth } from "~/auth.server"; +import { Shell } from "~/features/shell"; +import { useTheme } from "~/features/theme"; +import { User } from "~/features/user"; + +const load = query(async (): Promise => { + "use server"; + + const session = await auth.api.getSession(getRequestEvent()!.request); + + if (session === null) { + return undefined; + } + + const { username, name, email, image = null } = session.user; + + return { username, name, email, image }; +}, "session"); + +export const route = { + async preload() { + return load(); + }, +}; + +export default function ShellPage(props: ParentProps) { + const user = createAsync(() => load()); + const themeContext = useTheme(); + + return ( + + + + {props.children} + + ); +} diff --git a/src/routes/(shell)/[...404].tsx b/src/routes/(shell)/[...404].tsx new file mode 100644 index 0000000..4ea71ec --- /dev/null +++ b/src/routes/(shell)/[...404].tsx @@ -0,0 +1,19 @@ +import { Title } from "@solidjs/meta"; +import { HttpStatusCode } from "@solidjs/start"; + +export default function NotFound() { + return ( +
+ Not Found + +

Page Not Found

+

+ Visit{" "} + + start.solidjs.com + {" "} + to learn how to build SolidStart apps. +

+
+ ); +} diff --git a/src/routes/(shell)/index.tsx b/src/routes/(shell)/index.tsx new file mode 100644 index 0000000..2f8a03b --- /dev/null +++ b/src/routes/(shell)/index.tsx @@ -0,0 +1,15 @@ +import { Title } from "@solidjs/meta"; + +export const route = { + preload: async () => ({}), +}; + +export default function Home() { + return ( + <> + Home + +
HOME PAGE
+ + ); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..7d5871a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "jsx": "preserve", + "jsxImportSource": "solid-js", + "allowJs": true, + "strict": true, + "noEmit": true, + "types": ["vinxi/types/client"], + "isolatedModules": true, + "paths": { + "~/*": ["./src/*"] + } + } +}