Simplify character dossier fields, add ShowPronouns setting
Collapse Want/Need into Motivation and Internal/External Conflict into Conflict, drop Arc summary field, and move tags below open questions on the character page. Gate Pronouns display behind new UiSettings:ShowPronouns config (default off).
This commit is contained in:
@@ -23,11 +23,13 @@ import type {
|
||||
NovelSummary,
|
||||
TagReferences,
|
||||
TagSummary,
|
||||
UiSettings,
|
||||
User,
|
||||
} from './types'
|
||||
|
||||
export const keys = {
|
||||
me: ['me'] as const,
|
||||
uiSettings: ['ui-settings'] as const,
|
||||
members: (novelId: string) => ['novels', novelId, 'members'] as const,
|
||||
novels: ['novels'] as const,
|
||||
genres: ['genres'] as const,
|
||||
@@ -46,6 +48,9 @@ export const keys = {
|
||||
importJob: (id: string) => ['imports', id] as const,
|
||||
}
|
||||
|
||||
export const useUiSettings = () =>
|
||||
useQuery({ queryKey: keys.uiSettings, queryFn: () => api.get<UiSettings>('/api/ui-settings') })
|
||||
|
||||
export const useMe = () =>
|
||||
useQuery({
|
||||
queryKey: keys.me,
|
||||
|
||||
@@ -49,6 +49,10 @@ export interface User {
|
||||
globalRole: GlobalRole
|
||||
}
|
||||
|
||||
export interface UiSettings {
|
||||
showPronouns: boolean
|
||||
}
|
||||
|
||||
export interface NovelMember {
|
||||
userId: string
|
||||
email: string
|
||||
@@ -197,11 +201,8 @@ export interface Character {
|
||||
appearance: string | null
|
||||
personality: string | null
|
||||
backstory: string | null
|
||||
want: string | null
|
||||
need: string | null
|
||||
internalConflict: string | null
|
||||
externalConflict: string | null
|
||||
arcSummary: string | null
|
||||
motivation: string | null
|
||||
conflict: string | null
|
||||
voice: string | null
|
||||
notes: string | null
|
||||
aliases: string[]
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
useNovel,
|
||||
useRemoveRelationship,
|
||||
useTags,
|
||||
useUiSettings,
|
||||
useUnlinkCharacterIdentity,
|
||||
useUpdateCharacter,
|
||||
} from '../api/hooks'
|
||||
@@ -79,6 +80,7 @@ function CharacterSheet({
|
||||
canDelete: boolean
|
||||
}) {
|
||||
const navigate = useNavigate()
|
||||
const { data: uiSettings } = useUiSettings()
|
||||
const { data: allTags } = useTags(novelId)
|
||||
const { data: allCharacters } = useCharacters(novelId)
|
||||
const { data: chapters } = useChapters(novelId)
|
||||
@@ -125,12 +127,14 @@ function CharacterSheet({
|
||||
|
||||
<div className="grid gap-4 sm:grid-cols-3">
|
||||
<AutoField label="Age" value={character.age} onCommit={(age) => patch({ age })} readOnly={!canWrite} />
|
||||
<AutoField
|
||||
label="Pronouns"
|
||||
value={character.pronouns}
|
||||
onCommit={(pronouns) => patch({ pronouns })}
|
||||
readOnly={!canWrite}
|
||||
/>
|
||||
{uiSettings?.showPronouns && (
|
||||
<AutoField
|
||||
label="Pronouns"
|
||||
value={character.pronouns}
|
||||
onCommit={(pronouns) => patch({ pronouns })}
|
||||
readOnly={!canWrite}
|
||||
/>
|
||||
)}
|
||||
<AutoField
|
||||
label="Occupation"
|
||||
value={character.occupation}
|
||||
@@ -139,13 +143,7 @@ function CharacterSheet({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-5 grid gap-4 sm:grid-cols-2">
|
||||
<TagEditor
|
||||
label="Tags"
|
||||
tags={character.tags}
|
||||
suggestions={allTags?.map((t) => t.name) ?? []}
|
||||
onChange={(tags) => canWrite && patch({ tags })}
|
||||
/>
|
||||
<div className="mt-5">
|
||||
<AliasEditor
|
||||
label="Also known as"
|
||||
aliases={character.aliases}
|
||||
@@ -156,42 +154,20 @@ function CharacterSheet({
|
||||
|
||||
<div className="mt-6 grid gap-4 lg:grid-cols-2">
|
||||
<AutoField
|
||||
label="Wants"
|
||||
value={character.want}
|
||||
label="Motivation"
|
||||
value={character.motivation}
|
||||
multiline
|
||||
rows={3}
|
||||
placeholder="What they are consciously chasing."
|
||||
onCommit={(want) => patch({ want })}
|
||||
placeholder="What they consciously want, and what they need instead."
|
||||
onCommit={(motivation) => patch({ motivation })}
|
||||
readOnly={!canWrite}
|
||||
/>
|
||||
<AutoField
|
||||
label="Needs"
|
||||
value={character.need}
|
||||
label="Conflict"
|
||||
value={character.conflict}
|
||||
multiline
|
||||
rows={3}
|
||||
placeholder="What the story will make them face instead."
|
||||
onCommit={(need) => patch({ need })}
|
||||
readOnly={!canWrite}
|
||||
/>
|
||||
<AutoField
|
||||
label="Internal conflict"
|
||||
value={character.internalConflict}
|
||||
multiline
|
||||
onCommit={(internalConflict) => patch({ internalConflict })}
|
||||
readOnly={!canWrite}
|
||||
/>
|
||||
<AutoField
|
||||
label="External conflict"
|
||||
value={character.externalConflict}
|
||||
multiline
|
||||
onCommit={(externalConflict) => patch({ externalConflict })}
|
||||
readOnly={!canWrite}
|
||||
/>
|
||||
<AutoField
|
||||
label="Arc"
|
||||
value={character.arcSummary}
|
||||
multiline
|
||||
onCommit={(arcSummary) => patch({ arcSummary })}
|
||||
placeholder="The war inside them, and what in the world opposes them."
|
||||
onCommit={(conflict) => patch({ conflict })}
|
||||
readOnly={!canWrite}
|
||||
/>
|
||||
<AutoField
|
||||
@@ -304,6 +280,15 @@ function CharacterSheet({
|
||||
canDelete={canDelete}
|
||||
/>
|
||||
|
||||
<section id="character-tags" className="card mt-6 p-5">
|
||||
<TagEditor
|
||||
label="Tags"
|
||||
tags={character.tags}
|
||||
suggestions={allTags?.map((t) => t.name) ?? []}
|
||||
onChange={(tags) => canWrite && patch({ tags })}
|
||||
/>
|
||||
</section>
|
||||
|
||||
{confirmingDelete && (
|
||||
<ConfirmModal
|
||||
title="Delete character"
|
||||
|
||||
Reference in New Issue
Block a user