made it working in talespire

This commit is contained in:
2025-06-15 17:28:26 +02:00
parent b0bd4282c6
commit d8bad758f5
12 changed files with 159 additions and 99 deletions

View File

@@ -2,7 +2,7 @@
<html lang="de">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<link rel="icon" type="image/svg+xml" href="/icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>DSA 5e Charakter Bogen</title>
</head>

View File

@@ -1,29 +0,0 @@
{
"name": "DSA 5e Character Sheet",
"id": "dsa5e-character-sheet",
"version": "1.0.0",
"description": "Ein interaktiver DSA 5e Charakterbogen mit Optolith JSON Support",
"author": "Matthias Puchstein",
"entryPoint": "index.html",
"extras": [
"colorStyles"
],
"capabilities": [
"chat",
"dice"
],
"minTaleSpireVersion": "1.0.0",
"tags": [
"character-sheet",
"dsa",
"das-schwarze-auge",
"optolith",
"dsa5e"
],
"icon": "icon.svg",
"screenshots": [
"screenshot1.png"
],
"website": "https://gitea.puchstein.bayern/s0wlz_talespire_symbiotes/dsa5e_character_sheet",
"license": "GPL-3"
}

BIN
public/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 495 KiB

23
public/manifest.json Normal file
View File

@@ -0,0 +1,23 @@
{
"manifestVersion": 1,
"name": "DSA 5e Character Sheet",
"entryPoint": "/index.html",
"summary": "Ein interaktiver DSA 5e Charakterbogen mit Optolith JSON Support",
"version": "1.0.0",
"license": "GPL-3",
"about": {
"website": "https://gitea.puchstein.bayern/s0wlz_talespire_symbiotes/dsa5e_character_sheet",
"authors": ["Matthias Puchstein"]
},
"api": {
"version": "0.1",
"initTimeout": 10
},
"icons": {
"64x64": "/icon.png"
},
"environment": {
"capabilities": ["chat", "dice"],
"extras": ["colorStyles"]
}
}

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,11 +1,14 @@
import CharacterSheet from './components/CharacterSheet';
import './App.css';
import { ThemeProvider } from './contexts/ThemeContext';
function App() {
return (
<div className="App">
<CharacterSheet />
</div>
<ThemeProvider>
<div className="App">
<CharacterSheet />
</div>
</ThemeProvider>
);
}

View File

@@ -489,4 +489,55 @@ button:active {
font-size: 2rem;
text-align: center;
}
}
}
/* Dark Theme (Default) */
:root[data-theme='dark'] {
--ts-color-surface: #1a1a1a;
--ts-color-on-surface: #e0e0e0;
--ts-color-surface-variant: #2d2d2d;
--ts-color-primary: #9d4edd;
--ts-color-secondary: #7209b7;
--ts-color-outline: #404040;
--text-color: #e0e0e0;
--background-color: #121212;
--surface-color: #1a1a1a;
--surface-variant-color: #2d2d2d;
}
/* Light Theme */
:root[data-theme='light'] {
--ts-color-surface: #ffffff;
--ts-color-on-surface: #1a1a1a;
--ts-color-surface-variant: #f9f9f9;
--ts-color-primary: #7b2cbf;
--ts-color-secondary: #3a0ca3;
--ts-color-outline: #cccccc;
--text-color: #222;
--background-color: #f5f5f5;
--surface-color: #ffffff;
--surface-variant-color: #f9f9f9;
}
/* Theme Toggle Button */
.theme-toggle {
position: fixed;
top: 20px;
right: 20px;
width: 50px;
height: 50px;
border-radius: 25px;
background: var(--ts-color-primary);
color: white;
border: none;
font-size: 1.5rem;
cursor: pointer;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
transition: all 0.3s ease;
z-index: 1000;
}
.theme-toggle:hover {
transform: scale(1.1);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
}

View File

@@ -5,6 +5,8 @@ import Attributes from './Attributes';
import Skills from './Skills';
import CombatValues from './CombatValues';
import './CharacterSheet.css';
import ThemeToggle from "./ThemeToggle.tsx";
import iconUrl from '/icon.png';
const initialCharacter: DSACharacter = {
id: crypto.randomUUID(),
@@ -40,8 +42,9 @@ const CharacterSheet: React.FC = () => {
return (
<div className="character-sheet">
<ThemeToggle />
<header className="character-sheet-header">
<img src="/icon.svg" alt="DSA 5e Logo" className="character-sheet-icon" />
<img src={iconUrl} alt="DSA 5e Logo" className="character-sheet-icon" />
<h1>DSA 5 Character Sheet</h1>
</header>
<BasicInfo character={character} setCharacter={setCharacter} />

View File

@@ -0,0 +1,18 @@
import React from 'react';
import { useTheme } from '../contexts/ThemeContext';
const ThemeToggle: React.FC = () => {
const { theme, toggleTheme } = useTheme();
return (
<button
className="theme-toggle"
onClick={toggleTheme}
title={`Switch to ${theme === 'light' ? 'dark' : 'light'} mode`}
>
{theme === 'light' ? '🌙' : '☀️'}
</button>
);
};
export default ThemeToggle;

View File

@@ -0,0 +1,41 @@
import React, { createContext, useContext, useEffect, useState } from 'react';
type Theme = 'light' | 'dark';
interface ThemeContextType {
theme: Theme;
toggleTheme: () => void;
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
export const useTheme = () => {
const context = useContext(ThemeContext);
if (!context) {
throw new Error('useTheme must be used within ThemeProvider');
}
return context;
};
export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [theme, setTheme] = useState<Theme>(() => {
// Aus localStorage laden oder Default zu dark (passt zu TaleSpire)
const saved = localStorage.getItem('dsa5e-theme');
return (saved as Theme) || 'dark';
});
useEffect(() => {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('dsa5e-theme', theme);
}, [theme]);
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};

View File

@@ -1,7 +1,17 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
})
base: './',
build: {
minify: 'esbuild', // ← Statt terser
rollupOptions: {
output: {
assetFileNames: 'assets/[name].[ext]',
chunkFileNames: 'assets/[name].js',
entryFileNames: 'assets/[name].js'
}
}
}
});