mirror of
https://github.com/rajnandan1/kener.git
synced 2026-06-23 04:10:22 +00:00
chore: Update environment variables and documentation for ORIGIN requirement; refactor Docker setup for documentation indexing
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
KENER_SECRET_KEY=some_secret_key_for_kener
|
KENER_SECRET_KEY=some_secret_key_for_kener
|
||||||
REDIS_URL=redis://localhost:6379
|
REDIS_URL=redis://localhost:6379
|
||||||
|
ORIGIN=http://localhost:3000
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
name: Publish Main Docker Image (with Docs)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
DOCKERHUB_REGISTRY: docker.io
|
||||||
|
GITHUB_REGISTRY: ghcr.io
|
||||||
|
DOCKERHUB_IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }}
|
||||||
|
GITHUB_IMAGE_NAME: ${{ github.repository }}
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: main-docker-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push-main:
|
||||||
|
name: Build and push main Docker images (with docs)
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
variant: [debian, alpine]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out the repo
|
||||||
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
|
- name: Install cosign
|
||||||
|
uses: sigstore/cosign-installer@v3.8.0
|
||||||
|
with:
|
||||||
|
cosign-release: v2.2.4
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3.8.0
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v3.3.0
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Log in to GitHub Container Registry
|
||||||
|
uses: docker/login-action@v3.3.0
|
||||||
|
with:
|
||||||
|
registry: ${{ env.GITHUB_REGISTRY }}
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Extract Docker metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5.6.1
|
||||||
|
with:
|
||||||
|
images: |
|
||||||
|
${{ env.DOCKERHUB_IMAGE_NAME }}
|
||||||
|
${{ env.GITHUB_REGISTRY }}/${{ env.GITHUB_IMAGE_NAME }}
|
||||||
|
tags: |
|
||||||
|
type=raw,value=main-with-docs,enable=${{ matrix.variant == 'debian' }}
|
||||||
|
type=raw,value=main-with-docs-alpine,enable=${{ matrix.variant == 'alpine' }}
|
||||||
|
type=sha,format=short,prefix=main-with-docs-,enable=${{ matrix.variant == 'debian' }}
|
||||||
|
type=sha,format=short,prefix=main-with-docs-alpine-,enable=${{ matrix.variant == 'alpine' }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@v3.3.0
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
id: build-and-push
|
||||||
|
uses: docker/build-push-action@v6.13.0
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
build-args: |
|
||||||
|
VARIANT=${{ matrix.variant }}
|
||||||
|
WITH_DOCS=true
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
cache-from: type=gha
|
||||||
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
|
- name: Sign the published Docker images
|
||||||
|
env:
|
||||||
|
TAGS: ${{ steps.meta.outputs.tags }}
|
||||||
|
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||||
|
run: |
|
||||||
|
echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
|
||||||
+38
-7
@@ -7,10 +7,12 @@
|
|||||||
# Build:
|
# Build:
|
||||||
# docker build -t kener . # Alpine (default)
|
# docker build -t kener . # Alpine (default)
|
||||||
# docker build -t kener --build-arg VARIANT=debian . # Debian Slim
|
# docker build -t kener --build-arg VARIANT=debian . # Debian Slim
|
||||||
|
# docker build -t kener --build-arg WITH_DOCS=true . # Include docs
|
||||||
#
|
#
|
||||||
# Run:
|
# Run:
|
||||||
# docker run -d -p 3000:3000 \
|
# docker run -d -p 3000:3000 \
|
||||||
# -e KENER_SECRET_KEY=<secret> \
|
# -e KENER_SECRET_KEY=<secret> \
|
||||||
|
# -e ORIGIN=http://localhost:3000 \
|
||||||
# -e REDIS_URL=redis://<host>:6379 \
|
# -e REDIS_URL=redis://<host>:6379 \
|
||||||
# -v kener_db:/app/database \
|
# -v kener_db:/app/database \
|
||||||
# kener
|
# kener
|
||||||
@@ -18,6 +20,7 @@
|
|||||||
|
|
||||||
ARG NODE_VERSION=24
|
ARG NODE_VERSION=24
|
||||||
ARG VARIANT=alpine
|
ARG VARIANT=alpine
|
||||||
|
ARG WITH_DOCS=false
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# STAGE 1 — BUILDER (installs deps, compiles native modules, builds app)
|
# STAGE 1 — BUILDER (installs deps, compiles native modules, builds app)
|
||||||
@@ -62,14 +65,35 @@ COPY . .
|
|||||||
# 4. Create directories that the app expects
|
# 4. Create directories that the app expects
|
||||||
RUN mkdir -p database
|
RUN mkdir -p database
|
||||||
|
|
||||||
# 5. Remove docs routes before build (avoids EXDEV rename error in overlayfs)
|
# 5. Conditionally remove docs routes before build
|
||||||
# and clean .svelte-kit so stale route types don't persist
|
# (avoids EXDEV rename error in overlayfs; clean .svelte-kit so stale
|
||||||
RUN rm -rf src/routes/\(docs\) .svelte-kit
|
# route types don't persist)
|
||||||
|
ARG WITH_DOCS
|
||||||
|
RUN if [ "$WITH_DOCS" != "true" ]; then \
|
||||||
|
rm -rf src/routes/\(docs\) .svelte-kit; \
|
||||||
|
fi
|
||||||
|
|
||||||
# 6. Build: SvelteKit (vite) + server bundle (esbuild)
|
# 6. Build: SvelteKit (vite) + server bundle (esbuild)
|
||||||
RUN npm run build
|
# Use build-with-docs when docs are enabled
|
||||||
|
RUN if [ "$WITH_DOCS" = "true" ]; then \
|
||||||
|
npm run build-with-docs; \
|
||||||
|
else \
|
||||||
|
npm run build; \
|
||||||
|
fi
|
||||||
|
|
||||||
# 7. Remove devDependencies from node_modules
|
# 7. Stage docs runtime files for index-docs (empty dir when docs disabled)
|
||||||
|
RUN mkdir -p /docs-runtime && \
|
||||||
|
if [ "$WITH_DOCS" = "true" ]; then \
|
||||||
|
mkdir -p /docs-runtime/scripts && \
|
||||||
|
mkdir -p /docs-runtime/src/lib && \
|
||||||
|
mkdir -p "/docs-runtime/src/routes/(docs)/docs" && \
|
||||||
|
cp scripts/index-docs.ts /docs-runtime/scripts/ && \
|
||||||
|
cp src/lib/marked.ts /docs-runtime/src/lib/ && \
|
||||||
|
cp "src/routes/(docs)/docs.json" "/docs-runtime/src/routes/(docs)/" && \
|
||||||
|
cp -r "src/routes/(docs)/docs/content" "/docs-runtime/src/routes/(docs)/docs/"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 8. Remove devDependencies from node_modules
|
||||||
RUN npm prune --omit=dev
|
RUN npm prune --omit=dev
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
@@ -137,6 +161,13 @@ COPY --chown=node:node --from=builder /app/src/lib/server/templates/general
|
|||||||
# Build output (SvelteKit client/server + esbuild main.js) — changes most often
|
# Build output (SvelteKit client/server + esbuild main.js) — changes most often
|
||||||
COPY --chown=node:node --from=builder /app/build ./build
|
COPY --chown=node:node --from=builder /app/build ./build
|
||||||
|
|
||||||
|
# Docs runtime files (index-docs script + markdown sources; empty when WITH_DOCS=false)
|
||||||
|
COPY --chown=node:node --from=builder /docs-runtime/ ./
|
||||||
|
|
||||||
|
# Entrypoint script (runs index-docs on startup when docs are bundled)
|
||||||
|
COPY --chown=node:node docker-entrypoint.sh ./docker-entrypoint.sh
|
||||||
|
RUN chmod +x docker-entrypoint.sh
|
||||||
|
|
||||||
# ---- Runtime configuration ----
|
# ---- Runtime configuration ----
|
||||||
|
|
||||||
# Switch to non-root user
|
# Switch to non-root user
|
||||||
@@ -148,5 +179,5 @@ EXPOSE ${PORT}
|
|||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||||
CMD sh -c 'curl -sf http://localhost:${PORT}${KENER_BASE_PATH}/healthcheck || exit 1'
|
CMD sh -c 'curl -sf http://localhost:${PORT}${KENER_BASE_PATH}/healthcheck || exit 1'
|
||||||
|
|
||||||
ENTRYPOINT ["node"]
|
ENTRYPOINT ["./docker-entrypoint.sh"]
|
||||||
CMD ["build/main.js"]
|
CMD ["node", "build/main.js"]
|
||||||
|
|||||||
@@ -78,14 +78,14 @@ git clone https://github.com/rajnandan1/kener.git
|
|||||||
cd kener
|
cd kener
|
||||||
|
|
||||||
# Uses docker-compose.yml (includes Redis + Kener)
|
# Uses docker-compose.yml (includes Redis + Kener)
|
||||||
# Set a strong KENER_SECRET_KEY in docker-compose.yml before first run
|
# Set a strong KENER_SECRET_KEY and ORIGIN in docker-compose.yml before first run
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Open `http://localhost:3000`.
|
Open `http://localhost:3000`.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> Set a strong `KENER_SECRET_KEY` before starting for the first time.
|
> Set a strong `KENER_SECRET_KEY` and set `ORIGIN` to your public URL before starting for the first time.
|
||||||
|
|
||||||
Use `docker-compose.dev.yml` when you want to build from local source instead of pulling the published image:
|
Use `docker-compose.dev.yml` when you want to build from local source instead of pulling the published image:
|
||||||
|
|
||||||
@@ -113,6 +113,7 @@ docker run -d \
|
|||||||
-p 3000:3000 \
|
-p 3000:3000 \
|
||||||
-v "$(pwd)/database:/app/database" \
|
-v "$(pwd)/database:/app/database" \
|
||||||
-e "KENER_SECRET_KEY=replace_with_a_random_string" \
|
-e "KENER_SECRET_KEY=replace_with_a_random_string" \
|
||||||
|
-e "ORIGIN=http://localhost:3000" \
|
||||||
-e "REDIS_URL=redis://host.docker.internal:6379" \
|
-e "REDIS_URL=redis://host.docker.internal:6379" \
|
||||||
docker.io/rajnandan1/kener:latest
|
docker.io/rajnandan1/kener:latest
|
||||||
```
|
```
|
||||||
@@ -140,6 +141,7 @@ Create a `.env` with at least:
|
|||||||
|
|
||||||
```dotenv
|
```dotenv
|
||||||
KENER_SECRET_KEY=replace_with_a_random_string
|
KENER_SECRET_KEY=replace_with_a_random_string
|
||||||
|
ORIGIN=http://localhost:3000
|
||||||
REDIS_URL=redis://localhost:6379
|
REDIS_URL=redis://localhost:6379
|
||||||
PORT=3000
|
PORT=3000
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -36,20 +36,20 @@ services:
|
|||||||
args:
|
args:
|
||||||
VARIANT: alpine # or "debian"
|
VARIANT: alpine # or "debian"
|
||||||
NODE_VERSION: 24
|
NODE_VERSION: 24
|
||||||
|
WITH_DOCS: "true"
|
||||||
container_name: kener-dev
|
container_name: kener-dev
|
||||||
environment:
|
environment:
|
||||||
KENER_SECRET_KEY: dev-secret-key-for-local-testing-only
|
KENER_SECRET_KEY: dev-secret-key-for-local-testing-only
|
||||||
|
ORIGIN: http://localhost:3000
|
||||||
REDIS_URL: redis://redis:6379
|
REDIS_URL: redis://redis:6379
|
||||||
# DATABASE_URL: sqlite://./database/kener.sqlite.db
|
# DATABASE_URL: sqlite://./database/kener.sqlite.db
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
volumes:
|
volumes:
|
||||||
- dev_data:/app/database
|
- dev_data:/app/database
|
||||||
- dev_uploads:/app/uploads
|
|
||||||
depends_on:
|
depends_on:
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
dev_data:
|
dev_data:
|
||||||
dev_uploads:
|
|
||||||
|
|||||||
+1
-3
@@ -34,6 +34,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
# ── Required ──
|
# ── Required ──
|
||||||
KENER_SECRET_KEY: replace_me_with_a_random_string # generate: openssl rand -base64 32
|
KENER_SECRET_KEY: replace_me_with_a_random_string # generate: openssl rand -base64 32
|
||||||
|
ORIGIN: http://localhost:3000 # public URL of your Kener instance (required for CSRF protection)
|
||||||
REDIS_URL: redis://redis:6379
|
REDIS_URL: redis://redis:6379
|
||||||
|
|
||||||
# ── Database (default: SQLite) ──
|
# ── Database (default: SQLite) ──
|
||||||
@@ -59,7 +60,6 @@ services:
|
|||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
volumes:
|
volumes:
|
||||||
- data:/app/database
|
- data:/app/database
|
||||||
- uploads:/app/uploads
|
|
||||||
depends_on:
|
depends_on:
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@@ -107,8 +107,6 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
data:
|
data:
|
||||||
name: kener_db
|
name: kener_db
|
||||||
uploads:
|
|
||||||
name: kener_uploads
|
|
||||||
redis_data:
|
redis_data:
|
||||||
name: kener_redis
|
name: kener_redis
|
||||||
# postgres_data:
|
# postgres_data:
|
||||||
|
|||||||
Executable
+11
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Index documentation into Redis when docs are bundled in the image
|
||||||
|
if [ -f /app/scripts/index-docs.ts ]; then
|
||||||
|
echo "[kener] Indexing documentation into Redis..."
|
||||||
|
node --experimental-strip-types /app/scripts/index-docs.ts || \
|
||||||
|
echo "[kener] Warning: docs indexing failed (is REDIS_URL set?). Continuing..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
@@ -16,7 +16,7 @@ import IORedis from "ioredis";
|
|||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import { marked } from "marked";
|
import { marked } from "marked";
|
||||||
import plaintify from "marked-plaintify";
|
import plaintify from "marked-plaintify";
|
||||||
import { mdToText } from "../src/lib/marked";
|
import { mdToText } from "../src/lib/marked.ts";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { handler } from "../build/handler.js";
|
import { handler } from "../build/handler.js";
|
||||||
import { apiReference } from "@scalar/express-api-reference";
|
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
import express from "express";
|
import express from "express";
|
||||||
@@ -7,7 +6,6 @@ import Startup from "../src/lib/server/startup.ts";
|
|||||||
import shutdownSchedulers from "../src/lib/server/schedulers/shutdown.ts";
|
import shutdownSchedulers from "../src/lib/server/schedulers/shutdown.ts";
|
||||||
import shutdownQueues from "../src/lib/server/queues/shutdown.ts";
|
import shutdownQueues from "../src/lib/server/queues/shutdown.ts";
|
||||||
import dbInstance from "../src/lib/server/db/db.ts";
|
import dbInstance from "../src/lib/server/db/db.ts";
|
||||||
import fs from "fs-extra";
|
|
||||||
import knex from "knex";
|
import knex from "knex";
|
||||||
import knexOb from "../knexfile.js";
|
import knexOb from "../knexfile.js";
|
||||||
|
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ The fastest way to get started is with Docker Compose.
|
|||||||
git clone https://github.com/rajnandan1/kener.git
|
git clone https://github.com/rajnandan1/kener.git
|
||||||
cd kener
|
cd kener
|
||||||
|
|
||||||
# Update KENER_SECRET_KEY in docker-compose.yml before first run
|
# Update KENER_SECRET_KEY and ORIGIN in docker-compose.yml before first run
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
Kener will be available at `http://localhost:3000`.
|
Kener will be available at `http://localhost:3000`.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> Set a strong value for `KENER_SECRET_KEY` in `docker-compose.yml` before starting.
|
> Set a strong value for `KENER_SECRET_KEY` and set `ORIGIN` to your public URL in `docker-compose.yml` before starting.
|
||||||
|
|
||||||
### Run pre-built image {#run-pre-built-image-docker-hub-or-ghcr}
|
### Run pre-built image {#run-pre-built-image-docker-hub-or-ghcr}
|
||||||
|
|
||||||
@@ -57,6 +57,7 @@ Minimum `.env` for Docker:
|
|||||||
|
|
||||||
```dotenv
|
```dotenv
|
||||||
KENER_SECRET_KEY=replace_with_a_random_string
|
KENER_SECRET_KEY=replace_with_a_random_string
|
||||||
|
ORIGIN=http://localhost:3000
|
||||||
REDIS_URL=redis://host.docker.internal:6379
|
REDIS_URL=redis://host.docker.internal:6379
|
||||||
PORT=3000
|
PORT=3000
|
||||||
```
|
```
|
||||||
@@ -70,6 +71,7 @@ docker run -d \
|
|||||||
-p 3000:3000 \
|
-p 3000:3000 \
|
||||||
-v "$(pwd)/database:/app/database" \
|
-v "$(pwd)/database:/app/database" \
|
||||||
-e "KENER_SECRET_KEY=replace_with_a_random_string" \
|
-e "KENER_SECRET_KEY=replace_with_a_random_string" \
|
||||||
|
-e "ORIGIN=http://localhost:3000" \
|
||||||
-e "REDIS_URL=redis://host.docker.internal:6379" \
|
-e "REDIS_URL=redis://host.docker.internal:6379" \
|
||||||
docker.io/rajnandan1/kener:latest
|
docker.io/rajnandan1/kener:latest
|
||||||
```
|
```
|
||||||
@@ -122,6 +124,7 @@ Create or update your `.env`:
|
|||||||
|
|
||||||
```dotenv
|
```dotenv
|
||||||
KENER_SECRET_KEY=replace_with_a_random_string
|
KENER_SECRET_KEY=replace_with_a_random_string
|
||||||
|
ORIGIN=http://localhost:3000
|
||||||
REDIS_URL=redis://localhost:6379
|
REDIS_URL=redis://localhost:6379
|
||||||
PORT=3000
|
PORT=3000
|
||||||
# Optional (defaults to SQLite):
|
# Optional (defaults to SQLite):
|
||||||
|
|||||||
@@ -44,6 +44,38 @@ node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
|
|||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> Without `KENER_SECRET_KEY`, Kener will use a default key which is **not secure for production**. You'll see warnings in the console if running without this variable.
|
> Without `KENER_SECRET_KEY`, Kener will use a default key which is **not secure for production**. You'll see warnings in the console if running without this variable.
|
||||||
|
|
||||||
|
### ORIGIN {#origin}
|
||||||
|
|
||||||
|
**Purpose**: The public-facing URL of your Kener instance. Required by SvelteKit for CSRF protection in production.
|
||||||
|
|
||||||
|
**Why It's Required**: In production builds, SvelteKit validates that POST form submissions originate from the same site. Without `ORIGIN`, all form submissions (login, signup, settings, etc.) will fail with a **"Cross-site POST form submissions are forbidden"** error.
|
||||||
|
|
||||||
|
**Requirements**:
|
||||||
|
|
||||||
|
- Must include protocol (`http://` or `https://`)
|
||||||
|
- Must match the URL users access in their browser
|
||||||
|
- No trailing slash
|
||||||
|
- Not needed during local development (`vite dev` infers it automatically)
|
||||||
|
|
||||||
|
**Examples**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Local Docker testing
|
||||||
|
ORIGIN=http://localhost:3000
|
||||||
|
|
||||||
|
# Production
|
||||||
|
ORIGIN=https://status.example.com
|
||||||
|
|
||||||
|
# With custom port
|
||||||
|
ORIGIN=https://status.example.com:8443
|
||||||
|
|
||||||
|
# With base path
|
||||||
|
ORIGIN=https://example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> Without `ORIGIN`, **all form submissions will be rejected** in production. This includes login, signup, and admin panel actions. Always set this variable when deploying.
|
||||||
|
|
||||||
## Optional Variables {#optional-variables}
|
## Optional Variables {#optional-variables}
|
||||||
|
|
||||||
### KENER_BASE_PATH {#kener-base-path}
|
### KENER_BASE_PATH {#kener-base-path}
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import DotsIcon from "@lucide/svelte/icons/camera";
|
|
||||||
import FolderIcon from "@lucide/svelte/icons/folder";
|
|
||||||
import Share3Icon from "@lucide/svelte/icons/share";
|
|
||||||
import TrashIcon from "@lucide/svelte/icons/trash";
|
|
||||||
import type { Component } from "svelte";
|
|
||||||
import * as DropdownMenu from "$lib/components/ui/dropdown-menu/index.js";
|
|
||||||
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
|
|
||||||
let { items }: { items: { name: string; url: string; icon: Component }[] } = $props();
|
|
||||||
const sidebar = Sidebar.useSidebar();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Sidebar.Group class="group-data-[collapsible=icon]:hidden">
|
|
||||||
<Sidebar.GroupLabel>Documents</Sidebar.GroupLabel>
|
|
||||||
<Sidebar.Menu>
|
|
||||||
{#each items as item (item.name)}
|
|
||||||
<Sidebar.MenuItem>
|
|
||||||
<Sidebar.MenuButton>
|
|
||||||
{#snippet child({ props })}
|
|
||||||
<a {...props} href={item.url}>
|
|
||||||
<item.icon />
|
|
||||||
<span>{item.name}</span>
|
|
||||||
</a>
|
|
||||||
{/snippet}
|
|
||||||
</Sidebar.MenuButton>
|
|
||||||
<DropdownMenu.Root>
|
|
||||||
<DropdownMenu.Trigger>
|
|
||||||
{#snippet child({ props })}
|
|
||||||
<Sidebar.MenuAction {...props} showOnHover class="data-[state=open]:bg-accent rounded-sm">
|
|
||||||
<DotsIcon />
|
|
||||||
<span class="sr-only">More</span>
|
|
||||||
</Sidebar.MenuAction>
|
|
||||||
{/snippet}
|
|
||||||
</DropdownMenu.Trigger>
|
|
||||||
<DropdownMenu.Content
|
|
||||||
class="w-24 rounded-lg"
|
|
||||||
side={sidebar.isMobile ? "bottom" : "right"}
|
|
||||||
align={sidebar.isMobile ? "end" : "start"}
|
|
||||||
>
|
|
||||||
<DropdownMenu.Item>
|
|
||||||
<FolderIcon />
|
|
||||||
<span>Open</span>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
<DropdownMenu.Item>
|
|
||||||
<Share3Icon />
|
|
||||||
<span>Share</span>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
<DropdownMenu.Separator />
|
|
||||||
<DropdownMenu.Item variant="destructive">
|
|
||||||
<TrashIcon />
|
|
||||||
<span>Delete</span>
|
|
||||||
</DropdownMenu.Item>
|
|
||||||
</DropdownMenu.Content>
|
|
||||||
</DropdownMenu.Root>
|
|
||||||
</Sidebar.MenuItem>
|
|
||||||
{/each}
|
|
||||||
<Sidebar.MenuItem>
|
|
||||||
<Sidebar.MenuButton class="text-sidebar-foreground/70">
|
|
||||||
<DotsIcon class="text-sidebar-foreground/70" />
|
|
||||||
<span>More</span>
|
|
||||||
</Sidebar.MenuButton>
|
|
||||||
</Sidebar.MenuItem>
|
|
||||||
</Sidebar.Menu>
|
|
||||||
</Sidebar.Group>
|
|
||||||
@@ -1,7 +1,4 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import CirclePlusFilledIcon from "@lucide/svelte/icons/circle-plus";
|
|
||||||
import MailIcon from "@lucide/svelte/icons/mail";
|
|
||||||
import { Button } from "$lib/components/ui/button/index.js";
|
|
||||||
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
|
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
|
||||||
import { page } from "$app/state";
|
import { page } from "$app/state";
|
||||||
import type { Component } from "svelte";
|
import type { Component } from "svelte";
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import * as Sidebar from "$lib/components/ui/sidebar/index.js";
|
|
||||||
import type { WithoutChildren } from "$lib/utils.js";
|
|
||||||
import type { Component, ComponentProps } from "svelte";
|
|
||||||
let {
|
|
||||||
items,
|
|
||||||
...restProps
|
|
||||||
}: { items: { title: string; url: string; icon: Component }[] } & WithoutChildren<
|
|
||||||
ComponentProps<typeof Sidebar.Group>
|
|
||||||
> = $props();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Sidebar.Group {...restProps}>
|
|
||||||
<Sidebar.GroupContent>
|
|
||||||
<Sidebar.Menu>
|
|
||||||
{#each items as item (item.title)}
|
|
||||||
<Sidebar.MenuItem>
|
|
||||||
<Sidebar.MenuButton>
|
|
||||||
{#snippet child({ props })}
|
|
||||||
<a href={item.url} {...props}>
|
|
||||||
<item.icon />
|
|
||||||
<span>{item.title}</span>
|
|
||||||
</a>
|
|
||||||
{/snippet}
|
|
||||||
</Sidebar.MenuButton>
|
|
||||||
</Sidebar.MenuItem>
|
|
||||||
{/each}
|
|
||||||
</Sidebar.Menu>
|
|
||||||
</Sidebar.GroupContent>
|
|
||||||
</Sidebar.Group>
|
|
||||||
@@ -20,12 +20,14 @@
|
|||||||
href={clientResolver(resolve, "/")}
|
href={clientResolver(resolve, "/")}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
size="sm"
|
size="sm"
|
||||||
class="dark:text-foreground hidden sm:flex"
|
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
>
|
>
|
||||||
Status Page
|
Status Page
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button href="https://kener.ing/docs" variant="secondary" size="sm" target="_blank" rel="noopener noreferrer">
|
||||||
|
Documentation
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
Reference in New Issue
Block a user