Begin on dataset management screens
This commit is contained in:
parent
51ec6a480d
commit
86ed6122c9
35
SessionZero/Pages/Library/CharacterTemplates/Templates.razor
Normal file
35
SessionZero/Pages/Library/CharacterTemplates/Templates.razor
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
@page "/library/character-templates"
|
||||||
|
|
||||||
|
<NavLink class="button-secondary" href="/library/" style="align-self: flex-start;">
|
||||||
|
<img src="res/icons/outline/arrows/arrow-left.svg" class="button-icon" />
|
||||||
|
Back to Library
|
||||||
|
</NavLink>
|
||||||
|
|
||||||
|
<h1 class="page-title">Character Templates</h1>
|
||||||
|
|
||||||
|
<div class="library-card-container">
|
||||||
|
|
||||||
|
<div class="card" onclick="@(() => { })">
|
||||||
|
<img src="res/icons/outline/general/plus.svg" class="icon"/>
|
||||||
|
<h1>Create</h1>
|
||||||
|
<p>Create a new template</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card" onclick="@(() => { })">
|
||||||
|
<img src="res/icons/outline/general/edit.svg" class="icon"/>
|
||||||
|
<h1>Manage</h1>
|
||||||
|
<p>Manage and edit saved templates</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card" onclick="@(() => { })">
|
||||||
|
<img src="res/icons/outline/general/search.svg" class="icon"/>
|
||||||
|
<h1>SessionZeroDB</h1>
|
||||||
|
<p>Search online for new templates (NOT FUNCTIONAL)</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
@page "/Library/Datasets"
|
|
||||||
|
|
||||||
<NavLink class="button-secondary" href="/library/" style="align-self: flex-start;">
|
|
||||||
<img src="res/icons/outline/arrows/arrow-left.svg" class="button-icon" />
|
|
||||||
Back to Library
|
|
||||||
</NavLink>
|
|
||||||
|
|
||||||
<h1 class="page-title">Datasets</h1>
|
|
||||||
|
|
||||||
<p>@_message</p>
|
|
@ -1,8 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Components;
|
|
||||||
|
|
||||||
namespace SessionZero.Pages.Library;
|
|
||||||
|
|
||||||
public partial class Datasets : ComponentBase
|
|
||||||
{
|
|
||||||
private string _message = "Datasets Page Loaded Successfully!";
|
|
||||||
}
|
|
275
SessionZero/Pages/Library/Datasets/Datasets.razor
Normal file
275
SessionZero/Pages/Library/Datasets/Datasets.razor
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
@page "/Library/Datasets"
|
||||||
|
@using SessionZero.Data
|
||||||
|
@using SessionZero.Models
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject SessionZero.Services.ISzfStorageService SzfStorageService
|
||||||
|
@inject SzfParser SzfParser
|
||||||
|
@inject SzfGenerator SzfGenerator
|
||||||
|
|
||||||
|
<NavLink class="button-secondary" href="/library/" style="align-self: flex-start;">
|
||||||
|
<img src="res/icons/outline/arrows/arrow-left.svg" class="button-icon" />
|
||||||
|
Back to Library
|
||||||
|
</NavLink>
|
||||||
|
|
||||||
|
<h1 class="page-title">Datasets</h1>
|
||||||
|
|
||||||
|
@if (!string.IsNullOrEmpty(_message))
|
||||||
|
{
|
||||||
|
<div class="panel" style="background-color: var(--primary-color-light); margin-bottom: 1rem;">
|
||||||
|
<p>@_message</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
@switch (CurrentView)
|
||||||
|
{
|
||||||
|
case DatasetView.Overview:
|
||||||
|
<div class="library-card-container">
|
||||||
|
<div class="card" @onclick="ShowCreateDataset">
|
||||||
|
<img src="res/icons/outline/general/plus.svg" class="icon"/>
|
||||||
|
<h1>Create</h1>
|
||||||
|
<p>Create a new dataset</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card" @onclick="ShowManageDatasets">
|
||||||
|
<img src="res/icons/outline/general/edit.svg" class="icon"/>
|
||||||
|
<h1>Manage</h1>
|
||||||
|
<p>Manage and edit saved datasets</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<img src="res/icons/outline/general/search.svg" class="icon"/>
|
||||||
|
<h1>SessionZeroDB</h1>
|
||||||
|
<p>Search online for new datasets (NOT FUNCTIONAL)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DatasetView.CreateDataset:
|
||||||
|
<h3>Create New Dataset</h3>
|
||||||
|
<div class="panel">
|
||||||
|
<EditForm Model="@NewDataset" OnValidSubmit="@HandleCreateDataset">
|
||||||
|
<DataAnnotationsValidator />
|
||||||
|
<ValidationSummary />
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="datasetName">Name</label>
|
||||||
|
<InputText id="datasetName" class="form-control" @bind-Value="NewDataset.Metadata.Name" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="datasetType">Type (e.g., items, spells)</label>
|
||||||
|
<InputText id="datasetType" class="form-control" @bind-Value="NewDataset.DatasetType" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="datasetVersion">Version (e.g., 1.0.0)</label>
|
||||||
|
<InputText id="datasetVersion" class="form-control" @bind-Value="DatasetVersionString" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="datasetAuthor">Author</label>
|
||||||
|
<InputText id="datasetAuthor" class="form-control" @bind-Value="NewDataset.Metadata.Author" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="datasetImageUrl">Image URL</label>
|
||||||
|
<InputText id="datasetImageUrl" class="form-control" @bind-Value="NewDataset.ImageUrl" />
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label" for="datasetDescription">Description</label>
|
||||||
|
<InputTextArea id="datasetDescription" class="form-control" @bind-Value="NewDataset.Metadata.Description" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="button-group">
|
||||||
|
<button type="submit" class="button-main">Create Dataset</button>
|
||||||
|
<button type="button" class="button-secondary" @onclick="ShowOverview">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</EditForm>
|
||||||
|
</div>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DatasetView.ManageDatasets:
|
||||||
|
<h3>Manage Datasets</h3>
|
||||||
|
@if (SavedDatasets == null)
|
||||||
|
{
|
||||||
|
<p>Loading datasets...</p>
|
||||||
|
}
|
||||||
|
else if (!SavedDatasets.Any())
|
||||||
|
{
|
||||||
|
<div class="panel">
|
||||||
|
<p>No datasets saved yet. Click "Create" to add one.</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<table class="data-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Version</th>
|
||||||
|
<th>Author</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var dataset in SavedDatasets)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@dataset.Metadata.Name</td>
|
||||||
|
<td>@dataset.DatasetType</td>
|
||||||
|
<td>@dataset.Metadata.Version</td>
|
||||||
|
<td>@dataset.Metadata.Author</td>
|
||||||
|
<td>
|
||||||
|
<div class="button-group">
|
||||||
|
<button class="button-main" @onclick="() => EditDataset(dataset.Metadata.Guid.ToString())">Edit</button>
|
||||||
|
<button class="button-danger" @onclick="() => DeleteDataset(dataset.Metadata.Guid.ToString())">Delete</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
}
|
||||||
|
<div class="button-group">
|
||||||
|
<button type="button" class="button-secondary" @onclick="ShowOverview">Back</button>
|
||||||
|
</div>
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private enum DatasetView { Overview, CreateDataset, ManageDatasets }
|
||||||
|
private DatasetView CurrentView = DatasetView.Overview;
|
||||||
|
private SessionZero.Data.Dataset NewDataset = new();
|
||||||
|
private IEnumerable<SessionZero.Data.Dataset>? SavedDatasets;
|
||||||
|
private string _message = string.Empty;
|
||||||
|
|
||||||
|
// New property to handle Version binding
|
||||||
|
private string DatasetVersionString
|
||||||
|
{
|
||||||
|
get => NewDataset.Metadata.Version?.ToString() ?? string.Empty;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (Version.TryParse(value, out var parsedVersion))
|
||||||
|
{
|
||||||
|
NewDataset.Metadata.Version = parsedVersion;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Handle invalid version string, e.g., set to null or a default, or show an error
|
||||||
|
// For simplicity, we'll just leave it as is if parsing fails.
|
||||||
|
// A better approach would be to use a CustomValidator or more robust input handling.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
await LoadDatasets();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowOverview()
|
||||||
|
{
|
||||||
|
CurrentView = DatasetView.Overview;
|
||||||
|
_message = string.Empty; // Clear any messages
|
||||||
|
NewDataset = new(); // Reset the new dataset form
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowCreateDataset()
|
||||||
|
{
|
||||||
|
CurrentView = DatasetView.CreateDataset;
|
||||||
|
_message = string.Empty;
|
||||||
|
NewDataset = new() // Initialize with default values if needed
|
||||||
|
{
|
||||||
|
Metadata = new()
|
||||||
|
{
|
||||||
|
Guid = Guid.NewGuid(),
|
||||||
|
Version = new Version(1, 0, 0) // Ensure Version is initialized
|
||||||
|
}
|
||||||
|
};
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ShowManageDatasets()
|
||||||
|
{
|
||||||
|
CurrentView = DatasetView.ManageDatasets;
|
||||||
|
_message = string.Empty;
|
||||||
|
await LoadDatasets(); // Reload datasets when entering management view
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HandleCreateDataset()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var validationResult = NewDataset.Validate();
|
||||||
|
if (!validationResult.IsValid)
|
||||||
|
{
|
||||||
|
_message = "Validation errors: " + string.Join("; ", validationResult.Errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SzfFile szfFile = new SzfFile
|
||||||
|
{
|
||||||
|
Guid = NewDataset.Metadata.Guid.ToString(),
|
||||||
|
Content = SzfGenerator.Generate(NewDataset),
|
||||||
|
Type = "dataset",
|
||||||
|
};
|
||||||
|
await SzfStorageService.SaveSzfFileAsync(szfFile);
|
||||||
|
_message = $"Dataset '{NewDataset.Metadata.Name}' created successfully!";
|
||||||
|
await LoadDatasets(); // Refresh the list of datasets
|
||||||
|
ShowOverview(); // Go back to overview after creation
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_message = $"Error creating dataset: {ex.Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadDatasets()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var allSzfDatasetFiles = await SzfStorageService.GetSzfFilesByTypeAsync("dataset");
|
||||||
|
var allSzfObjects = allSzfDatasetFiles.Select(file => SzfParser.Parse(file.Content));
|
||||||
|
|
||||||
|
SavedDatasets = allSzfObjects.OfType<SessionZero.Data.Dataset>().ToList();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_message = $"Error loading datasets: {ex.Message}";
|
||||||
|
SavedDatasets = new List<Dataset>(); // Ensure it's not null on error
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task EditDataset(string guid)
|
||||||
|
{
|
||||||
|
_message = $"Attempting to edit dataset with GUID: {guid}";
|
||||||
|
var datasetFileToEdit = await SzfStorageService.GetSzfFileByGuidAsync(guid);
|
||||||
|
var datasetToEdit = SzfParser.Parse(datasetFileToEdit.Content);
|
||||||
|
if (datasetToEdit is Dataset ds)
|
||||||
|
{
|
||||||
|
NewDataset = ds; // Populate the form with the dataset to edit
|
||||||
|
CurrentView = DatasetView.CreateDataset; // Re-use the create form for editing
|
||||||
|
_message = $"Editing dataset: {ds.Metadata.Name}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_message = "Dataset not found for editing.";
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteDataset(string guid)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await SzfStorageService.DeleteSzfFileAsync(guid);
|
||||||
|
_message = "Dataset deleted successfully!";
|
||||||
|
await LoadDatasets(); // Refresh the list after deletion
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_message = $"Error deleting dataset: {ex.Message}";
|
||||||
|
}
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
}
|
8
SessionZero/Pages/Library/Datasets/Datasets.razor.cs
Normal file
8
SessionZero/Pages/Library/Datasets/Datasets.razor.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace SessionZero.Pages.Library.Datasets;
|
||||||
|
|
||||||
|
public partial class Datasets : ComponentBase
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
@ -1,9 +1,11 @@
|
|||||||
@page "/Library"
|
@page "/Library"
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
|
|
||||||
<h1 class="page-title">Library</h1>
|
<h1 class="page-title">Library</h1>
|
||||||
|
|
||||||
<div class="library-card-container">
|
<div class="library-card-container">
|
||||||
<NavLink class="card" onclick="@(() => { NavigationManager.NavigateTo("/library/templates"); })">
|
<NavLink class="card" onclick="@(() => { NavigationManager.NavigateTo("/library/character-templates"); })">
|
||||||
<img src="res/icons/outline/user/address-book.svg" class="icon" />
|
<img src="res/icons/outline/user/address-book.svg" class="icon" />
|
||||||
<h1>Character Sheet Templates</h1>
|
<h1>Character Sheet Templates</h1>
|
||||||
<p>Create and manage Character Sheet Templates</p>
|
<p>Create and manage Character Sheet Templates</p>
|
||||||
@ -14,39 +16,3 @@
|
|||||||
<p>Create and manage Datasets</p>
|
<p>Create and manage Datasets</p>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
.library-card-container {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 1.5rem;
|
|
||||||
justify-content: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.library-card-container .card {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 250px;
|
|
||||||
max-width: calc(50% - 0.75rem);
|
|
||||||
padding: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.library-card-container .card p {
|
|
||||||
color: var(--neutral-medium);
|
|
||||||
}
|
|
||||||
|
|
||||||
.library-card-container .card h1 {
|
|
||||||
font-size: 1.6em;
|
|
||||||
color: var(--heading-color);
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private void NavigateToTemplates()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
@page "/library/templates"
|
|
||||||
|
|
||||||
<NavLink class="button-secondary" href="/library/" style="align-self: flex-start;">
|
|
||||||
<img src="res/icons/outline/arrows/arrow-left.svg" class="button-icon" />
|
|
||||||
Back to Library
|
|
||||||
</NavLink>
|
|
||||||
|
|
||||||
<h1 class="page-title">Templates</h1>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
|
|
||||||
}
|
|
@ -100,6 +100,30 @@ html, body, #app {
|
|||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.library-card-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 1.5rem;
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-card-container .card {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 250px;
|
||||||
|
max-width: calc(50% - 0.75rem);
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-card-container .card p {
|
||||||
|
color: var(--neutral-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.library-card-container .card h1 {
|
||||||
|
font-size: 1.6em;
|
||||||
|
color: var(--heading-color);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
.button-main {
|
.button-main {
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
padding: 0.6rem 1.2rem;
|
padding: 0.6rem 1.2rem;
|
||||||
@ -145,6 +169,267 @@ html, body, #app {
|
|||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Forms and Input Elements */
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
color: var(--heading-color);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.8rem 1rem;
|
||||||
|
background-color: var(--form-background);
|
||||||
|
border: 1px solid var(--primary-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 1rem;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
box-shadow: 0 0 0 3px rgba(91, 137, 179, 0.3); /* Accent color with transparency */
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control::placeholder {
|
||||||
|
color: var(--neutral-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea.form-control {
|
||||||
|
min-height: 100px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
select.form-control {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url('../res/icons/arrow-left.svg'); /* Using local arrow-left.svg */
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 1rem center;
|
||||||
|
background-size: 1em;
|
||||||
|
padding-right: 2.5rem; /* Make space for the arrow */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checkboxes and Radios */
|
||||||
|
.form-check {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-input {
|
||||||
|
margin-right: 0.75rem;
|
||||||
|
width: 1.25rem;
|
||||||
|
height: 1.25rem;
|
||||||
|
border: 1px solid var(--primary-color-light);
|
||||||
|
border-radius: 3px;
|
||||||
|
background-color: var(--form-background);
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
transition: background-color 0.2s ease, border-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-input:checked {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
border-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-input[type="checkbox"]:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 3px;
|
||||||
|
width: 6px;
|
||||||
|
height: 10px;
|
||||||
|
border: solid var(--text-color);
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-input[type="radio"] {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-input[type="radio"]:checked::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--text-color);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-check-label {
|
||||||
|
color: var(--text-color);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
.data-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden; /* Ensures rounded corners apply to content */
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table th,
|
||||||
|
.data-table td {
|
||||||
|
padding: 1rem 1.2rem;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid var(--neutral-dark);
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table thead {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table th {
|
||||||
|
color: var(--heading-color);
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table tbody tr {
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table tbody tr:nth-child(even) {
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table tbody tr:nth-child(odd) {
|
||||||
|
background-color: var(--form-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table tbody tr:hover {
|
||||||
|
background-color: var(--primary-color-light);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table td {
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lists (e.g., for items or dynamic content) */
|
||||||
|
.custom-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-list-item {
|
||||||
|
padding: 1rem 1.2rem;
|
||||||
|
border-bottom: 1px solid var(--neutral-dark);
|
||||||
|
color: var(--text-color);
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-list-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-list-item:hover {
|
||||||
|
background-color: var(--primary-color-light);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-list-item-header {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--heading-color);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-list-item-meta {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--neutral-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Custom Visual Elements (e.g., panels, containers) */
|
||||||
|
.panel {
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
padding: 1.5rem;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-header {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
color: var(--heading-color);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border-bottom: 1px solid var(--neutral-dark);
|
||||||
|
padding-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-content {
|
||||||
|
color: var(--text-color);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 1rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-item {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 250px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Action Buttons within forms/lists */
|
||||||
|
.button-action {
|
||||||
|
background-color: var(--success-color);
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--button-text);
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-action:hover {
|
||||||
|
background-color: var(--success-color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-danger {
|
||||||
|
background-color: var(--danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-danger:hover {
|
||||||
|
background-color: var(--danger-color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -79,16 +79,16 @@ FieldName (text) = Some Value # This is an inline comment.
|
|||||||
|
|
||||||
The .szf format supports a variety of field types to handle different kinds of data. These types are declared in character_template and dataset files.
|
The .szf format supports a variety of field types to handle different kinds of data. These types are declared in character_template and dataset files.
|
||||||
|
|
||||||
| Type | Description | Example Value |
|
| Type | Description | Example Value |
|
||||||
| :---- | :---- | :---- |
|
|:---------------------|:----------------------------------------------------------------|:---------------------------------------------|
|
||||||
| text | A single line of text. | Elara the Brave |
|
| text | A single line of text. | Elara the Brave |
|
||||||
| text-field | A multi-line block of text. | A long sword forged by...\nIt glows faintly. |
|
| text-field | A multi-line block of text. | A long sword forged by...\nIt glows faintly. |
|
||||||
| number | An integer or floating-point number. | 16 or 3.5 |
|
| number | An integer or floating-point number. | 16 or 3.5 |
|
||||||
| bool | A boolean value. | true or false |
|
| bool | A boolean value. | true or false |
|
||||||
| calculated | A value derived from a formula. | (Strength - 10) / 2 |
|
| calculated | A value derived from a formula. | (Strength - 10) / 2 |
|
||||||
| system | A special field that controls application behavior. | items |
|
| system | A special field that controls application behavior. | |
|
||||||
| entry-reference | A reference to a single entry from a dataset. | ClassData or ItemData.Longsword |
|
| entry-reference | A reference to a single entry from a dataset. | ClassData or ItemData.Longsword |
|
||||||
| entry-reference-list | A comma-separated list of references to entries from a dataset. | CoreFeats.PowerAttack, CoreFeats.Cleave |
|
| entry-reference-list | A comma-separated list of references to entries from a dataset. | CoreFeats.PowerAttack, CoreFeats.Cleave |
|
||||||
|
|
||||||
## **4. File Type Specifications**
|
## **4. File Type Specifications**
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user