made it working in talespire
This commit is contained in:
@@ -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>
|
||||
|
@@ -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
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
23
public/manifest.json
Normal 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"]
|
||||
}
|
||||
}
|
@@ -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 |
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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} />
|
||||
|
18
src/components/ThemeToggle.tsx
Normal file
18
src/components/ThemeToggle.tsx
Normal 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;
|
41
src/contexts/ThemeContext.tsx
Normal file
41
src/contexts/ThemeContext.tsx
Normal 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>
|
||||
);
|
||||
};
|
@@ -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'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
Reference in New Issue
Block a user