Merge branch 'users' into main
Players library, circular NPC tokens, disposition types; keep main overlay/release fixes. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -302,7 +302,7 @@ function FilterToolbar({
|
||||
return (
|
||||
<Panel position="top-left">
|
||||
<Select
|
||||
className={styles.filterSelect}
|
||||
{...(styles.filterSelect ? { className: styles.filterSelect } : {})}
|
||||
ariaLabel={ui.graphFilter}
|
||||
value={value}
|
||||
onChange={(next) => onChange(next as GraphGroupFilter)}
|
||||
|
||||
@@ -189,6 +189,15 @@
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.colorInput {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
border: 1px solid var(--stroke);
|
||||
border-radius: 8px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.avatarPick {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
|
||||
@@ -14,8 +14,10 @@ import type {
|
||||
import editorStyles from '../editor/EditorApp.module.css';
|
||||
import { useEditorI18n } from '../editor/i18n/EditorI18nContext';
|
||||
import { getDndApi } from '../shared/dndApi';
|
||||
import { PlayerTokenView } from '../shared/playerToken/PlayerTokenView';
|
||||
import { Button, Input, Select } from '../shared/ui/controls';
|
||||
import { useAssetUrl } from '../shared/useAssetImageUrl';
|
||||
import { npcDispositionRingColor } from '../../shared/types/npcDisposition';
|
||||
|
||||
import { NpcDescriptionField } from './NpcDescriptionField';
|
||||
import { NpcEditModal } from './NpcEditModal';
|
||||
@@ -735,11 +737,27 @@ export function NpcsEditorApp() {
|
||||
<div>
|
||||
<div className={styles.fieldLabel}>{t('npcs.avatar')}</div>
|
||||
<div className={styles.avatarPick}>
|
||||
<div className={styles.avatarPreview}>
|
||||
{selectedUrl ? (
|
||||
<img className={styles.avatarPreviewImg} src={selectedUrl} alt="" />
|
||||
) : null}
|
||||
</div>
|
||||
<PlayerTokenView
|
||||
name={selected.name}
|
||||
imageUrl={selectedUrl}
|
||||
ringColor={npcDispositionRingColor(selected.disposition ?? 'neutral')}
|
||||
imageOffset={selected.imageOffset}
|
||||
imageScale={selected.imageScale}
|
||||
sizePx={140}
|
||||
panEnabled
|
||||
onImageOffsetChange={(imageOffset) => {
|
||||
void api.invoke(ipcChannels.project.updateNpcFields, {
|
||||
npcId: selected.id,
|
||||
imageOffset,
|
||||
});
|
||||
}}
|
||||
onImageScaleChange={(imageScale) => {
|
||||
void api.invoke(ipcChannels.project.updateNpcFields, {
|
||||
npcId: selected.id,
|
||||
imageScale,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
disabled={avatarBusy}
|
||||
onClick={() => {
|
||||
@@ -764,6 +782,25 @@ export function NpcsEditorApp() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label>
|
||||
<div className={styles.fieldLabel}>{t('npcs.disposition')}</div>
|
||||
<Select
|
||||
value={selected.disposition ?? 'neutral'}
|
||||
ariaLabel={t('npcs.disposition')}
|
||||
onChange={(next) => {
|
||||
void api.invoke(ipcChannels.project.updateNpcFields, {
|
||||
npcId: selected.id,
|
||||
disposition: next as 'hostile' | 'neutral' | 'friendly',
|
||||
});
|
||||
}}
|
||||
options={[
|
||||
{ value: 'hostile', label: t('npcs.disposition.hostile') },
|
||||
{ value: 'neutral', label: t('npcs.disposition.neutral') },
|
||||
{ value: 'friendly', label: t('npcs.disposition.friendly') },
|
||||
]}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<div className={styles.fieldLabel}>{t('npcs.name')}</div>
|
||||
<Input
|
||||
|
||||
Reference in New Issue
Block a user