add DatabasePageHeader to entity detail/edit pages
This commit is contained in:
parent
5c2203af42
commit
2898740cb2
7 changed files with 177 additions and 27 deletions
75
src/lib/components/database/DatabasePageHeader.svelte
Normal file
75
src/lib/components/database/DatabasePageHeader.svelte
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
<svelte:options runes={true} />
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
|
import type { Snippet } from 'svelte'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
/** Page title (not the item name) */
|
||||||
|
title: string
|
||||||
|
/** Custom right action content */
|
||||||
|
rightAction?: Snippet | undefined
|
||||||
|
/** Click handler for back button - defaults to history.back() */
|
||||||
|
onBack?: (() => void) | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
let { title, rightAction, onBack }: Props = $props()
|
||||||
|
|
||||||
|
function handleBack() {
|
||||||
|
if (onBack) {
|
||||||
|
onBack()
|
||||||
|
} else {
|
||||||
|
history.back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<header class="header">
|
||||||
|
<div class="left">
|
||||||
|
<Button variant="ghost" size="small" leftIcon="chevron-left" onclick={handleBack}>
|
||||||
|
Back
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h1 class="title">{title}</h1>
|
||||||
|
|
||||||
|
<div class="right">
|
||||||
|
{#if rightAction}
|
||||||
|
{@render rightAction()}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@use '$src/themes/spacing' as spacing;
|
||||||
|
@use '$src/themes/typography' as typography;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: spacing.$unit-2x;
|
||||||
|
gap: spacing.$unit-2x;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left,
|
||||||
|
.right {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: spacing.$unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-size: typography.$font-small;
|
||||||
|
font-weight: typography.$medium;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
} from '$lib/utils/external-links'
|
} from '$lib/utils/external-links'
|
||||||
import Button from '$lib/components/ui/Button.svelte'
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
import CharacterTags from '$lib/components/tags/CharacterTags.svelte'
|
import CharacterTags from '$lib/components/tags/CharacterTags.svelte'
|
||||||
|
import DatabasePageHeader from '$lib/components/database/DatabasePageHeader.svelte'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
@ -192,13 +193,19 @@
|
||||||
<PageMeta title={pageTitle} description={m.page_desc_home()} />
|
<PageMeta title={pageTitle} description={m.page_desc_home()} />
|
||||||
|
|
||||||
<div class="page">
|
<div class="page">
|
||||||
|
<DatabasePageHeader title="Character">
|
||||||
|
{#snippet rightAction()}
|
||||||
|
{#if canEdit && editUrl}
|
||||||
|
<Button variant="element-ghost" element={elementName} size="small" href={editUrl}>Edit</Button>
|
||||||
|
{/if}
|
||||||
|
{/snippet}
|
||||||
|
</DatabasePageHeader>
|
||||||
|
|
||||||
{#if character}
|
{#if character}
|
||||||
<DetailScaffold
|
<DetailScaffold
|
||||||
type="character"
|
type="character"
|
||||||
item={character}
|
item={character}
|
||||||
image={getCharacterGridImage(character)}
|
image={getCharacterGridImage(character)}
|
||||||
showEdit={canEdit}
|
|
||||||
editUrl={canEdit ? editUrl : undefined}
|
|
||||||
{currentTab}
|
{currentTab}
|
||||||
onTabChange={handleTabChange}
|
onTabChange={handleTabChange}
|
||||||
onDownloadAllImages={canEdit ? handleDownloadAllImages : undefined}
|
onDownloadAllImages={canEdit ? handleDownloadAllImages : undefined}
|
||||||
|
|
@ -379,7 +386,7 @@
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: layout.$card-corner;
|
border-radius: layout.$page-corner;
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,15 @@
|
||||||
import TagInput from '$lib/components/ui/TagInput.svelte'
|
import TagInput from '$lib/components/ui/TagInput.svelte'
|
||||||
import { getCharacterImage } from '$lib/utils/images'
|
import { getCharacterImage } from '$lib/utils/images'
|
||||||
import { CHARACTER_SERIES_NAMES } from '$lib/types/enums'
|
import { CHARACTER_SERIES_NAMES } from '$lib/types/enums'
|
||||||
|
import { getElementLabel } from '$lib/utils/element'
|
||||||
import {
|
import {
|
||||||
buildWikiEnUrl,
|
buildWikiEnUrl,
|
||||||
buildWikiJaUrl,
|
buildWikiJaUrl,
|
||||||
buildGamewithUrl,
|
buildGamewithUrl,
|
||||||
buildKamigameUrl
|
buildKamigameUrl
|
||||||
} from '$lib/utils/external-links'
|
} from '$lib/utils/external-links'
|
||||||
|
import DatabasePageHeader from '$lib/components/database/DatabasePageHeader.svelte'
|
||||||
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
@ -56,6 +59,18 @@
|
||||||
// Always in edit mode
|
// Always in edit mode
|
||||||
const editMode = true
|
const editMode = true
|
||||||
|
|
||||||
|
// Element for button styling
|
||||||
|
const elementName = $derived(
|
||||||
|
getElementLabel(character?.element)?.toLowerCase() as
|
||||||
|
| 'wind'
|
||||||
|
| 'fire'
|
||||||
|
| 'water'
|
||||||
|
| 'earth'
|
||||||
|
| 'dark'
|
||||||
|
| 'light'
|
||||||
|
| undefined
|
||||||
|
)
|
||||||
|
|
||||||
// Save state
|
// Save state
|
||||||
let isSaving = $state(false)
|
let isSaving = $state(false)
|
||||||
let saveError = $state<string | null>(null)
|
let saveError = $state<string | null>(null)
|
||||||
|
|
@ -277,17 +292,20 @@
|
||||||
<PageMeta title={pageTitle} description={m.page_desc_home()} />
|
<PageMeta title={pageTitle} description={m.page_desc_home()} />
|
||||||
|
|
||||||
<div class="page">
|
<div class="page">
|
||||||
|
<DatabasePageHeader title="Edit Character" onBack={handleCancel}>
|
||||||
|
{#snippet rightAction()}
|
||||||
|
<Button variant="element-ghost" element={elementName} size="small" onclick={saveChanges} disabled={isSaving}>
|
||||||
|
{isSaving ? 'Saving...' : 'Save'}
|
||||||
|
</Button>
|
||||||
|
{/snippet}
|
||||||
|
</DatabasePageHeader>
|
||||||
|
|
||||||
{#if character}
|
{#if character}
|
||||||
<DetailScaffold
|
<DetailScaffold
|
||||||
type="character"
|
type="character"
|
||||||
item={character}
|
item={character}
|
||||||
image={getCharacterGridImage(character)}
|
image={getCharacterGridImage(character)}
|
||||||
showEdit={true}
|
|
||||||
{editMode}
|
{editMode}
|
||||||
{isSaving}
|
|
||||||
{saveError}
|
|
||||||
onSave={saveChanges}
|
|
||||||
onCancel={handleCancel}
|
|
||||||
>
|
>
|
||||||
<section class="details">
|
<section class="details">
|
||||||
<CharacterMetadataSection {character} {editMode} bind:editData />
|
<CharacterMetadataSection {character} {editMode} bind:editData />
|
||||||
|
|
@ -394,7 +412,7 @@
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: layout.$card-corner;
|
border-radius: layout.$page-corner;
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
buildKamigameUrl
|
buildKamigameUrl
|
||||||
} from '$lib/utils/external-links'
|
} from '$lib/utils/external-links'
|
||||||
import Button from '$lib/components/ui/Button.svelte'
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
|
import DatabasePageHeader from '$lib/components/database/DatabasePageHeader.svelte'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
@ -184,13 +185,19 @@
|
||||||
<PageMeta title={pageTitle} description={m.page_desc_home()} />
|
<PageMeta title={pageTitle} description={m.page_desc_home()} />
|
||||||
|
|
||||||
<div class="page">
|
<div class="page">
|
||||||
|
<DatabasePageHeader title="Summon">
|
||||||
|
{#snippet rightAction()}
|
||||||
|
{#if canEdit && editUrl}
|
||||||
|
<Button variant="element-ghost" element={elementName} size="small" href={editUrl}>Edit</Button>
|
||||||
|
{/if}
|
||||||
|
{/snippet}
|
||||||
|
</DatabasePageHeader>
|
||||||
|
|
||||||
{#if summon}
|
{#if summon}
|
||||||
<DetailScaffold
|
<DetailScaffold
|
||||||
type="summon"
|
type="summon"
|
||||||
item={summon}
|
item={summon}
|
||||||
image={getSummonGridImage(summon)}
|
image={getSummonGridImage(summon)}
|
||||||
showEdit={canEdit}
|
|
||||||
editUrl={canEdit ? editUrl : undefined}
|
|
||||||
{currentTab}
|
{currentTab}
|
||||||
onTabChange={handleTabChange}
|
onTabChange={handleTabChange}
|
||||||
onDownloadAllImages={canEdit ? handleDownloadAllImages : undefined}
|
onDownloadAllImages={canEdit ? handleDownloadAllImages : undefined}
|
||||||
|
|
@ -369,7 +376,7 @@
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: layout.$card-corner;
|
border-radius: layout.$page-corner;
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,9 @@
|
||||||
buildGamewithUrl,
|
buildGamewithUrl,
|
||||||
buildKamigameUrl
|
buildKamigameUrl
|
||||||
} from '$lib/utils/external-links'
|
} from '$lib/utils/external-links'
|
||||||
|
import { getElementLabel } from '$lib/utils/element'
|
||||||
|
import DatabasePageHeader from '$lib/components/database/DatabasePageHeader.svelte'
|
||||||
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
@ -47,6 +50,18 @@
|
||||||
// Always in edit mode
|
// Always in edit mode
|
||||||
const editMode = true
|
const editMode = true
|
||||||
|
|
||||||
|
// Element for button styling
|
||||||
|
const elementName = $derived(
|
||||||
|
getElementLabel(summon?.element)?.toLowerCase() as
|
||||||
|
| 'wind'
|
||||||
|
| 'fire'
|
||||||
|
| 'water'
|
||||||
|
| 'earth'
|
||||||
|
| 'dark'
|
||||||
|
| 'light'
|
||||||
|
| undefined
|
||||||
|
)
|
||||||
|
|
||||||
// Save state
|
// Save state
|
||||||
let isSaving = $state(false)
|
let isSaving = $state(false)
|
||||||
let saveError = $state<string | null>(null)
|
let saveError = $state<string | null>(null)
|
||||||
|
|
@ -201,17 +216,20 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="page">
|
<div class="page">
|
||||||
|
<DatabasePageHeader title="Edit Summon" onBack={handleCancel}>
|
||||||
|
{#snippet rightAction()}
|
||||||
|
<Button variant="element-ghost" element={elementName} size="small" onclick={saveChanges} disabled={isSaving}>
|
||||||
|
{isSaving ? 'Saving...' : 'Save'}
|
||||||
|
</Button>
|
||||||
|
{/snippet}
|
||||||
|
</DatabasePageHeader>
|
||||||
|
|
||||||
{#if summon}
|
{#if summon}
|
||||||
<DetailScaffold
|
<DetailScaffold
|
||||||
type="summon"
|
type="summon"
|
||||||
item={summon}
|
item={summon}
|
||||||
image={getSummonGridImage(summon)}
|
image={getSummonGridImage(summon)}
|
||||||
showEdit={true}
|
|
||||||
{editMode}
|
{editMode}
|
||||||
{isSaving}
|
|
||||||
{saveError}
|
|
||||||
onSave={saveChanges}
|
|
||||||
onCancel={handleCancel}
|
|
||||||
>
|
>
|
||||||
<section class="details">
|
<section class="details">
|
||||||
<SummonMetadataSection {summon} {editMode} bind:editData />
|
<SummonMetadataSection {summon} {editMode} bind:editData />
|
||||||
|
|
@ -327,7 +345,7 @@
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: layout.$card-corner;
|
border-radius: layout.$page-corner;
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@
|
||||||
buildKamigameUrl
|
buildKamigameUrl
|
||||||
} from '$lib/utils/external-links'
|
} from '$lib/utils/external-links'
|
||||||
import Button from '$lib/components/ui/Button.svelte'
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
|
import DatabasePageHeader from '$lib/components/database/DatabasePageHeader.svelte'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
@ -186,13 +187,19 @@
|
||||||
<PageMeta title={pageTitle} description={m.page_desc_home()} />
|
<PageMeta title={pageTitle} description={m.page_desc_home()} />
|
||||||
|
|
||||||
<div class="page">
|
<div class="page">
|
||||||
|
<DatabasePageHeader title="Weapon">
|
||||||
|
{#snippet rightAction()}
|
||||||
|
{#if canEdit && editUrl}
|
||||||
|
<Button variant="element-ghost" element={elementName} size="small" href={editUrl}>Edit</Button>
|
||||||
|
{/if}
|
||||||
|
{/snippet}
|
||||||
|
</DatabasePageHeader>
|
||||||
|
|
||||||
{#if weapon}
|
{#if weapon}
|
||||||
<DetailScaffold
|
<DetailScaffold
|
||||||
type="weapon"
|
type="weapon"
|
||||||
item={weapon}
|
item={weapon}
|
||||||
image={getWeaponImage(weapon)}
|
image={getWeaponImage(weapon)}
|
||||||
showEdit={canEdit}
|
|
||||||
editUrl={canEdit ? editUrl : undefined}
|
|
||||||
{currentTab}
|
{currentTab}
|
||||||
onTabChange={handleTabChange}
|
onTabChange={handleTabChange}
|
||||||
onDownloadAllImages={canEdit ? handleDownloadAllImages : undefined}
|
onDownloadAllImages={canEdit ? handleDownloadAllImages : undefined}
|
||||||
|
|
@ -372,7 +379,7 @@
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: layout.$card-corner;
|
border-radius: layout.$page-corner;
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,9 @@
|
||||||
buildGamewithUrl,
|
buildGamewithUrl,
|
||||||
buildKamigameUrl
|
buildKamigameUrl
|
||||||
} from '$lib/utils/external-links'
|
} from '$lib/utils/external-links'
|
||||||
|
import { getElementLabel } from '$lib/utils/element'
|
||||||
|
import DatabasePageHeader from '$lib/components/database/DatabasePageHeader.svelte'
|
||||||
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
@ -48,6 +51,18 @@
|
||||||
// Always in edit mode
|
// Always in edit mode
|
||||||
const editMode = true
|
const editMode = true
|
||||||
|
|
||||||
|
// Element for button styling
|
||||||
|
const elementName = $derived(
|
||||||
|
getElementLabel(weapon?.element)?.toLowerCase() as
|
||||||
|
| 'wind'
|
||||||
|
| 'fire'
|
||||||
|
| 'water'
|
||||||
|
| 'earth'
|
||||||
|
| 'dark'
|
||||||
|
| 'light'
|
||||||
|
| undefined
|
||||||
|
)
|
||||||
|
|
||||||
// Save state
|
// Save state
|
||||||
let isSaving = $state(false)
|
let isSaving = $state(false)
|
||||||
let saveError = $state<string | null>(null)
|
let saveError = $state<string | null>(null)
|
||||||
|
|
@ -224,17 +239,20 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="page">
|
<div class="page">
|
||||||
|
<DatabasePageHeader title="Edit Weapon" onBack={handleCancel}>
|
||||||
|
{#snippet rightAction()}
|
||||||
|
<Button variant="element-ghost" element={elementName} size="small" onclick={saveChanges} disabled={isSaving}>
|
||||||
|
{isSaving ? 'Saving...' : 'Save'}
|
||||||
|
</Button>
|
||||||
|
{/snippet}
|
||||||
|
</DatabasePageHeader>
|
||||||
|
|
||||||
{#if weapon}
|
{#if weapon}
|
||||||
<DetailScaffold
|
<DetailScaffold
|
||||||
type="weapon"
|
type="weapon"
|
||||||
item={weapon}
|
item={weapon}
|
||||||
image={getWeaponImage(weapon)}
|
image={getWeaponImage(weapon)}
|
||||||
showEdit={true}
|
|
||||||
{editMode}
|
{editMode}
|
||||||
{isSaving}
|
|
||||||
{saveError}
|
|
||||||
onSave={saveChanges}
|
|
||||||
onCancel={handleCancel}
|
|
||||||
>
|
>
|
||||||
<section class="details">
|
<section class="details">
|
||||||
<WeaponMetadataSection {weapon} {editMode} bind:editData />
|
<WeaponMetadataSection {weapon} {editMode} bind:editData />
|
||||||
|
|
@ -351,7 +369,7 @@
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: layout.$card-corner;
|
border-radius: layout.$page-corner;
|
||||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue