Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 33 additions & 18 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,45 @@
name: Build and Push Docker Container

name: Build and push Docker images
on:
push:
branches: main
paths:
- 'nix/**'
- 'flake.nix'
- 'flake.lock'
- 'apps/**'
- 'packages/**'
- '.dockerignore'
- '.github/workflows/docker.yml'
- 'ci/build-push-images.sh'
- 'package.json'
- 'pnpm-lock.yaml'
- 'pnpm-workspace.yaml'
workflow_dispatch:

jobs:
build:
name: 'nix docker build'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
if: github.repository == 'PluralKit/dashboard'

# temporarily comment this out for testing
#if: github.repository == 'PluralKit/web'
steps:
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v4
- run: echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
- name: Build docker image
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main

- name: nuke runner registries
run: sudo rm -f /etc/containers/registries.conf

- if: ${{ !env.ACT }}
env:
OWNER: ${{ github.repository_owner }}
TAG: ${{ github.sha }}
REF_NAME: ${{ github.ref_name }}
ACTOR: ${{ github.actor }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REGISTRY_AUTH_FILE: ${{ runner.temp }}/auth.json
run: |
docker build \
-t ghcr.io/pluralkit/dashboard-v2:${{ env.BRANCH_NAME }} \
-t ghcr.io/pluralkit/dashboard-v2:${{ github.sha }} \
-t ghcr.io/pluralkit/dashboard-v2:latest \
--build-arg base_api_url=https://api.pluralkit.me \
--push \
.
ci/build-push-images.sh
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
build
.svelte-kit
package
.direnv
.envrc
.env
.env.*
!.env.example
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Contributing
This repository is part of [PluralKit](https://github.com/PluralKit). Contributing guidelines can be found in the [main repo](https://github.com/PluralKit/PluralKit/blob/HEAD/CONTRIBUTING.md)
619 changes: 619 additions & 0 deletions COPYING

Large diffs are not rendered by default.

28 changes: 0 additions & 28 deletions Dockerfile

This file was deleted.

19 changes: 4 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
This the SvelteKit rewrite of [PluralKit's dashboard](https://github.com/PluralKit/PluralKit/tree/main/dashboard). It uses [svelte 5](https://svelte-5-preview.vercel.app/).
# PluralKit Web
This repo is home to web-based applications for PluralKit.

## Development
Developing the dashboard requires [node.js v20](https://nodejs.org/en) and [pnpm](https://pnpm.io/).

Create a .env file in the repository root with the following variables
- `PUBLIC_BASE_API_URL`: the default base API url (not ending in a `/`)
- `PUBLIC_REPOSITORY_URL`: url of the git repository (use https://github.com/PluralKit/dashboard or your fork)
Developing any of the apps in this repo requires at least [node.js v20](https://nodejs.org/en) and [pnpm](https://pnpm.io/).
A Nix flake is provided with a development environment: `nix develop .`

## Building
Building can either be done using `pnpm build` or `docker build`.

Example docker build command
```
docker build -t pluralkit-dashboard \
--build-arg="base_api_url=https://api.pluralkit.me" \
--build-arg="repository_url=https://github.com/PluralKit/dashboard" \
.
```
2 changes: 2 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Security
This repository is part of [PluralKit](https://github.com/PluralKit). Security guidelines can be found in the [main repo](https://github.com/PluralKit/PluralKit/blob/HEAD/SECURITY.md)
5 changes: 5 additions & 0 deletions apps/dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This the SvelteKit rewrite of PluralKit's dashboard. It uses [svelte 5](https://svelte.dev/).

## Development

## Building
49 changes: 49 additions & 0 deletions apps/dashboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"name": "@pluralkit-web/dashboard",
"version": "0.0.1",
"private": true,
"type": "module",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
},
"dependencies": {
"@pluralkit-web/ui": "workspace:*",
"highlight.js": "^11.11.1"
},
"devDependencies": {
"@pluralkit-web/config": "workspace:*",
"@sveltejs/adapter-node": "^5.5.7",
"@sveltejs/kit": "^2.69.1",
"@sveltejs/vite-plugin-svelte": "6.2.1",
"@tabler/icons-svelte": "^3.44.0",
"@tailwindcss/postcss": "^4.3.2",
"@types/node": "^25.9.4",
"@types/nprogress": "^0.2.3",
"caniuse-lite": "^1.0.30001800",
"discord-markdown": "github:Draconizations/discord-markdown#f40d97795f2c8913f6e621daae375d6973fefd63",
"js-base64": "^3.8.0",
"magic-string": "^0.30.21",
"moment": "^2.30.1",
"nprogress": "^0.2.0",
"postcss": "^8.5.16",
"sass": "^1.101.0",
"svelecte": "5.3.0",
"svelte": "5.56.4",
"svelte-check": "^4.7.1",
"svelte-dnd-action": "^0.9.70",
"svelte-textarea-autoresize": "^1.0.0",
"tailwindcss": "^3.4.19",
"tslib": "^2.8.1",
"typescript": "^5.9.3",
"vite": "^7.3.6"
},
"overrides": {
"@rgossiaux/svelte-headlessui": {
"svelte": "$svelte"
}
}
}
1 change: 1 addition & 0 deletions apps/dashboard/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "@pluralkit-web/config/postcss"
2 changes: 1 addition & 1 deletion src/api/index.ts → apps/dashboard/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ async function parseError(resp: Response, reject: (reason: any) => void) {
if (resp.headers.get("content-type")?.includes("application/json")) {
let body = await resp.json()

;(err.message = body.message), (err.data = body)
;((err.message = body.message), (err.data = body))
}

reject(err)
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions src/app.d.ts → apps/dashboard/src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import type { ApiClient } from "$api"

declare const __COMMIT_HASH__: string

// for information about these interfaces
declare global {
namespace App {
Expand Down
1 change: 0 additions & 1 deletion src/app.html → apps/dashboard/src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<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>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
<script lang="ts">
import { dash } from "$lib/dash/dash.svelte"
import {
IconPaint,
IconLayout,
IconAmbulance,
IconSettings,
} from "@tabler/icons-svelte"
import { IconPaint, IconLayout, IconAmbulance, IconSettings } from "@tabler/icons-svelte"

let { hide = false } = $props()
let system = dash.user
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import Spinny from "$components/Spinny.svelte"
import { Spinny } from "@pluralkit-web/ui"

export let htmlPromise: Promise<string> = Promise.resolve("")
</script>
Expand Down
59 changes: 59 additions & 0 deletions apps/dashboard/src/components/dash/IconImage.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script lang="ts">
import type { Group, Member, System } from "$api/types"
import { browser } from "$app/environment"
import discord_icon from "@pluralkit-web/ui/assets/discord_icon.svg"

let {
type,
item,
}: {
type: "member" | "group" | "system"
item: Member | Group | System
} = $props()
</script>

{#if browser}
{#if type === "member"}
{#if (item as Member).webhook_avatar_url || (item as Member).avatar_url}
<div class="avatar w-14 h-14">
<img
class="object-cover rounded-full item-icon"
src={(item as Member).webhook_avatar_url || (item as Member).avatar_url || ""}
alt={`${item.name}'s avatar'`}
/>
</div>
{:else}
<div class="avatar w-14 h-14">
<img class="object-cover rounded-full item-icon" src={discord_icon} alt="Default avatar" />
</div>
{/if}
{:else if type === "system"}
{#if (item as System).avatar_url}
<div class="avatar w-14 h-14">
<img
class="object-cover rounded-full item-icon"
src={(item as System).avatar_url || ""}
alt={`Avatar of ${item.name ?? "this system"}`}
/>
</div>
{:else}
<div class="avatar w-14 h-14">
<img class="object-cover rounded-full item-icon" src={discord_icon} alt="Default avatar" />
</div>
{/if}
{:else if type === "group"}
{#if (item as Group).icon}
<div class="avatar w-14 h-14">
<img
class="object-cover rounded-full item-icon"
src={(item as Group).icon || ""}
alt={`${item.name}'s icon'`}
/>
</div>
{:else}
<div class="avatar w-14 h-14">
<img class="object-cover rounded-full item-icon" src={discord_icon} alt="Default avatar" />
</div>
{/if}
{/if}
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -115,24 +115,47 @@
</div>
<div class="flex flex-col p-2 rounded-b-lg tab-contents lg:p-4 bg-base-200">
{#if type === "member"}
{#if openedOnce}
<MemberView {privacyMode} {memberList} {groupList} bind:member={item} {tab} open={isOpen} {asPage} />
<MemberInfo {privacyMode} {memberList} {groupList} bind:member={item} {tab} {asPage} />
{#if tabbedOnce}
<MemberGroups {privacyMode} {memberList} {groupList} bind:member={item} {tab} {asPage} />
{/if}
{#if openedOnce}
<MemberView
{privacyMode}
{memberList}
{groupList}
bind:member={item}
{tab}
open={isOpen}
{asPage}
/>
<MemberInfo {privacyMode} {memberList} {groupList} bind:member={item} {tab} {asPage} />
{#if tabbedOnce}
<MemberGroups
{privacyMode}
{memberList}
{groupList}
bind:member={item}
{tab}
{asPage}
/>
{/if}
{/if}
{:else if type === "system"}
<SystemView bind:system={item} {tab} open={isOpen} {asPage} />
<SystemInfo bind:system={item} {tab} {asPage} />
<SystemView bind:system={item} {tab} open={isOpen} {asPage} />
<SystemInfo bind:system={item} {tab} {asPage} />
{:else if type === "group"}
{#if openedOnce}
<GroupView {memberList} {privacyMode} list={groupList} bind:group={item} {tab} open={isOpen} {asPage} />
<GroupInfo {memberList} {privacyMode} list={groupList} bind:group={item} {tab} {asPage} />
{#if tabbedOnce}
<GroupMembers {privacyMode} {memberList} {groupList} bind:group={item} {tab} {asPage} />
{/if}
{#if openedOnce}
<GroupView
{memberList}
{privacyMode}
list={groupList}
bind:group={item}
{tab}
open={isOpen}
{asPage}
/>
<GroupInfo {memberList} {privacyMode} list={groupList} bind:group={item} {tab} {asPage} />
{#if tabbedOnce}
<GroupMembers {privacyMode} {memberList} {groupList} bind:group={item} {tab} {asPage} />
{/if}
{/if}
{/if}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
list = $bindable(),
}: {
wide: boolean
list: DashList<Member|Group>
list: DashList<Member | Group>
} = $props()
</script>

Expand Down Expand Up @@ -41,7 +41,7 @@
class="input input-sm input-bordered join-item flex-1"
id="member-list-view"
bind:value={list.settings.viewType}
onchange={() => list.settings.itemsPerPage = list.settings.view.defaultItemsPerPage}
onchange={() => (list.settings.itemsPerPage = list.settings.view.defaultItemsPerPage)}
>
<option value={dash.settings.display?.keepOpen === true ? ViewType.OPEN : ViewType.COLLAPSE}
>List</option
Expand All @@ -50,4 +50,4 @@
<option value={ViewType.TINY}>Tiny</option>
</select>
</div>
</div>
</div>
Loading