batch import: use individual inputs instead of comma-separated
- start with 3 inputs, add/remove as needed - avoids issues with item names containing commas
This commit is contained in:
parent
dd1591d5b3
commit
42f7722e50
3 changed files with 249 additions and 66 deletions
|
|
@ -18,6 +18,7 @@
|
||||||
import SidebarHeader from '$lib/components/ui/SidebarHeader.svelte'
|
import SidebarHeader from '$lib/components/ui/SidebarHeader.svelte'
|
||||||
import Button from '$lib/components/ui/Button.svelte'
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
import Input from '$lib/components/ui/Input.svelte'
|
import Input from '$lib/components/ui/Input.svelte'
|
||||||
|
import Icon from '$lib/components/Icon.svelte'
|
||||||
import TagInput from '$lib/components/ui/TagInput.svelte'
|
import TagInput from '$lib/components/ui/TagInput.svelte'
|
||||||
|
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
@ -35,7 +36,7 @@
|
||||||
let { data }: { data: PageData } = $props()
|
let { data }: { data: PageData } = $props()
|
||||||
|
|
||||||
// Input phase
|
// Input phase
|
||||||
let wikiPagesInput = $state('')
|
let wikiPagesInputs = $state<string[]>(['', '', ''])
|
||||||
let isFetching = $state(false)
|
let isFetching = $state(false)
|
||||||
let fetchError = $state<string | null>(null)
|
let fetchError = $state<string | null>(null)
|
||||||
|
|
||||||
|
|
@ -135,10 +136,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add/remove input fields
|
||||||
|
function addInput() {
|
||||||
|
wikiPagesInputs = [...wikiPagesInputs, '']
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeInput(index: number) {
|
||||||
|
if (wikiPagesInputs.length > 1) {
|
||||||
|
wikiPagesInputs = wikiPagesInputs.filter((_, i) => i !== index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch wiki data for entered pages
|
// Fetch wiki data for entered pages
|
||||||
async function fetchWikiData() {
|
async function fetchWikiData() {
|
||||||
const pages = wikiPagesInput
|
const pages = wikiPagesInputs
|
||||||
.split(',')
|
|
||||||
.map((p) => p.trim())
|
.map((p) => p.trim())
|
||||||
.filter((p) => p.length > 0)
|
.filter((p) => p.length > 0)
|
||||||
.slice(0, 10)
|
.slice(0, 10)
|
||||||
|
|
@ -349,24 +360,41 @@
|
||||||
<!-- Input phase -->
|
<!-- Input phase -->
|
||||||
{#if entities.size === 0}
|
{#if entities.size === 0}
|
||||||
<div class="input-phase">
|
<div class="input-phase">
|
||||||
<DetailsContainer title="Enter Wiki Pages">
|
<p class="hint">Enter up to 10 wiki page names to import data</p>
|
||||||
<div class="wiki-input">
|
<div class="wiki-inputs">
|
||||||
<Input
|
{#each wikiPagesInputs as _, index}
|
||||||
bind:value={wikiPagesInput}
|
<div class="input-row">
|
||||||
placeholder="Narmaya_(Summer), Zeta_(Summer), Beatrix_(Summer)"
|
<Input
|
||||||
contained
|
bind:value={wikiPagesInputs[index]}
|
||||||
/>
|
placeholder="Narmaya_(Summer)"
|
||||||
<p class="hint">Enter wiki page names separated by commas (up to 10)</p>
|
contained
|
||||||
</div>
|
fullWidth
|
||||||
{#if fetchError}
|
/>
|
||||||
<p class="error">{fetchError}</p>
|
{#if wikiPagesInputs.length > 1}
|
||||||
{/if}
|
<button
|
||||||
<div class="fetch-button">
|
type="button"
|
||||||
<Button variant="primary" onclick={fetchWikiData} disabled={isFetching}>
|
class="remove-button"
|
||||||
{isFetching ? 'Fetching...' : 'Fetch Wiki Data'}
|
onclick={() => removeInput(index)}
|
||||||
</Button>
|
aria-label="Remove input"
|
||||||
</div>
|
>
|
||||||
</DetailsContainer>
|
<Icon name="close" size={16} />
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
<Button variant="ghost" onclick={addInput}>
|
||||||
|
<Icon name="plus" size={16} />
|
||||||
|
Add another
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{#if fetchError}
|
||||||
|
<p class="error">{fetchError}</p>
|
||||||
|
{/if}
|
||||||
|
<div class="fetch-button">
|
||||||
|
<Button variant="primary" onclick={fetchWikiData} disabled={isFetching}>
|
||||||
|
{isFetching ? 'Fetching...' : 'Fetch data'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- Entity selector -->
|
<!-- Entity selector -->
|
||||||
|
|
@ -586,15 +614,48 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-phase {
|
.input-phase {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: spacing.$unit-2x;
|
||||||
padding: spacing.$unit-2x;
|
padding: spacing.$unit-2x;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wiki-input {
|
.wiki-inputs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: spacing.$unit;
|
gap: spacing.$unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-row {
|
||||||
|
display: flex;
|
||||||
|
gap: spacing.$unit;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-radius: layout.$input-corner;
|
||||||
|
color: colors.$grey-50;
|
||||||
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: colors.$grey-90;
|
||||||
|
color: colors.$grey-30;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(svg) {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.hint {
|
.hint {
|
||||||
font-size: typography.$font-small;
|
font-size: typography.$font-small;
|
||||||
color: colors.$grey-50;
|
color: colors.$grey-50;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
import SidebarHeader from '$lib/components/ui/SidebarHeader.svelte'
|
import SidebarHeader from '$lib/components/ui/SidebarHeader.svelte'
|
||||||
import Button from '$lib/components/ui/Button.svelte'
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
import Input from '$lib/components/ui/Input.svelte'
|
import Input from '$lib/components/ui/Input.svelte'
|
||||||
|
import Icon from '$lib/components/Icon.svelte'
|
||||||
import TagInput from '$lib/components/ui/TagInput.svelte'
|
import TagInput from '$lib/components/ui/TagInput.svelte'
|
||||||
|
|
||||||
import type { PageData } from './$types'
|
import type { PageData } from './$types'
|
||||||
|
|
@ -34,7 +35,7 @@
|
||||||
let { data }: { data: PageData } = $props()
|
let { data }: { data: PageData } = $props()
|
||||||
|
|
||||||
// Input phase
|
// Input phase
|
||||||
let wikiPagesInput = $state('')
|
let wikiPagesInputs = $state<string[]>(['', '', ''])
|
||||||
let isFetching = $state(false)
|
let isFetching = $state(false)
|
||||||
let fetchError = $state<string | null>(null)
|
let fetchError = $state<string | null>(null)
|
||||||
|
|
||||||
|
|
@ -125,10 +126,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add/remove input fields
|
||||||
|
function addInput() {
|
||||||
|
wikiPagesInputs = [...wikiPagesInputs, '']
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeInput(index: number) {
|
||||||
|
if (wikiPagesInputs.length > 1) {
|
||||||
|
wikiPagesInputs = wikiPagesInputs.filter((_, i) => i !== index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch wiki data for entered pages
|
// Fetch wiki data for entered pages
|
||||||
async function fetchWikiData() {
|
async function fetchWikiData() {
|
||||||
const pages = wikiPagesInput
|
const pages = wikiPagesInputs
|
||||||
.split(',')
|
|
||||||
.map((p) => p.trim())
|
.map((p) => p.trim())
|
||||||
.filter((p) => p.length > 0)
|
.filter((p) => p.length > 0)
|
||||||
.slice(0, 10)
|
.slice(0, 10)
|
||||||
|
|
@ -326,24 +337,41 @@
|
||||||
<!-- Input phase -->
|
<!-- Input phase -->
|
||||||
{#if entities.size === 0}
|
{#if entities.size === 0}
|
||||||
<div class="input-phase">
|
<div class="input-phase">
|
||||||
<DetailsContainer title="Enter Wiki Pages">
|
<p class="hint">Enter up to 10 wiki page names to import data</p>
|
||||||
<div class="wiki-input">
|
<div class="wiki-inputs">
|
||||||
<Input
|
{#each wikiPagesInputs as _, index}
|
||||||
bind:value={wikiPagesInput}
|
<div class="input-row">
|
||||||
placeholder="Bahamut, Lucifer, Zeus"
|
<Input
|
||||||
contained
|
bind:value={wikiPagesInputs[index]}
|
||||||
/>
|
placeholder="Bahamut"
|
||||||
<p class="hint">Enter wiki page names separated by commas (up to 10)</p>
|
contained
|
||||||
</div>
|
fullWidth
|
||||||
{#if fetchError}
|
/>
|
||||||
<p class="error">{fetchError}</p>
|
{#if wikiPagesInputs.length > 1}
|
||||||
{/if}
|
<button
|
||||||
<div class="fetch-button">
|
type="button"
|
||||||
<Button variant="primary" onclick={fetchWikiData} disabled={isFetching}>
|
class="remove-button"
|
||||||
{isFetching ? 'Fetching...' : 'Fetch Wiki Data'}
|
onclick={() => removeInput(index)}
|
||||||
</Button>
|
aria-label="Remove input"
|
||||||
</div>
|
>
|
||||||
</DetailsContainer>
|
<Icon name="close" size={16} />
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
<Button variant="ghost" onclick={addInput}>
|
||||||
|
<Icon name="plus" size={16} />
|
||||||
|
Add another
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{#if fetchError}
|
||||||
|
<p class="error">{fetchError}</p>
|
||||||
|
{/if}
|
||||||
|
<div class="fetch-button">
|
||||||
|
<Button variant="primary" onclick={fetchWikiData} disabled={isFetching}>
|
||||||
|
{isFetching ? 'Fetching...' : 'Fetch data'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- Entity selector -->
|
<!-- Entity selector -->
|
||||||
|
|
@ -564,15 +592,48 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-phase {
|
.input-phase {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: spacing.$unit-2x;
|
||||||
padding: spacing.$unit-2x;
|
padding: spacing.$unit-2x;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wiki-input {
|
.wiki-inputs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: spacing.$unit;
|
gap: spacing.$unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-row {
|
||||||
|
display: flex;
|
||||||
|
gap: spacing.$unit;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-radius: layout.$input-corner;
|
||||||
|
color: colors.$grey-50;
|
||||||
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: colors.$grey-90;
|
||||||
|
color: colors.$grey-30;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(svg) {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.hint {
|
.hint {
|
||||||
font-size: typography.$font-small;
|
font-size: typography.$font-small;
|
||||||
color: colors.$grey-50;
|
color: colors.$grey-50;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
import SidebarHeader from '$lib/components/ui/SidebarHeader.svelte'
|
import SidebarHeader from '$lib/components/ui/SidebarHeader.svelte'
|
||||||
import Button from '$lib/components/ui/Button.svelte'
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
import Input from '$lib/components/ui/Input.svelte'
|
import Input from '$lib/components/ui/Input.svelte'
|
||||||
|
import Icon from '$lib/components/Icon.svelte'
|
||||||
import TagInput from '$lib/components/ui/TagInput.svelte'
|
import TagInput from '$lib/components/ui/TagInput.svelte'
|
||||||
import CharacterTypeahead from '$lib/components/ui/CharacterTypeahead.svelte'
|
import CharacterTypeahead from '$lib/components/ui/CharacterTypeahead.svelte'
|
||||||
|
|
||||||
|
|
@ -35,7 +36,7 @@
|
||||||
let { data }: { data: PageData } = $props()
|
let { data }: { data: PageData } = $props()
|
||||||
|
|
||||||
// Input phase
|
// Input phase
|
||||||
let wikiPagesInput = $state('')
|
let wikiPagesInputs = $state<string[]>(['', '', ''])
|
||||||
let isFetching = $state(false)
|
let isFetching = $state(false)
|
||||||
let fetchError = $state<string | null>(null)
|
let fetchError = $state<string | null>(null)
|
||||||
|
|
||||||
|
|
@ -127,10 +128,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add/remove input fields
|
||||||
|
function addInput() {
|
||||||
|
wikiPagesInputs = [...wikiPagesInputs, '']
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeInput(index: number) {
|
||||||
|
if (wikiPagesInputs.length > 1) {
|
||||||
|
wikiPagesInputs = wikiPagesInputs.filter((_, i) => i !== index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch wiki data for entered pages
|
// Fetch wiki data for entered pages
|
||||||
async function fetchWikiData() {
|
async function fetchWikiData() {
|
||||||
const pages = wikiPagesInput
|
const pages = wikiPagesInputs
|
||||||
.split(',')
|
|
||||||
.map((p) => p.trim())
|
.map((p) => p.trim())
|
||||||
.filter((p) => p.length > 0)
|
.filter((p) => p.length > 0)
|
||||||
.slice(0, 10)
|
.slice(0, 10)
|
||||||
|
|
@ -331,24 +342,41 @@
|
||||||
<!-- Input phase -->
|
<!-- Input phase -->
|
||||||
{#if entities.size === 0}
|
{#if entities.size === 0}
|
||||||
<div class="input-phase">
|
<div class="input-phase">
|
||||||
<DetailsContainer title="Enter Wiki Pages">
|
<p class="hint">Enter up to 10 wiki page names to import data</p>
|
||||||
<div class="wiki-input">
|
<div class="wiki-inputs">
|
||||||
<Input
|
{#each wikiPagesInputs as _, index}
|
||||||
bind:value={wikiPagesInput}
|
<div class="input-row">
|
||||||
placeholder="Ixaba, Benedia, Sky Ace"
|
<Input
|
||||||
contained
|
bind:value={wikiPagesInputs[index]}
|
||||||
/>
|
placeholder="Ixaba"
|
||||||
<p class="hint">Enter wiki page names separated by commas (up to 10)</p>
|
contained
|
||||||
</div>
|
fullWidth
|
||||||
{#if fetchError}
|
/>
|
||||||
<p class="error">{fetchError}</p>
|
{#if wikiPagesInputs.length > 1}
|
||||||
{/if}
|
<button
|
||||||
<div class="fetch-button">
|
type="button"
|
||||||
<Button variant="primary" onclick={fetchWikiData} disabled={isFetching}>
|
class="remove-button"
|
||||||
{isFetching ? 'Fetching...' : 'Fetch Wiki Data'}
|
onclick={() => removeInput(index)}
|
||||||
</Button>
|
aria-label="Remove input"
|
||||||
</div>
|
>
|
||||||
</DetailsContainer>
|
<Icon name="close" size={16} />
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
<Button variant="ghost" onclick={addInput}>
|
||||||
|
<Icon name="plus" size={16} />
|
||||||
|
Add another
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
{#if fetchError}
|
||||||
|
<p class="error">{fetchError}</p>
|
||||||
|
{/if}
|
||||||
|
<div class="fetch-button">
|
||||||
|
<Button variant="primary" onclick={fetchWikiData} disabled={isFetching}>
|
||||||
|
{isFetching ? 'Fetching...' : 'Fetch data'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<!-- Entity selector -->
|
<!-- Entity selector -->
|
||||||
|
|
@ -567,15 +595,48 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-phase {
|
.input-phase {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: spacing.$unit-2x;
|
||||||
padding: spacing.$unit-2x;
|
padding: spacing.$unit-2x;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wiki-input {
|
.wiki-inputs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: spacing.$unit;
|
gap: spacing.$unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-row {
|
||||||
|
display: flex;
|
||||||
|
gap: spacing.$unit;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-radius: layout.$input-corner;
|
||||||
|
color: colors.$grey-50;
|
||||||
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: colors.$grey-90;
|
||||||
|
color: colors.$grey-30;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(svg) {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.hint {
|
.hint {
|
||||||
font-size: typography.$font-small;
|
font-size: typography.$font-small;
|
||||||
color: colors.$grey-50;
|
color: colors.$grey-50;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue