diff --git a/backend/VERSION.md b/backend/VERSION.md new file mode 100644 index 0000000..e1e9cf4 --- /dev/null +++ b/backend/VERSION.md @@ -0,0 +1,70 @@ +# Version Management + +## Current Version: 0.1.30 + +The backend version is managed in `/backend/config/version.go`. + +## Updating the Version + +To update the application version: + +1. Edit `/backend/config/version.go` +2. Change the `Version` constant: + ```go + const Version = "0.1.31" // Update this + ``` + +## Git Commit Information + +The git commit hash is automatically detected at runtime from: + +1. `GIT_COMMIT` environment variable (preferred for Docker) +2. Git command output (works in development) +3. Falls back to "unknown" if neither is available + +## Setting Git Commit in Docker + +### Development Environment + +Add to `docker/.env`: +```bash +GIT_COMMIT=$(git rev-parse --short HEAD) +``` + +Then restart the container: +```bash +cd docker +docker-compose -f docker-compose.dev.yml up -d backend-dev +``` + +### Production Build + +Use build-time variable: +```bash +docker build --build-arg GIT_COMMIT=$(git rev-parse --short HEAD) . +``` + +Or set in docker-compose.yml: +```yaml +environment: + - GIT_COMMIT=${GIT_COMMIT:-unknown} +``` + +## API Endpoints + +- **Public**: `GET /api/public/version` (no authentication) +- **Protected**: `GET /api/version` (requires JWT token) + +Both return: +```json +{ + "version": "0.1.30", + "gitCommit": "d0c177b" +} +``` + +## Frontend Integration + +The landing page automatically fetches version information from `/api/public/version` and displays it. + +To see the version in the frontend, visit: http://localhost:5173 diff --git a/backend/cmd/main.go b/backend/cmd/main.go index ca6de1b..fe775e3 100644 --- a/backend/cmd/main.go +++ b/backend/cmd/main.go @@ -82,9 +82,11 @@ func main() { importer.RegisterRoutes(protected) pdfrender.RegisterRoutes(protected) transfer.RegisterRoutes(protected) + config.RegisterRoutes(protected) // Register public routes (no authentication) pdfrender.RegisterPublicRoutes(r) + config.RegisterPublicRoutes(r) logger.Info("API-Routen erfolgreich registriert") diff --git a/backend/config/handlers.go b/backend/config/handlers.go new file mode 100644 index 0000000..ba75953 --- /dev/null +++ b/backend/config/handlers.go @@ -0,0 +1,10 @@ +package config + +import ( + "github.com/gin-gonic/gin" +) + +// Versionsinfo returns version and git commit information +func Versionsinfo(c *gin.Context) { + c.JSON(200, GetInfo()) +} diff --git a/backend/config/routes.go b/backend/config/routes.go new file mode 100644 index 0000000..d09a4fe --- /dev/null +++ b/backend/config/routes.go @@ -0,0 +1,15 @@ +package config + +import "github.com/gin-gonic/gin" + +// RegisterRoutes registers config-related routes (protected) +func RegisterRoutes(r *gin.RouterGroup) { + r.GET("/version", Versionsinfo) +} + +// RegisterPublicRoutes registers public config routes (no auth required) +func RegisterPublicRoutes(r *gin.Engine) { + // Public version endpoint - no authentication required + public := r.Group("/api/public") + public.GET("/version", Versionsinfo) +} diff --git a/backend/config/version.go b/backend/config/version.go new file mode 100644 index 0000000..f22469e --- /dev/null +++ b/backend/config/version.go @@ -0,0 +1,60 @@ +package config + +// Version is the application version +const Version = "0.1.30" + +var ( + // GitCommit will be set by build flags or detected at runtime + GitCommit = "unknown" +) + +// init detects git commit if not set during build +func init() { + /* + if GitCommit == "" { + // Try environment variable first + if envCommit := os.Getenv("GIT_COMMIT"); envCommit != "" { + GitCommit = envCommit + } else { + // Try to detect from git command + GitCommit = detectGitCommit() + } + } + */ +} + +/* +// detectGitCommit tries to get the current git commit hash +func detectGitCommit() string { + cmd := exec.Command("git", "rev-parse", "--short", "HEAD") + output, err := cmd.Output() + if err != nil { + return "unknown" + } + return strings.TrimSpace(string(output)) +} +*/ +// GetVersion returns the current application version +func GetVersion() string { + return Version +} + +/* +// GetGitCommit returns the git commit hash +func GetGitCommit() string { + return GitCommit +} +*/ +// Info contains version information +type Info struct { + Version string `json:"version"` + GitCommit string `json:"gitCommit"` +} + +// GetInfo returns version information as a struct +func GetInfo() Info { + return Info{ + Version: Version, + GitCommit: GitCommit, + } +} diff --git a/backend/config/version_test.go b/backend/config/version_test.go new file mode 100644 index 0000000..62f702a --- /dev/null +++ b/backend/config/version_test.go @@ -0,0 +1,43 @@ +package config + +import ( + "testing" +) + +func TestGetVersion(t *testing.T) { + version := GetVersion() + if version == "" { + t.Error("Version should not be empty") + } + if version != Version { + t.Errorf("Expected version %s, got %s", Version, version) + } +} + +/* + func TestGetGitCommit(t *testing.T) { + commit := GetGitCommit() + if commit == "" { + t.Error("GitCommit should not be empty") + } + // Should be either "unknown" or a valid git hash + if commit != "unknown" && len(commit) < 7 { + t.Errorf("Invalid git commit format: %s", commit) + } + } +*/ +func TestGetInfo(t *testing.T) { + info := GetInfo() + + if info.Version == "" { + t.Error("Info.Version should not be empty") + } + + if info.GitCommit == "" { + t.Error("Info.GitCommit should not be empty") + } + + if info.Version != Version { + t.Errorf("Expected info.Version %s, got %s", Version, info.Version) + } +} diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index f13867b..1a2d930 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -14,6 +14,7 @@ services: - API_PORT=${API_PORT:-8180} - TEMPLATES_DIR=${TEMPLATES_DIR:-./templatesx} - EXPORT_TEMP_DIR=${EXPORT_TEMP_DIR:-./export_tempx} + - GIT_COMMIT=${GIT_COMMIT:-unknown} depends_on: mariadb-dev: condition: service_healthy diff --git a/docker/start-dev.sh b/docker/start-dev.sh index 8aaf104..255c0b3 100755 --- a/docker/start-dev.sh +++ b/docker/start-dev.sh @@ -11,6 +11,10 @@ fi # Gehe ins Docker-Verzeichnis cd "$(dirname "$0")" +# Get current git commit +export GIT_COMMIT=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") +echo "📝 Git Commit: $GIT_COMMIT" + echo "📦 Building and starting development containers..." # Stoppe vorhandene Container diff --git a/frontend/VERSION.md b/frontend/VERSION.md new file mode 100644 index 0000000..b4835d2 --- /dev/null +++ b/frontend/VERSION.md @@ -0,0 +1,87 @@ +# Frontend Version Management + +## Current Version: 0.1.30 + +The frontend version is managed independently from the backend. + +## Version Locations + +1. **Primary source**: `/frontend/src/version.js` + - Contains the VERSION constant + - Exports version info functions + +2. **Package metadata**: `/frontend/package.json` + - Standard npm version field + - Should match version.js + +## Updating the Version + +### Option 1: Using the update script (Recommended) +```bash +# Updates both backend and frontend +./scripts/update-version.sh 0.1.31 +``` + +### Option 2: Manual update +Edit `/frontend/src/version.js`: +```javascript +export const VERSION = '0.1.31' // Update this +``` + +And `/frontend/package.json`: +```json +{ + "version": "0.1.31" // Update this +} +``` + +## Git Commit Information + +The git commit is injected via environment variable: +- Set `VITE_GIT_COMMIT` in `.env` or at build time +- Falls back to "unknown" if not set + +Example `.env`: +```bash +VITE_GIT_COMMIT=d0c177b +``` + +## Usage in Components + +```javascript +import { getVersion, getGitCommit, getVersionInfo } from '@/version' + +// Get version string +const version = getVersion() // "0.1.30" + +// Get git commit +const commit = getGitCommit() // "d0c177b" or "unknown" + +// Get full info object +const info = getVersionInfo() // { version: "0.1.30", gitCommit: "d0c177b" } +``` + +## Landing Page Display + +The landing page shows both: +- **Frontend Version**: From `/frontend/src/version.js` +- **Backend Version**: Fetched from `/api/public/version` + +This allows users to see if frontend and backend are in sync. + +## Build-time Version Injection + +To inject git commit at build time, update `vite.config.js`: + +```javascript +import { defineConfig } from 'vite' +import { execSync } from 'child_process' + +const gitCommit = execSync('git rev-parse --short HEAD').toString().trim() + +export default defineConfig({ + define: { + 'import.meta.env.VITE_GIT_COMMIT': JSON.stringify(gitCommit) + } +}) +``` diff --git a/frontend/package.json b/frontend/package.json index d83539a..faae845 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { - "name": "my-app", - "version": "0.0.0", + "name": "bamort-frontend", + "version": "0.1.21", "private": true, "type": "module", "scripts": { diff --git a/frontend/public/Abgrund-DD2.jpg b/frontend/public/Abgrund-DD2.jpg new file mode 100644 index 0000000..adfde2b Binary files /dev/null and b/frontend/public/Abgrund-DD2.jpg differ diff --git a/frontend/public/Drache.png b/frontend/public/Drache.png new file mode 100644 index 0000000..aafd311 Binary files /dev/null and b/frontend/public/Drache.png differ diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css index 473d551..9352e08 100644 --- a/frontend/src/assets/main.css +++ b/frontend/src/assets/main.css @@ -1467,4 +1467,2421 @@ a, .spells-grid, .available-spells .spells-grid { grid-template-columns: repeat(5, 1fr); } +} + +/* ======================================== + CONSOLIDATED MODAL STYLES + ======================================== */ + +/* Modal overlay - covers entire viewport */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; +} + +/* Modal content container */ +.modal-content { + background: white; + border-radius: 8px; + width: 90%; + max-width: 500px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + display: flex; + flex-direction: column; + max-height: 80vh; + animation: modalSlideIn 0.3s ease-out; +} + +/* Modal header */ +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20px; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; +} + +.modal-header h3 { + margin: 0; + color: #333; + font-size: 1.25rem; +} + +/* Modal body */ +.modal-body { + padding: 20px; + overflow-y: auto; + flex: 1; + min-height: 0; +} + +/* Modal footer */ +.modal-footer { + display: flex; + justify-content: flex-end; + gap: 10px; + padding: 20px; + border-top: 1px solid #dee2e6; + flex-shrink: 0; +} + +/* Modal actions (alternative to footer) */ +.modal-actions { + display: flex; + justify-content: flex-end; + gap: 10px; + margin-top: 20px; + padding-top: 15px; + border-top: 1px solid #eee; +} + +/* Close button */ +.close-button { + background: none; + border: none; + font-size: 1.5rem; + color: #999; + cursor: pointer; + padding: 0; + width: 30px; + height: 30px; + display: flex; + align-items: center; + justify-content: center; + transition: color 0.2s ease; +} + +.close-button:hover { + color: #333; +} + +/* Modal slide in animation */ +@keyframes modalSlideIn { + from { + opacity: 0; + transform: scale(0.9) translateY(-20px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } +} + +/* ======================================== + CONSOLIDATED BUTTON STYLES + ======================================== */ + +/* Cancel button */ +.btn-cancel { + padding: 10px 20px; + border: 1px solid #dee2e6; + border-radius: 6px; + background: #f8f9fa; + color: #495057; + cursor: pointer; + font-weight: 500; + transition: all 0.2s ease; +} + +.btn-cancel:hover { + background: #e9ecef; + border-color: #adb5bd; +} + +/* Confirm button (success/submit) */ +.btn-confirm { + padding: 10px 20px; + border: none; + border-radius: 6px; + background: #1da766; + color: white; + cursor: pointer; + font-weight: 600; + transition: all 0.2s ease; +} + +.btn-confirm:hover:not(:disabled) { + background: #16a085; +} + +.btn-confirm:disabled { + background: #ccc; + cursor: not-allowed; + opacity: 0.6; +} + +/* Export button */ +.btn-export { + padding: 10px 20px; + border: 1px solid #007bff; + border-radius: 6px; + background: #007bff; + color: white; + cursor: pointer; + font-weight: 500; + transition: all 0.2s ease; +} + +.btn-export:hover:not(:disabled) { + background: #0056b3; + border-color: #0056b3; +} + +.btn-export:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +/* Small export button with icon */ +.export-button-small { + width: 40px; + height: 40px; + padding: 0; + border: 1px solid #007bff; + border-radius: 8px; + background: #007bff; + color: white; + font-size: 1.2rem; + cursor: pointer; + transition: all 0.2s ease; + flex-shrink: 0; +} + +.export-button-small:hover { + background: #0056b3; + border-color: #0056b3; + transform: scale(1.05); +} + +/* Delete button */ +.btn-delete { + background: none; + border: none; + cursor: pointer; + font-size: 1.2rem; + padding: 4px 8px; + transition: transform 0.2s ease; + color: #dc3545; +} + +.btn-delete:hover { + transform: scale(1.2); +} + +/* Edit button */ +.btn-edit { + background: none; + border: none; + cursor: pointer; + font-size: 1.2rem; + padding: 4px 8px; + transition: transform 0.2s ease; + color: #007bff; +} + +.btn-edit:hover { + transform: scale(1.2); +} + +/* Add button */ +.btn-add, +.btn-add-equipment, +.btn-add-weapon, +.btn-add-inline, +.btn-add-spell { + padding: 8px 16px; + background: #1da766; + color: white; + border: none; + border-radius: 6px; + cursor: pointer; + font-weight: bold; + transition: background 0.2s ease; +} + +.btn-add:hover, +.btn-add-equipment:hover, +.btn-add-weapon:hover, +.btn-add-inline:hover, +.btn-add-spell:hover { + background: #16a085; +} + +/* Action button small (for table actions) */ +.btn-action { + background: none; + border: none; + cursor: pointer; + padding: 4px 8px; + transition: all 0.2s ease; + font-size: 1rem; +} + +.btn-action:hover { + transform: scale(1.1); +} + +.icon { + font-size: 14px; +} + +.btn-improve-small { + font-size: 1.2rem; +} + +/* ======================================== + CONSOLIDATED FORM STYLES + ======================================== */ + +/* Form group container */ +.form-group { + margin-bottom: 20px; +} + +.form-group label { + display: block; + margin-bottom: 8px; + font-weight: 500; + color: #495057; + font-size: 0.95rem; +} + +/* Form control (input, select, textarea) */ +.form-control, +.template-select, +.form-group input[type="text"], +.form-group input[type="email"], +.form-group input[type="password"], +.form-group input[type="number"], +.form-group select, +.form-group textarea { + width: 100%; + padding: 10px 12px; + border: 1px solid #dee2e6; + border-radius: 6px; + background: white; + color: #495057; + font-size: 0.95rem; + box-sizing: border-box; + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.form-control:focus, +.template-select:focus, +.form-group input:focus, +.form-group select:focus, +.form-group textarea:focus { + outline: none; + border-color: #007bff; + box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); +} + +.form-control:disabled, +.template-select:disabled, +.form-group input:disabled, +.form-group select:disabled, +.form-group textarea:disabled { + opacity: 0.6; + cursor: not-allowed; + background: #e9ecef; +} + +/* Form row */ +.form-row { + display: flex; + gap: 15px; + align-items: flex-start; + margin-bottom: 15px; +} + +@media (max-width: 768px) { + .form-row { + flex-direction: column; + } +} + +/* Checkbox label */ +.checkbox-label { + display: flex; + align-items: center; + gap: 8px; + cursor: pointer; + user-select: none; + font-weight: normal; + margin: 0; +} + +.checkbox-label input[type="checkbox"] { + width: 18px; + height: 18px; + cursor: pointer; + margin: 0; +} + +/* Help text */ +.help-text { + display: block; + margin-top: 5px; + font-size: 12px; + color: #6c757d; + font-style: italic; +} + +/* ======================================== + CONSOLIDATED LOADING INDICATORS + ======================================== */ + +/* Loading overlay (absolute positioned within container) */ +.loading-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(255, 255, 255, 0.95); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + z-index: 10; + border-radius: 8px; +} + +.loading-overlay p { + color: #007bff; + font-weight: 500; + margin: 0; +} + +/* Spinner animation */ +.spinner { + border: 4px solid #f3f3f3; + border-top: 4px solid #007bff; + border-radius: 50%; + width: 50px; + height: 50px; + animation: spin 1s linear infinite; + margin-bottom: 15px; +} + +/* Loading message (text only) */ +.loading-message { + text-align: center; + padding: 20px; + color: #6c757d; + font-style: italic; +} + +/* ======================================== + CONSOLIDATED TABLE STYLES + ======================================== */ + +/* Table header cell */ +.cd-table-header { + background-color: #1da766; + color: white; + font-weight: bold; + padding: 8px; + text-align: left; +} + +/* Empty state for tables/lists */ +.empty-state { + text-align: center; + color: #999; + font-style: italic; + padding: 2rem; +} + +.empty-state h3 { + color: #333; + margin-bottom: 10px; + font-size: 1.5rem; +} + +/* Action cell */ +.action-cell { + text-align: center; + vertical-align: middle; +} + +/* ======================================== + CONSOLIDATED HEADER/LAYOUT STYLES + ======================================== */ + +/* Header section */ +.header-section { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; + flex-wrap: wrap; + gap: 10px; +} + +/* Header content */ +.header-content { + display: flex; + align-items: center; + gap: 15px; + flex: 1; +} + +/* Character header */ +.character-header { + margin-bottom: 20px; +} + +.character-header h2 { + margin: 0; + color: #333; + font-size: 1.5rem; + border-bottom: 2px solid #007bff; + padding-bottom: 10px; + flex: 1; +} + +/* ======================================== + COMPONENT-SPECIFIC STYLES (EXTRACTED FROM COMPONENTS) + ======================================== */ + +/* SkillView - Tables Container */ +.tables-container { + display: flex; + gap: 1rem; + width: 100%; +} + +.table-wrapper-left { + flex: 6; + min-width: 0; +} + +.table-wrapper-right { + flex: 4; + min-width: 0; +} + +/* Learning Mode Controls */ +.learning-mode-controls { + display: flex; + align-items: center; + gap: 15px; +} + +.resources-display { + display: flex; + gap: 15px; + animation: slideIn 0.3s ease; +} + +.resource-item { + display: flex; + align-items: center; + gap: 5px; + padding: 6px 12px; + background: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 6px; + font-weight: bold; + color: #495057; +} + +.resource-value { + font-size: 14px; + white-space: nowrap; +} + +/* Learning Mode Buttons */ +.btn-learning-mode { + padding: 8px 16px; + border: 2px solid #1da766; + background: white; + color: #1da766; + border-radius: 6px; + cursor: pointer; + font-weight: bold; + display: flex; + align-items: center; + gap: 5px; + transition: all 0.3s ease; + position: relative; +} + +.btn-learning-mode:hover { + background: #1da766; + color: white; +} + +.btn-learning-mode.active { + background: #1da766; + color: white; +} + +.learning-actions { + display: flex; + gap: 5px; + animation: slideIn 0.3s ease; +} + +.btn-learn-new { + width: 40px; + height: 40px; + border: 2px solid #007bff; + background: white; + border-radius: 6px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + transition: all 0.2s ease; + position: relative; +} + +.btn-learn-new:hover { + background: #007bff; + color: white; +} + +.btn-improve { + width: 40px; + height: 40px; + border: 2px solid #28a745; + background: white; + border-radius: 6px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 16px; + transition: all 0.2s ease; + position: relative; +} + +.btn-improve:hover { + background: #28a745; + color: white; +} + +/* Practice Points Controls */ +.pp-cell { + padding: 4px 8px; +} + +.pp-container { + display: flex; + align-items: center; + justify-content: center; + gap: 2px; +} + +.pp-btn { + width: 20px; + height: 20px; + border: 1px solid #007bff; + background: white; + color: #007bff; + border-radius: 3px; + cursor: pointer; + font-size: 14px; + font-weight: bold; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + line-height: 1; + padding: 0; +} + +.pp-btn:hover:not(:disabled) { + background: #007bff; + color: white; +} + +.pp-btn:disabled { + border-color: #ccc; + color: #ccc; + cursor: not-allowed; + opacity: 0.5; +} + +.pp-btn-plus { + border-color: #28a745; + color: #28a745; +} + +.pp-btn-plus:hover:not(:disabled) { + background: #28a745; + color: white; +} + +.pp-btn-minus { + border-color: #dc3545; + color: #dc3545; +} + +.pp-btn-minus:hover:not(:disabled) { + background: #dc3545; + color: white; +} + +.pp-value { + min-width: 20px; + text-align: center; + font-weight: bold; + color: #495057; + font-size: 13px; +} + +/* Spell/Skill Dialog Styles */ +.modal-wide { + max-width: 700px; +} + +.current-resources { + display: flex; + gap: 15px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.resource-display-card { + display: flex; + align-items: center; + gap: 10px; + padding: 12px 16px; + background: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 8px; + flex: 1; + min-width: 160px; +} + +.resource-display-card .resource-icon { + font-size: 20px; +} + +.resource-remaining { + margin-top: 4px; +} + +.resource-remaining small { + color: #6c757d; + font-weight: normal; +} + +.text-warning { + color: #f0ad4e !important; +} + +.text-danger { + color: #d9534f !important; +} + +/* Selection Summary */ +.selection-summary { + background: #e7f3ff; + padding: 12px; + border-radius: 6px; + margin-bottom: 10px; + border-left: 4px solid #007bff; +} + +.cost-summary { + color: #28a745; + font-weight: bold; +} + +/* Learning Levels List */ +.learning-levels { + border: 1px solid #dee2e6; + border-radius: 6px; + max-height: 300px; + overflow-y: auto; +} + +.level-option { + padding: 12px 16px; + border-bottom: 1px solid #f1f1f1; + cursor: pointer; + transition: all 0.2s ease; +} + +.level-option:last-child { + border-bottom: none; +} + +.level-option:hover:not(.disabled) { + background: #f8f9fa; +} + +.level-option.selected { + background: #e7f3ff; + border-left: 4px solid #007bff; +} + +.level-option.in-sequence:not(.selected) { + background: #f0f8ff; + border-left: 2px solid #87ceeb; +} + +.level-option.disabled { + background: #f8f9fa; + color: #6c757d; + cursor: not-allowed; + opacity: 0.6; +} + +.level-header { + display: flex; + justify-content: space-between; + align-items: center; + font-weight: 500; +} + +.level-target { + color: #495057; +} + +.level-cost { + color: #28a745; + font-weight: bold; +} + +.level-option.disabled .level-cost { + color: #dc3545; +} + +.level-details { + margin-top: 4px; + color: #6c757d; +} + +/* Form Column Layouts */ +.form-col { + flex: 1; + min-width: 0; +} + +.form-col-main { + flex: 2; + min-width: 200px; +} + +.form-col-input { + flex: 1; + min-width: 140px; +} + +/* School Buttons */ +.school-buttons { + display: flex; + gap: 8px; + flex-wrap: wrap; + margin-top: 5px; +} + +.school-btn { + padding: 6px 12px; + border: 1px solid #dee2e6; + border-radius: 4px; + background: white; + color: #495057; + cursor: pointer; + font-size: 14px; + transition: all 0.2s ease; +} + +.school-btn:hover { + background: #f8f9fa; + border-color: #007bff; +} + +.school-btn.active { + background: #007bff; + color: white; + border-color: #007bff; +} + +/* Spell/Skill Container and Sections */ +.spells-container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + margin-bottom: 15px; +} + +@media (max-width: 1024px) { + .spells-container { + grid-template-columns: 1fr; + } +} + +.available-spells-section, +.learning-list-section { + min-height: 300px; +} + +.learning-item { + background: #f0f8ff !important; + border-left: 3px solid #007bff !important; +} + +.learning-item .level-header { + position: relative; +} + +.remove-btn { + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + background: #dc3545; + color: white; + border: none; + border-radius: 50%; + width: 24px; + height: 24px; + cursor: pointer; + font-size: 16px; + line-height: 1; + display: flex; + align-items: center; + justify-content: center; +} + +.remove-btn:hover { + background: #c82333; +} + +.already-selected { + opacity: 0.5; + pointer-events: none; +} + +.spell-actions-inline { + display: flex; + align-items: center; + gap: 10px; +} + +.btn-add-inline { + background: #28a745; + color: white; + border: none; + border-radius: 50%; + width: 28px; + height: 28px; + cursor: pointer; + font-size: 14px; + font-weight: bold; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + flex-shrink: 0; +} + +.btn-add-inline:hover:not(:disabled) { + background: #218838; + transform: scale(1.1); +} + +.btn-add-inline:disabled { + background: #6c757d; + cursor: not-allowed; + transform: none; +} + +.already-selected .btn-add-inline { + background: #17a2b8; +} + +/* Total Costs Display */ +.total-costs { + margin-top: 10px; + padding: 10px; + background: #e7f3ff; + border-radius: 4px; + border-left: 4px solid #007bff; +} + +/* Spell Details */ +.spell-details-section { + background: #e7f3ff; + padding: 16px; + border-radius: 6px; + margin-bottom: 10px; + border-left: 4px solid #007bff; +} + +.loading-spell-details { + text-align: center; + padding: 20px; + color: #6c757d; + font-style: italic; +} + +.spell-details-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 15px; + margin-top: 15px; +} + +.spell-detail-card { + background: white; + border: 1px solid #dee2e6; + border-radius: 6px; + padding: 12px; +} + +.spell-detail-card h4 { + margin: 0 0 10px 0; + color: #495057; + font-size: 14px; + font-weight: bold; + border-bottom: 1px solid #e9ecef; + padding-bottom: 5px; +} + +.detail-row { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 6px; + font-size: 13px; +} + +.detail-row:last-child { + margin-bottom: 0; +} + +.detail-label { + color: #6c757d; + font-weight: 500; + flex: 0 0 auto; + margin-right: 10px; +} + +.detail-value { + color: #495057; + text-align: right; + flex: 1 1 auto; +} + +.spell-description { + background: white; + border: 1px solid #dee2e6; + border-radius: 6px; + padding: 12px; + margin-top: 15px; +} + +.spell-description h4 { + margin: 0 0 8px 0; + color: #495057; + font-size: 14px; + font-weight: bold; +} + +.spell-description p { + margin: 0; + color: #495057; + font-size: 13px; + line-height: 1.4; +} + +/* Spell Actions */ +.spell-actions { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} + +.cost-info { + color: #28a745; + font-weight: bold; +} + +.btn-add-spell { + padding: 4px 12px; + background: #28a745; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 12px; + transition: background 0.2s ease; +} + +.btn-add-spell:hover:not(:disabled) { + background: #218838; +} + +.btn-add-spell:disabled { + background: #6c757d; + cursor: not-allowed; +} + +/* No Spells Message */ +.no-spells { + text-align: center; + padding: 20px; + color: #6c757d; + font-style: italic; +} + +/* Modal Content Headers */ +.modal-content h3 { + margin-top: 0; + margin-bottom: 20px; + color: #333; + border-bottom: 2px solid #1da766; + padding-bottom: 10px; +} + +/* ======================================== + SKILL LEARN DIALOG STYLES + ======================================== */ + +/* Dialog Header */ +.dialog-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20px 24px; + border-bottom: 2px solid #1da766; + background: #f8f9fa; + border-radius: 0; + flex-shrink: 0; + z-index: 10; +} + +.dialog-header h3 { + margin: 0; + color: #333; + font-size: 1.5rem; +} + +.btn-close { + background: none; + border: none; + font-size: 24px; + cursor: pointer; + color: #666; + padding: 0; + width: 30px; + height: 30px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; +} + +.btn-close:hover { + background: #e9ecef; + color: #333; +} + +/* Resources Section */ +.resources-section { + padding: 20px 24px; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + flex-shrink: 0; +} + +.resources-section h4 { + margin: 0 0 15px 0; + color: #495057; + font-size: 1.1rem; +} + +.text-info { + color: #17a2b8 !important; +} + +/* Reward Method Section */ +.reward-method-section { + margin-top: 20px; + padding-top: 20px; + border-top: 1px solid #dee2e6; +} + +.reward-method-section label { + display: block; + margin-bottom: 8px; + font-weight: 600; + color: #495057; + font-size: 0.95rem; +} + +.reward-method-section .form-select { + width: 100%; + padding: 12px 16px; + border: 2px solid #dee2e6; + border-radius: 8px; + font-size: 14px; + font-family: inherit; + transition: border-color 0.2s ease, box-shadow 0.2s ease; + box-sizing: border-box; + background: white; +} + +.reward-method-section .form-select:focus { + outline: none; + border-color: #1da766; + box-shadow: 0 0 0 3px rgba(29, 167, 102, 0.1); +} + +.reward-method-section .form-hint { + display: block; + margin-top: 4px; + font-size: 0.85rem; + color: #6c757d; + font-style: italic; +} + +/* Form Section */ +.form-section { + padding: 24px; + flex: 1; + overflow-y: auto; +} + +.form-input, +.form-select, +.form-textarea { + width: 100%; + padding: 12px 16px; + border: 2px solid #dee2e6; + border-radius: 8px; + font-size: 14px; + font-family: inherit; + transition: border-color 0.2s ease, box-shadow 0.2s ease; + box-sizing: border-box; +} + +.form-input:focus, +.form-select:focus, +.form-textarea:focus { + outline: none; + border-color: #1da766; + box-shadow: 0 0 0 3px rgba(29, 167, 102, 0.1); +} + +.form-textarea { + resize: vertical; + min-height: 80px; +} + +.form-hint { + display: block; + margin-top: 4px; + font-size: 0.85rem; + color: #6c757d; + font-style: italic; +} + +/* Costs Preview */ +.costs-preview { + padding: 20px 24px; + background: #fff3cd; + border-top: 1px solid #ffeaa7; + border-bottom: 1px solid #ffeaa7; + flex-shrink: 0; +} + +.costs-preview h4 { + margin: 0 0 12px 0; + color: #856404; + font-size: 1rem; +} + +.cost-item { + display: flex; + align-items: center; + gap: 8px; +} + +.cost-label { + color: #856404; + font-weight: 500; +} + +.cost-value { + font-weight: bold; + color: #495057; + background: white; + padding: 4px 8px; + border-radius: 4px; + border: 1px solid #ffeaa7; +} + +/* Action Info */ +.action-info { + flex: 1; +} + +.selection-count { + font-size: 0.9rem; + color: #6c757d; + font-weight: 500; +} + +.action-buttons { + display: flex; + gap: 12px; +} + +/* Skills Selection Container */ +.skills-selection-container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + margin-bottom: 20px; +} + +@media (max-width: 1024px) { + .skills-selection-container { + grid-template-columns: 1fr; + gap: 16px; + } +} + +.skills-available, +.skills-selected { + border: 2px solid #dee2e6; + border-radius: 8px; + overflow: hidden; +} + +.skills-available h4, +.skills-selected h4 { + margin: 0; + padding: 12px 16px; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + font-size: 1rem; + color: #495057; +} + +/* Category Filters */ +.category-filters { + padding: 12px 16px; + border-bottom: 1px solid #dee2e6; + display: flex; + flex-wrap: wrap; + gap: 8px; + background: #f8f9fa; +} + +.category-filter-btn { + padding: 6px 12px; + background: white; + border: 2px solid #dee2e6; + border-radius: 20px; + font-size: 0.85rem; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; + font-weight: 500; + color: #495057; +} + +.category-filter-btn:hover { + border-color: #1da766; + color: #1da766; +} + +.category-filter-btn.active { + background: #1da766; + border-color: #1da766; + color: white; + font-weight: 600; +} + +.category-filter-btn:first-child { + font-weight: 600; + background: #e9ecef; + border-color: #adb5bd; +} + +.category-filter-btn:first-child.active { + background: #495057; + border-color: #495057; + color: white; +} + +/* Sort and Search Controls */ +.search-input { + margin: 0; + font-size: 13px; +} + +.sort-and-search-controls { + padding: 12px 16px; + border-bottom: 1px solid #dee2e6; + display: flex; + align-items: center; + gap: 20px; + background: #f8f9fa; + flex-wrap: wrap; +} + +.sort-controls { + display: flex; + align-items: center; + gap: 12px; + flex: 0 0 auto; +} + +.skills-search { + flex: 1; + min-width: 200px; +} + +.sort-label { + font-size: 0.9rem; + color: #495057; + font-weight: 500; +} + +.sort-btn { + padding: 6px 12px; + background: white; + border: 2px solid #dee2e6; + border-radius: 6px; + font-size: 0.85rem; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; + font-weight: 500; + color: #495057; + display: flex; + align-items: center; + gap: 4px; +} + +.sort-btn:hover { + border-color: #1da766; + color: #1da766; +} + +.sort-btn.active { + background: #1da766; + border-color: #1da766; + color: white; + font-weight: 600; +} + +.sort-icon { + font-size: 0.8rem; + font-weight: bold; +} + +/* Skills List */ +.skills-list { + max-height: 60vh; + overflow-y: auto; + background: white; +} + +.skill-item { + padding: 12px 16px; + border-bottom: 1px solid #f8f9fa; + display: flex; + align-items: center; + gap: 12px; + cursor: grab; + transition: all 0.2s ease; +} + +.skill-item:hover { + background: #f8f9fa; +} + +.skill-item:active { + cursor: grabbing; +} + +.skill-item.skill-affordable { + border-left: 4px solid #1da766; +} + +.skill-item:not(.skill-affordable) { + opacity: 0.6; + cursor: not-allowed; +} + +.skill-info { + flex: 1; +} + +.skill-main-line { + display: flex; + align-items: center; + gap: 12px; + flex-wrap: wrap; +} + +.skill-name { + font-weight: 600; + color: #333; + font-size: 0.95rem; + min-width: 120px; +} + +.skill-category { + font-size: 0.8rem; + color: #6c757d; + font-style: italic; + min-width: 100px; +} + +.skill-costs { + display: flex; + gap: 8px; + font-size: 0.85rem; + margin-left: auto; +} + +.cost-ep { + color: #1da766; + font-weight: 600; +} + +.cost-gold { + color: #ffc107; + font-weight: 600; +} + +.skill-actions { + display: flex; + gap: 8px; +} + +.btn-select { + width: 32px; + height: 32px; + border: 2px solid #1da766; + background: white; + color: #1da766; + border-radius: 50%; + cursor: pointer; + font-weight: bold; + font-size: 14px; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; +} + +.btn-select:hover:not(:disabled) { + background: #1da766; + color: white; + transform: scale(1.1); +} + +.btn-select:disabled { + border-color: #6c757d; + color: #6c757d; + cursor: not-allowed; + transform: none; +} + +/* Skills Drop Zone */ +.skills-drop-zone { + min-height: 60vh; + padding: 16px; + background: white; + border: 2px dashed #dee2e6; + margin: 16px; + border-radius: 8px; + transition: all 0.2s ease; +} + +.skills-drop-zone.drag-over { + border-color: #1da766; + background: rgba(29, 167, 102, 0.05); +} + +.drop-zone-placeholder { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + min-height: 200px; + color: #6c757d; + text-align: center; +} + +.placeholder-icon { + font-size: 48px; + margin-bottom: 16px; + opacity: 0.7; +} + +.placeholder-text { + font-size: 0.9rem; + line-height: 1.4; + max-width: 200px; +} + +/* Selected Skills List */ +.selected-skills-list { + display: flex; + flex-direction: column; + gap: 8px; +} + +.selected-skill-item { + display: flex; + align-items: center; + gap: 12px; + padding: 12px; + background: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 6px; + transition: all 0.2s ease; +} + +.selected-skill-item:hover { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.selected-skill-info { + flex: 1; +} + +.selected-skill-name { + font-weight: 600; + color: #333; + margin-bottom: 4px; +} + +.selected-skill-costs { + display: flex; + gap: 12px; + font-size: 0.85rem; +} + +/* Total Costs */ +.total-costs-header { + font-weight: 600; + color: #856404; + margin-bottom: 8px; +} + +.total-costs-breakdown { + display: flex; + gap: 16px; + margin-bottom: 8px; +} + +.total-ep, +.total-gold { + font-weight: 600; + font-size: 0.9rem; +} + +.total-ep { + color: #1da766; +} + +.total-gold { + color: #ffc107; +} + +.affordability-check { + font-size: 0.85rem; + font-weight: 600; +} + +.text-success { + color: #28a745; +} + +.loading-skills { + padding: 20px; + text-align: center; + color: #6c757d; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; +} + +.simple-input-section { + margin-bottom: 20px; + padding: 16px; + background: #fff3cd; + border: 1px solid #ffeaa7; + border-radius: 8px; +} + +.simple-input-section .form-group { + margin-bottom: 0; +} + +/* ======================================== + AUDIT LOG VIEW STYLES + ======================================== */ +.audit-log-view { + padding: 20px; + background: #f8f9fa; + border-radius: 8px; + margin-top: 20px; +} + +.audit-log-view h4 { + color: #333; + margin-bottom: 20px; + padding-bottom: 10px; + border-bottom: 2px solid #007bff; +} + +.filter-controls { + display: flex; + flex-wrap: wrap; + gap: 15px; + align-items: center; + margin-bottom: 20px; + padding: 15px; + background: white; + border-radius: 6px; + border: 1px solid #e9ecef; +} + +.filter-group { + display: flex; + align-items: center; + gap: 10px; +} + +.date-range-group { + display: flex; + align-items: center; + gap: 10px; + margin-left: 10px; +} + +.filter-select, .date-input { + padding: 8px 12px; + border: 1px solid #ddd; + border-radius: 4px; + background: white; +} + +.btn-refresh { + padding: 8px 16px; + background: #007bff; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + gap: 5px; +} + +.btn-refresh:hover:not(:disabled) { + background: #0056b3; +} + +.stats-section { + margin-bottom: 25px; + padding: 15px; + background: white; + border-radius: 6px; + border: 1px solid #e9ecef; +} + +.stats-section h5 { + margin-bottom: 15px; + color: #555; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 15px; +} + +.stat-item { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; + background: #f8f9fa; + border-radius: 4px; +} + +.stat-label { + font-weight: 500; + color: #666; +} + +.stat-value { + font-weight: bold; + font-size: 1.1em; +} + +.stat-value.positive { + color: #28a745; +} + +.stat-value.negative { + color: #dc3545; +} + +.audit-entries { + background: white; + border-radius: 6px; + border: 1px solid #e9ecef; +} + +.loading, .no-entries { + padding: 40px; + text-align: center; + color: #666; + font-style: italic; +} + +.audit-entry { + padding: 15px; + border-bottom: 1px solid #e9ecef; + transition: background-color 0.2s; +} + +.audit-entry:last-child { + border-bottom: none; +} + +.audit-entry:hover { + background-color: #f8f9fa; +} + +.audit-entry.positive-change { + border-left: 4px solid #28a745; +} + +.audit-entry.negative-change { + border-left: 4px solid #dc3545; +} + +.entry-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; +} + +.entry-field { + display: flex; + align-items: center; + gap: 8px; + font-weight: bold; +} + +.field-icon { + font-size: 1.2em; +} + +.entry-timestamp { + color: #666; + font-size: 0.9em; + text-align: right; + display: flex; + flex-direction: column; + gap: 2px; +} + +.timestamp-date { + font-weight: 500; + color: #555; +} + +.timestamp-time { + font-size: 0.85em; + color: #888; + font-family: monospace; +} + +.timestamp-relative { + font-size: 0.8em; + color: #999; + font-style: italic; +} + +.entry-content { + margin-left: 20px; +} + +.value-change { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 8px; + font-family: monospace; + font-size: 1.1em; +} + +.old-value { + color: #666; +} + +.arrow { + color: #007bff; + font-weight: bold; +} + +.new-value { + font-weight: bold; +} + +.difference { + font-weight: bold; + font-size: 0.9em; +} + +.difference.positive { + color: #28a745; +} + +.difference.negative { + color: #dc3545; +} + +.entry-reason, .entry-notes { + display: flex; + gap: 8px; + margin-bottom: 5px; + font-size: 0.9em; +} + +.reason-label, .notes-label { + font-weight: 500; + color: #666; + min-width: 50px; +} + +.reason-value { + background: #e9ecef; + padding: 2px 8px; + border-radius: 12px; + font-size: 0.85em; + font-weight: 500; +} + +.notes-value { + color: #555; + font-style: italic; +} + +.date-group { + margin-bottom: 25px; +} + +.date-group-header { + background: #007bff; + color: white; + padding: 8px 15px; + margin: 0 0 10px 0; + border-radius: 4px; + font-weight: 500; + font-size: 0.9em; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.checkbox-input { + margin-right: 8px; +} + +/* ======================================== + EQUIPMENT VIEW STYLES + ======================================== */ +.btn-add-equipment { + padding: 8px 16px; + background: #1da766; + color: white; + border: none; + border-radius: 6px; + cursor: pointer; + font-weight: bold; + transition: background 0.2s ease; +} + +.btn-add-equipment:hover { + background: #16a085; +} + +.empty-state { + text-align: center; + color: #999; + font-style: italic; + padding: 2rem !important; +} + +.btn-delete { + background: none; + border: none; + cursor: pointer; + font-size: 1.2rem; + padding: 4px 8px; + transition: transform 0.2s ease; +} + +.btn-delete:hover { + transform: scale(1.2); +} + +.equipment-list { + max-height: 300px; + overflow-y: auto; + border: 1px solid #ddd; + border-radius: 4px; + margin-bottom: 15px; +} + +.equipment-item { + padding: 12px; + border-bottom: 1px solid #eee; + cursor: pointer; + transition: background 0.2s ease; +} + +.equipment-item:hover { + background: #f5f5f5; +} + +.equipment-item.selected { + background: #e8f5e9; + border-left: 3px solid #1da766; +} + +.equipment-name { + font-weight: bold; + color: #333; + margin-bottom: 4px; +} + +.equipment-details { + font-size: 0.9em; + color: #666; +} + +.no-results { + text-align: center; + padding: 2rem; + color: #999; + font-style: italic; +} + +.selected-equipment-details { + background: #f8f9fa; + padding: 15px; + border-radius: 4px; + margin-top: 15px; +} + +.selected-equipment-details h4 { + margin-top: 0; + color: #1da766; +} + +.selected-equipment-details p { + margin: 8px 0; +} + +.btn-confirm { + padding: 8px 20px; + background: #1da766; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-weight: bold; + transition: background 0.2s ease; +} + +.btn-confirm:hover:not(:disabled) { + background: #16a085; +} + +.btn-confirm:disabled { + background: #ccc; + cursor: not-allowed; +} + +.btn-cancel { + padding: 8px 20px; + background: #6c757d; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + transition: background 0.2s ease; +} + +.btn-cancel:hover { + background: #5a6268; +} + +/* ======================================== + CHARACTER CREATION STYLES + ======================================== */ +.character-creation { + width: 100%; + max-width: none; + margin: 0; + padding: 10px; +} + +.creation-content { + width: 100%; + background: white; + border-radius: 8px; + padding: 30px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + margin-bottom: 20px; +} + +.creation-header { + margin-bottom: 30px; +} + +.creation-header h1 { + text-align: center; + margin-bottom: 20px; + color: #333; +} + +.progress-indicator { + display: flex; + justify-content: center; + align-items: center; + gap: 20px; + margin-bottom: 20px; +} + +.step { + display: flex; + flex-direction: column; + align-items: center; + padding: 10px; + border-radius: 8px; + transition: all 0.3s ease; +} + +.step.active { + background-color: #e3f2fd; + border: 2px solid #2196f3; +} + +.step.completed { + background-color: #e8f5e8; + border: 2px solid #4caf50; +} + +.step-number { + display: flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + border-radius: 50%; + background-color: #ddd; + color: #666; + font-weight: bold; + margin-bottom: 5px; +} + +.step.active .step-number { + background-color: #2196f3; + color: white; +} + +.step.completed .step-number { + background-color: #4caf50; + color: white; +} + +.step.clickable { + cursor: pointer; + transition: all 0.3s ease; +} + +.step.clickable:hover { + transform: translateY(-2px); + box-shadow: 0 4px 8px rgba(0,0,0,0.1); +} + +.step.completed:hover .step-number { + background-color: #45a049; +} + +.step.active:hover .step-number { + background-color: #1976d2; +} + +.step-title { + font-size: 12px; + color: #666; + text-align: center; +} + +.session-info { + display: flex; + justify-content: space-between; + align-items: center; + padding: 15px; + background-color: #f5f5f5; + border-radius: 4px; + font-size: 14px; + color: #666; +} + +.delete-btn { + background-color: #f44336; + color: white; + padding: 8px 16px; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; +} + +.delete-btn:hover { + background-color: #d32f2f; +} + +/* ======================================== + DATASHEET VIEW STYLES + ======================================== */ +.datasheet-container { + padding-top: 10px; +} + +.character-overview { + margin-bottom: 30px; + margin-top: 0; +} + +.character-image { + position: relative; +} + +.character-image .image-upload-container { + position: absolute; + bottom: 10px; + right: 10px; +} + +.character-info { + margin-top: 20px; +} + +.info-section { + max-width: none; + white-space: normal; + line-height: 1.6; +} + +.info-section p { + margin: 15px 0; + padding: 0; +} + +.editable-value { + cursor: pointer; + padding: 2px 4px; + border-radius: 3px; + transition: background-color 0.2s; +} + +.editable-value:hover { + background-color: rgba(0, 123, 255, 0.1); +} + +.edit-input { + width: 60px; + padding: 2px 4px; + font-size: inherit; + font-weight: bold; + border: 2px solid var(--primary-color); + border-radius: 3px; + text-align: center; +} + +.edit-input:focus { + outline: none; + border-color: #0056b3; +} + +.editable-prop { + cursor: pointer; + padding: 1px 3px; + border-radius: 2px; + transition: background-color 0.2s; + display: inline-block; + min-width: 20px; +} + +.editable-prop:hover { + background-color: rgba(0, 123, 255, 0.1); +} + +.prop-input { + padding: 1px 4px; + font-size: inherit; + border: 1px solid var(--primary-color); + border-radius: 3px; + min-width: 60px; +} + +.prop-input:focus { + outline: none; + border-color: #0056b3; +} + +/* =================================== + LANDING PAGE STYLES + =================================== */ + +.landing-page { + width: 100vw; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; + background-image: url('/Abgrund-DD2.jpg'); + background-size: cover; + background-position: center; + background-repeat: no-repeat; + background-attachment: fixed; + position: relative; + overflow: hidden; +} + +.landing-page::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.5); + z-index: 1; +} + +.landing-content { + position: relative; + z-index: 2; + max-width: 800px; + padding: 2rem; + text-align: center; + color: white; +} + +.dragon-container { + margin-bottom: 2rem; +} + +.dragon-image { + max-width: 300px; + width: 100%; + height: auto; + filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3)); + animation: float 3s ease-in-out infinite; +} + +@keyframes float { + 0%, 100% { + transform: translateY(0); + } + 50% { + transform: translateY(-10px); + } +} + +.info-container h1 { + font-size: 2.5rem; + margin-bottom: 1.5rem; + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7); + line-height: 1.2; +} + +.info-container .description { + font-size: 1.2rem; + line-height: 1.6; + margin-bottom: 2rem; + text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.7); +} + +.version-info { + margin-bottom: 2rem; + font-size: 0.9rem; + opacity: 0.9; +} + +.version-info p { + margin: 0.5rem 0; + line-height: 1.4; +} + +.action-links { + display: flex; + gap: 1rem; + justify-content: center; + flex-wrap: wrap; +} + +.action-links .btn { + min-width: 150px; + font-size: 1.1rem; + padding: 12px 24px; +} + +@media (max-width: 768px) { + .landing-content { + padding: 1rem; + } + + .dragon-image { + max-width: 200px; + } + + .info-container h1 { + font-size: 1.8rem; + } + + .info-container .description { + font-size: 1rem; + } + + .action-links { + flex-direction: column; + align-items: center; + } + + .action-links .btn { + width: 100%; + max-width: 300px; + } } \ No newline at end of file diff --git a/frontend/src/components/AuditLogView.vue b/frontend/src/components/AuditLogView.vue index c32b016..af2030a 100644 --- a/frontend/src/components/AuditLogView.vue +++ b/frontend/src/components/AuditLogView.vue @@ -431,276 +431,6 @@ export default { }; - diff --git a/frontend/src/components/AusruestungForm.vue b/frontend/src/components/AusruestungForm.vue index 0db9227..fe387e1 100644 --- a/frontend/src/components/AusruestungForm.vue +++ b/frontend/src/components/AusruestungForm.vue @@ -35,3 +35,7 @@ export default { }, } + + diff --git a/frontend/src/components/AusruestungList.vue b/frontend/src/components/AusruestungList.vue index f78556e..b397174 100644 --- a/frontend/src/components/AusruestungList.vue +++ b/frontend/src/components/AusruestungList.vue @@ -38,3 +38,7 @@ export default { }, } + + diff --git a/frontend/src/components/CharacterCreation.vue b/frontend/src/components/CharacterCreation.vue index 8e816fc..26fa0db 100644 --- a/frontend/src/components/CharacterCreation.vue +++ b/frontend/src/components/CharacterCreation.vue @@ -359,132 +359,6 @@ export default { } - diff --git a/frontend/src/components/CharacterCreation/CharacterAttributes.vue b/frontend/src/components/CharacterCreation/CharacterAttributes.vue index 2ec184d..cc1087d 100644 --- a/frontend/src/components/CharacterCreation/CharacterAttributes.vue +++ b/frontend/src/components/CharacterCreation/CharacterAttributes.vue @@ -336,22 +336,8 @@ export default { } - diff --git a/frontend/src/components/CharacterCreation/CharacterBasicInfo.vue b/frontend/src/components/CharacterCreation/CharacterBasicInfo.vue index fda5b8b..f4f2666 100644 --- a/frontend/src/components/CharacterCreation/CharacterBasicInfo.vue +++ b/frontend/src/components/CharacterCreation/CharacterBasicInfo.vue @@ -390,49 +390,8 @@ export default { } - diff --git a/frontend/src/components/CharacterCreation/CharacterSkills.vue b/frontend/src/components/CharacterCreation/CharacterSkills.vue index e433139..86b5798 100644 --- a/frontend/src/components/CharacterCreation/CharacterSkills.vue +++ b/frontend/src/components/CharacterCreation/CharacterSkills.vue @@ -705,10 +705,9 @@ export default { } - + \ No newline at end of file diff --git a/frontend/src/components/CharacterList.vue b/frontend/src/components/CharacterList.vue index b741f4e..441dcec 100644 --- a/frontend/src/components/CharacterList.vue +++ b/frontend/src/components/CharacterList.vue @@ -132,8 +132,9 @@ export default { } - - + diff --git a/frontend/src/components/EquipmentView.vue b/frontend/src/components/EquipmentView.vue index 0785770..85549cc 100644 --- a/frontend/src/components/EquipmentView.vue +++ b/frontend/src/components/EquipmentView.vue @@ -119,272 +119,12 @@ - diff --git a/frontend/src/components/ExperianceView.vue b/frontend/src/components/ExperianceView.vue index 1509c36..72dea8a 100644 --- a/frontend/src/components/ExperianceView.vue +++ b/frontend/src/components/ExperianceView.vue @@ -93,8 +93,8 @@ - + + diff --git a/frontend/src/components/ForgotPasswordForm.vue b/frontend/src/components/ForgotPasswordForm.vue index a8b1069..c1f276b 100644 --- a/frontend/src/components/ForgotPasswordForm.vue +++ b/frontend/src/components/ForgotPasswordForm.vue @@ -95,6 +95,6 @@ export default { } - diff --git a/frontend/src/components/ImageUploadCropper.vue b/frontend/src/components/ImageUploadCropper.vue index 60ae4ed..791c049 100644 --- a/frontend/src/components/ImageUploadCropper.vue +++ b/frontend/src/components/ImageUploadCropper.vue @@ -74,7 +74,10 @@ - - diff --git a/frontend/src/components/Menu.vue b/frontend/src/components/Menu.vue index 1e20def..1fc86be 100644 --- a/frontend/src/components/Menu.vue +++ b/frontend/src/components/Menu.vue @@ -1,6 +1,9 @@ diff --git a/frontend/src/components/SkillLearnDialog.vue b/frontend/src/components/SkillLearnDialog.vue index ca9012c..13e6a43 100644 --- a/frontend/src/components/SkillLearnDialog.vue +++ b/frontend/src/components/SkillLearnDialog.vue @@ -740,17 +740,9 @@ export default { - - diff --git a/frontend/src/components/WeaponView.vue b/frontend/src/components/WeaponView.vue index 1812e17..2b32f3f 100644 --- a/frontend/src/components/WeaponView.vue +++ b/frontend/src/components/WeaponView.vue @@ -191,7 +191,9 @@ - diff --git a/frontend/src/views/UserProfileView.vue b/frontend/src/views/UserProfileView.vue index 92619ed..fd615cf 100644 --- a/frontend/src/views/UserProfileView.vue +++ b/frontend/src/views/UserProfileView.vue @@ -95,7 +95,9 @@ -