Skip to content
Closed
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
9 changes: 8 additions & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/copilot.data.migration.agent.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/copilot.data.migration.ask.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/copilot.data.migration.edit.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}
53 changes: 33 additions & 20 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

plugins {
java
id("com.gradleup.shadow") version "9.3.1"
id("org.springframework.boot") version "4.0.2"
id("io.spring.dependency-management") version "1.1.7"
}

group = "dev.robothanzo.werewolf"
Expand All @@ -15,33 +14,47 @@ repositories {
}

dependencies {
// Spring Boot
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-data-mongodb")
implementation("org.springframework.boot:spring-boot-starter-websocket")
implementation("org.springframework.boot:spring-boot-starter-security")
implementation("org.mongodb:mongodb-spring-session:4.0.0-rc1")

// Discord
implementation("net.dv8tion:JDA:6.3.0")
implementation("club.minnced:discord-webhooks:0.8.4")
implementation("org.mongodb:mongodb-driver-sync:5.1.3")
implementation("ch.qos.logback:logback-classic:1.5.7")
implementation("com.github.RobotHanzo:JDAInteractions:v0.1.4")
implementation("dev.arbjerg:lavaplayer:2.2.1")
compileOnly("org.projectlombok:lombok:1.18.34")
annotationProcessor("org.projectlombok:lombok:1.18.34")
implementation("com.github.Mokulu:discord-oauth2-api:1.0.4")

// JDA Audio supplements
implementation("dev.arbjerg:lavaplayer:2.2.6")
implementation("club.minnced:jdave-api:0.1.5")
implementation("club.minnced:jdave-native-linux-x86-64:0.1.5")
implementation("club.minnced:jdave-native-linux-aarch64:0.1.5")
implementation("club.minnced:jdave-native-win-x86-64:0.1.5")

compileOnly("org.projectlombok:lombok:1.18.42")
annotationProcessor("org.projectlombok:lombok:1.18.42")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks {
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(21)
}
configurations.all {
exclude(group = "org.slf4j", module = "slf4j-reload4j")
}

jar {
manifest {
attributes["Main-Class"] = "dev.robothanzo.werewolf.WerewolfHelper"
tasks {
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(25))
}
}

named<ShadowJar>("shadowJar") {
archiveClassifier.set("")
compileJava {
options.encoding = Charsets.UTF_8.name()
}

build {
dependsOn(shadowJar)
bootJar {
mainClass.set("dev.robothanzo.werewolf.WerewolfApplication")
}
}
24 changes: 24 additions & 0 deletions src/dashboard/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
83 changes: 83 additions & 0 deletions src/dashboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Werewolf Helper Dashboard

This is the admin dashboard frontend for the Werewolf Discord Bot. It allows admins to view the game state in real-time
and execute commands.
*Made by vibe-coding using Google Antigravity, I take no credit for the design, and no responsibility for any issues
that may arise.*

## Prerequisites

- [Node.js](https://nodejs.org/) (Version 16 or higher)
- [Yarn](https://yarnpkg.com/)

## Installation

1. Clone the repository (or download the source).
2. Install dependencies:

```bash
yarn install
```

## Development

To start the local development server:

```bash
yarn dev
```

The application will be available at `http://localhost:5173`.

## Production Build

To build the application for production:

```bash
yarn build
```

The output will be in the `dist/` directory. You can serve this static directory using any web server (Nginx, Apache,
Vercel, Netlify, etc.).

### Preview Production Build

To preview the production build locally:

```bash
yarn preview
```

## Discord OAuth Configuration

The dashboard uses Discord OAuth2 for authentication. To set this up:

1. **Create a Discord Application**:
- Go to the [Discord Developer Portal](https://discord.com/developers/applications)
- Click **New Application** and give it a name
- Navigate to the **OAuth2** section

2. **Configure Redirect URIs**:
- Add your redirect URI (e.g., `http://localhost:5173/auth/callback` for local development)
- For production, use your deployed dashboard URL (e.g., `https://yourdomain.com/auth/callback`)

3. **Get Your Credentials**:
- Copy your **Client ID** from the General Information page
- Generate a **Client Secret** from the OAuth2 page

4. **Set Environment Variables**:
- The backend requires the following environment variables:
```bash
DISCORD_CLIENT_ID=your_client_id_here
DISCORD_CLIENT_SECRET=your_client_secret_here
DISCORD_REDIRECT_URI=http://localhost:5173/auth/callback
DASHBOARD_URL=http://localhost:5173
```

5. **Bot Permissions**:
- The OAuth2 application needs the following scopes: `identify`, `guilds`, `guilds.members.read`

## Integration

Refer to the "Integration Guide" within the dashboard application for details on how to connect this frontend to your
Java Discord Bot backend.
25 changes: 25 additions & 0 deletions src/dashboard/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>狼人殺助手 - 管理員儀表板</title>
<script type="importmap">
{
"imports": {
"react": "https://esm.sh/react@^19.2.4",
"react-dom/": "https://esm.sh/react-dom@^19.2.4/",
"lucide-react": "https://esm.sh/lucide-react@^0.563.0",
"react/": "https://esm.sh/react@^19.2.4/",
"@vitejs/plugin-react": "https://esm.sh/@vitejs/plugin-react@^5.1.2",
"vite": "https://esm.sh/vite@^7.3.1"
}
}
</script>
<link href="/src/index.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script src="/src/main.tsx" type="module"></script>
</body>
</html>
5 changes: 5 additions & 0 deletions src/dashboard/metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"description": "Generated by Gemini.",
"requestFramePermissions": [],
"name": "App"
}
28 changes: 28 additions & 0 deletions src/dashboard/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "werewolf-helper-dashboard",
"private": true,
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"lucide-react": "^0.344.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^7.13.0"
},
"devDependencies": {
"@types/node": "^25.2.0",
"@types/react": "^18.2.64",
"@types/react-dom": "^18.2.21",
"@vitejs/plugin-react": "^4.2.1",
"autoprefixer": "^10.4.18",
"postcss": "^8.4.35",
"tailwindcss": "^3.4.1",
"typescript": "^5.2.2",
"vite": "^5.1.6"
}
}
6 changes: 6 additions & 0 deletions src/dashboard/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
20 changes: 20 additions & 0 deletions src/dashboard/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {Route, Routes} from 'react-router-dom';
import {AuthCallback} from '@/features/auth/components/AuthCallback';
import {AccessDenied} from '@/features/auth/components/AccessDenied';
import {LoginPage} from '@/features/auth/pages/LoginPage';
import {ServerSelectionPage} from '@/features/server-selection/pages/ServerSelectionPage';
import {Dashboard} from '@/features/game/components/Dashboard';

const App = () => {
return (
<Routes>
<Route path="/login" element={<LoginPage/>}/>
<Route path="/auth/callback" element={<AuthCallback/>}/>
<Route path="/access-denied" element={<AccessDenied/>}/>
<Route path="/" element={<ServerSelectionPage/>}/>
<Route path="/server/:guildId/*" element={<Dashboard/>}/>
</Routes>
);
};

export default App;
Loading
Loading