Adjusted functionality and style of class/background/species screens
This commit is contained in:
1 parent
18734acaad
commit
4491e22573
3 files changed
+186
-172
No files matched your search
+40
-7
@@ -350,7 +350,7 @@ function getDesktopReskinBootstrap(externalImageRoot: string | null): string {
|
||||
addCharactersMenu();
|
||||
addResetOnboardingMenu();
|
||||
bindNativeNavbarSync();
|
||||
postNativeNavbarModel();
|
||||
queueNativeNavbarModelPost({ isForce: true });
|
||||
};
|
||||
|
||||
const NAVBAR_ACTION_ATTR = "data-5etd-nav-action-id";
|
||||
@@ -593,17 +593,50 @@ function getDesktopReskinBootstrap(externalImageRoot: string | null): string {
|
||||
return groups;
|
||||
};
|
||||
|
||||
const postNativeNavbarModel = () => {
|
||||
let navbarModelLastSignature = "";
|
||||
let isNavbarModelPostQueued = false;
|
||||
|
||||
const postNativeNavbarModel = ({ isForce = false } = {}) => {
|
||||
if (!window.parent || window.parent === window) return;
|
||||
const groups = buildNativeNavbarGroups();
|
||||
let nextSignature = "";
|
||||
try {
|
||||
nextSignature = JSON.stringify(groups);
|
||||
} catch {
|
||||
nextSignature = \`groups:\${groups.length}:\${Date.now()}\`;
|
||||
}
|
||||
|
||||
if (!isForce && nextSignature === navbarModelLastSignature) {
|
||||
return;
|
||||
}
|
||||
navbarModelLastSignature = nextSignature;
|
||||
|
||||
window.parent.postMessage(
|
||||
{
|
||||
type: "5etd:native-navbar-data",
|
||||
groups: buildNativeNavbarGroups()
|
||||
groups
|
||||
},
|
||||
"*"
|
||||
);
|
||||
};
|
||||
|
||||
const queueNativeNavbarModelPost = ({ isForce = false } = {}) => {
|
||||
if (isForce) {
|
||||
isNavbarModelPostQueued = false;
|
||||
postNativeNavbarModel({ isForce: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNavbarModelPostQueued) {
|
||||
return;
|
||||
}
|
||||
isNavbarModelPostQueued = true;
|
||||
window.setTimeout(() => {
|
||||
isNavbarModelPostQueued = false;
|
||||
postNativeNavbarModel();
|
||||
}, 80);
|
||||
};
|
||||
|
||||
let navbarSyncObserver = null;
|
||||
const bindNativeNavbarSync = () => {
|
||||
const navbar = document.getElementById("navbar");
|
||||
@@ -614,9 +647,9 @@ function getDesktopReskinBootstrap(externalImageRoot: string | null): string {
|
||||
navbar.dataset.desktopNavSyncBound = "1";
|
||||
navbarSyncObserver?.disconnect?.();
|
||||
navbarSyncObserver = new MutationObserver(() => {
|
||||
window.requestAnimationFrame(postNativeNavbarModel);
|
||||
queueNativeNavbarModelPost();
|
||||
});
|
||||
navbarSyncObserver.observe(navbar, { childList: true, subtree: true, attributes: true, characterData: true });
|
||||
navbarSyncObserver.observe(navbar, { childList: true, subtree: true });
|
||||
};
|
||||
|
||||
const runNativeNavbarAction = (actionId) => {
|
||||
@@ -649,7 +682,7 @@ function getDesktopReskinBootstrap(externalImageRoot: string | null): string {
|
||||
|
||||
if (data.type === "5etd:native-navbar-request") {
|
||||
bindNativeNavbarSync();
|
||||
postNativeNavbarModel();
|
||||
queueNativeNavbarModelPost({ isForce: true });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -693,7 +726,7 @@ html.desktop-reskin .page__header {
|
||||
border: 1px solid rgba(109, 164, 223, 0.32) !important;
|
||||
border-radius: 18px;
|
||||
background: linear-gradient(115deg, rgba(17, 29, 47, 0.98), rgba(24, 38, 58, 0.96) 64%, rgba(87, 58, 32, 0.88));
|
||||
backdrop-filter: blur(14px);
|
||||
// backdrop-filter: blur(14px);
|
||||
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.24);
|
||||
}
|
||||
|
||||
|
||||
+116
-152
@@ -1,7 +1,6 @@
|
||||
import { FormEvent, JSX, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
|
||||
const DEFAULT_PAGE = "/5etools.html";
|
||||
const CARD_PAGE_SIZE = 8;
|
||||
const APP_CHARACTERS_MENU_ID = "__characters";
|
||||
|
||||
const CHARACTER_STEPS = [
|
||||
@@ -82,6 +81,10 @@ const FIVEETOOLS_RENDER_STYLESHEET_PATHS = ["css/bootstrap.css", "css/main.css"]
|
||||
|
||||
type CharacterModalMode = "closed" | "list" | "editor";
|
||||
type EntityPopoverKind = "class" | "species" | "background";
|
||||
type PendingEntitySelection = {
|
||||
kind: EntityPopoverKind;
|
||||
option: CharacterSelectionOption;
|
||||
};
|
||||
|
||||
type RendererHandle = {
|
||||
setBaseUrl: (value: string) => RendererHandle;
|
||||
@@ -206,10 +209,6 @@ function getPathnameFromHrefLoose(hrefRaw: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
function areTopbarGroupsEquivalent(a: TopbarMenuGroup[], b: TopbarMenuGroup[]): boolean {
|
||||
return JSON.stringify(a) === JSON.stringify(b);
|
||||
}
|
||||
|
||||
function parseNativeTopbarMenuList(
|
||||
list: Element,
|
||||
registerAction: (ele: HTMLElement) => string,
|
||||
@@ -755,17 +754,6 @@ function filterBySourceBuckets(options: CharacterSelectionOption[], sourceBucket
|
||||
return options.filter((option) => selected.has(option.sourceBucket));
|
||||
}
|
||||
|
||||
function clampPage(page: number, totalItems: number): number {
|
||||
const totalPages = Math.max(1, Math.ceil(totalItems / CARD_PAGE_SIZE));
|
||||
return Math.max(1, Math.min(totalPages, page));
|
||||
}
|
||||
|
||||
function paginateOptions(options: CharacterSelectionOption[], page: number): CharacterSelectionOption[] {
|
||||
const safePage = clampPage(page, options.length);
|
||||
const start = (safePage - 1) * CARD_PAGE_SIZE;
|
||||
return options.slice(start, start + CARD_PAGE_SIZE);
|
||||
}
|
||||
|
||||
function toEntityRef(option: CharacterSelectionOption): CharacterEntityRef {
|
||||
return {
|
||||
entityType: option.entityType,
|
||||
@@ -2001,6 +1989,7 @@ function WikiView() {
|
||||
const [topbarGroups, setTopbarGroups] = useState<TopbarMenuGroup[]>([]);
|
||||
const frameRef = useRef<HTMLIFrameElement | null>(null);
|
||||
const topbarRef = useRef<HTMLElement | null>(null);
|
||||
const topbarGroupsSignatureRef = useRef<string>("");
|
||||
|
||||
const [characterModalMode, setCharacterModalMode] = useState<CharacterModalMode>("closed");
|
||||
const [characterStep, setCharacterStep] = useState<number>(0);
|
||||
@@ -2019,10 +2008,8 @@ function WikiView() {
|
||||
const [spellSearch, setSpellSearch] = useState("");
|
||||
const [equipmentItemInput, setEquipmentItemInput] = useState("");
|
||||
|
||||
const [classPage, setClassPage] = useState(1);
|
||||
const [speciesPage, setSpeciesPage] = useState(1);
|
||||
const [backgroundPage, setBackgroundPage] = useState(1);
|
||||
const [entityPopover, setEntityPopover] = useState<{ kind: EntityPopoverKind; entityRef: string } | null>(null);
|
||||
const [pendingEntitySelection, setPendingEntitySelection] = useState<PendingEntitySelection | null>(null);
|
||||
const [featCatalog, setFeatCatalog] = useState<FeatCatalogItem[] | null>(null);
|
||||
const [spellCatalog, setSpellCatalog] = useState<SpellCatalogItem[] | null>(null);
|
||||
const [itemCatalog, setItemCatalog] = useState<string[]>([]);
|
||||
@@ -2081,6 +2068,60 @@ function WikiView() {
|
||||
[ensureOptionDetail]
|
||||
);
|
||||
|
||||
const closeEntityPopover = useCallback(() => {
|
||||
setEntityPopover(null);
|
||||
setPendingEntitySelection(null);
|
||||
}, []);
|
||||
|
||||
const confirmPendingEntitySelection = useCallback(() => {
|
||||
if (!pendingEntitySelection) {
|
||||
closeEntityPopover();
|
||||
return;
|
||||
}
|
||||
|
||||
const { kind, option } = pendingEntitySelection;
|
||||
updateDraft((draft) => {
|
||||
if (kind === "class") {
|
||||
return {
|
||||
...draft,
|
||||
selections: {
|
||||
...draft.selections,
|
||||
class: toEntityRef(option),
|
||||
subclass: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (kind === "species") {
|
||||
return {
|
||||
...draft,
|
||||
selections: {
|
||||
...draft.selections,
|
||||
species: toEntityRef(option)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...draft,
|
||||
selections: {
|
||||
...draft.selections,
|
||||
background: toEntityRef(option)
|
||||
},
|
||||
steps: {
|
||||
...draft.steps,
|
||||
abilityScores: {
|
||||
...draft.steps.abilityScores,
|
||||
backgroundBonusModeIndex: 0,
|
||||
backgroundBonusSelections: []
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
closeEntityPopover();
|
||||
}, [closeEntityPopover, pendingEntitySelection, updateDraft]);
|
||||
|
||||
const refreshCharacterSummaries = useCallback(async () => {
|
||||
const list = await window.desktopApi.listCharacters();
|
||||
setCharacterSummaries(list);
|
||||
@@ -2093,9 +2134,6 @@ function WikiView() {
|
||||
setFeatSearch("");
|
||||
setSpellSearch("");
|
||||
setEquipmentItemInput("");
|
||||
setClassPage(1);
|
||||
setSpeciesPage(1);
|
||||
setBackgroundPage(1);
|
||||
setCharacterStep(0);
|
||||
}, []);
|
||||
|
||||
@@ -2348,9 +2386,9 @@ function WikiView() {
|
||||
};
|
||||
};
|
||||
|
||||
const pLoadAll = runtime.DataUtil?.spell?.pLoadAll;
|
||||
const spellDataUtil = runtime.DataUtil?.spell;
|
||||
const getCombinedClasses = runtime.Renderer?.spell?.getCombinedClasses;
|
||||
if (!pLoadAll) {
|
||||
if (!spellDataUtil?.pLoadAll) {
|
||||
if (!isCancelled) {
|
||||
setSpellCatalog([]);
|
||||
}
|
||||
@@ -2367,7 +2405,7 @@ function WikiView() {
|
||||
sourceLookup = null;
|
||||
}
|
||||
|
||||
const spellsRaw = await pLoadAll();
|
||||
const spellsRaw = await spellDataUtil.pLoadAll();
|
||||
const next = (Array.isArray(spellsRaw) ? spellsRaw : [])
|
||||
.map((spellRaw): SpellCatalogItem | null => {
|
||||
if (!isRecord(spellRaw)) {
|
||||
@@ -2471,7 +2509,20 @@ function WikiView() {
|
||||
return;
|
||||
}
|
||||
|
||||
setTopbarGroups((current) => (areTopbarGroupsEquivalent(current, data.groups as TopbarMenuGroup[]) ? current : (data.groups as TopbarMenuGroup[])));
|
||||
const nextGroups = data.groups as TopbarMenuGroup[];
|
||||
let nextSignature = "";
|
||||
try {
|
||||
nextSignature = JSON.stringify(nextGroups);
|
||||
} catch {
|
||||
nextSignature = `groups:${nextGroups.length}:${Date.now()}`;
|
||||
}
|
||||
|
||||
if (topbarGroupsSignatureRef.current === nextSignature) {
|
||||
return;
|
||||
}
|
||||
|
||||
topbarGroupsSignatureRef.current = nextSignature;
|
||||
setTopbarGroups(nextGroups);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2829,39 +2880,6 @@ function WikiView() {
|
||||
[characterOptions?.backgrounds, sourceBuckets, backgroundSearch]
|
||||
);
|
||||
|
||||
const classTotalPages = Math.max(1, Math.ceil(filteredClassOptions.length / CARD_PAGE_SIZE));
|
||||
const speciesTotalPages = Math.max(1, Math.ceil(filteredSpeciesOptions.length / CARD_PAGE_SIZE));
|
||||
const backgroundTotalPages = Math.max(1, Math.ceil(filteredBackgroundOptions.length / CARD_PAGE_SIZE));
|
||||
|
||||
const classPageSafe = clampPage(classPage, filteredClassOptions.length);
|
||||
const speciesPageSafe = clampPage(speciesPage, filteredSpeciesOptions.length);
|
||||
const backgroundPageSafe = clampPage(backgroundPage, filteredBackgroundOptions.length);
|
||||
|
||||
const classPageOptions = useMemo(
|
||||
() => paginateOptions(filteredClassOptions, classPageSafe),
|
||||
[filteredClassOptions, classPageSafe]
|
||||
);
|
||||
const speciesPageOptions = useMemo(
|
||||
() => paginateOptions(filteredSpeciesOptions, speciesPageSafe),
|
||||
[filteredSpeciesOptions, speciesPageSafe]
|
||||
);
|
||||
const backgroundPageOptions = useMemo(
|
||||
() => paginateOptions(filteredBackgroundOptions, backgroundPageSafe),
|
||||
[filteredBackgroundOptions, backgroundPageSafe]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setClassPage((current) => clampPage(current, filteredClassOptions.length));
|
||||
}, [filteredClassOptions.length]);
|
||||
|
||||
useEffect(() => {
|
||||
setSpeciesPage((current) => clampPage(current, filteredSpeciesOptions.length));
|
||||
}, [filteredSpeciesOptions.length]);
|
||||
|
||||
useEffect(() => {
|
||||
setBackgroundPage((current) => clampPage(current, filteredBackgroundOptions.length));
|
||||
}, [filteredBackgroundOptions.length]);
|
||||
|
||||
useEffect(() => {
|
||||
const selectedRefs = [
|
||||
characterDraft?.selections.class?.entityRef,
|
||||
@@ -2883,6 +2901,12 @@ function WikiView() {
|
||||
: null;
|
||||
const entityPopoverDetail = entityPopover ? detailCache[entityPopover.entityRef] ?? null : null;
|
||||
|
||||
useEffect(() => {
|
||||
if (characterModalMode !== "editor") {
|
||||
closeEntityPopover();
|
||||
}
|
||||
}, [characterModalMode, closeEntityPopover]);
|
||||
|
||||
useEffect(() => {
|
||||
if (characterModalMode !== "editor" || !entityPopover) {
|
||||
return;
|
||||
@@ -2890,22 +2914,22 @@ function WikiView() {
|
||||
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === "Escape") {
|
||||
setEntityPopover(null);
|
||||
closeEntityPopover();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", onKeyDown);
|
||||
return () => window.removeEventListener("keydown", onKeyDown);
|
||||
}, [characterModalMode, entityPopover]);
|
||||
}, [characterModalMode, closeEntityPopover, entityPopover]);
|
||||
|
||||
useEffect(() => {
|
||||
if (characterModalMode !== "editor" || !entityPopover) {
|
||||
return;
|
||||
}
|
||||
if (characterStep < 0 || characterStep > 2) {
|
||||
setEntityPopover(null);
|
||||
closeEntityPopover();
|
||||
}
|
||||
}, [characterModalMode, characterStep, entityPopover]);
|
||||
}, [characterModalMode, characterStep, closeEntityPopover, entityPopover]);
|
||||
|
||||
const classSkillData = useMemo(
|
||||
() => parseClassSkills(selectedClassDetail),
|
||||
@@ -4168,7 +4192,7 @@ function WikiView() {
|
||||
<div className="entity-layout">
|
||||
<div className="entity-list-panel entity-list-panel--solo">
|
||||
<div className="entity-card-grid">
|
||||
{classPageOptions.map((option) => {
|
||||
{filteredClassOptions.map((option) => {
|
||||
const isSelected = characterDraft.selections.class?.entityRef === option.entityRef;
|
||||
const imageUrl = buildAssetUrl(wikiUrl, option.imagePath);
|
||||
const sourceBadge = getSourceBadgeText(option.source, option.sourceEdition);
|
||||
@@ -4179,14 +4203,7 @@ function WikiView() {
|
||||
key={option.entityRef}
|
||||
className={isSelected ? "entity-tile is-selected" : "entity-tile"}
|
||||
onClick={() => {
|
||||
updateDraft((draft) => ({
|
||||
...draft,
|
||||
selections: {
|
||||
...draft.selections,
|
||||
class: toEntityRef(option),
|
||||
subclass: null
|
||||
}
|
||||
}));
|
||||
setPendingEntitySelection({ kind: "class", option });
|
||||
openEntityPopover("class", option.entityRef);
|
||||
}}
|
||||
>
|
||||
@@ -4205,22 +4222,6 @@ function WikiView() {
|
||||
|
||||
{filteredClassOptions.length === 0 ? <p className="character-empty">No classes match the selected source buckets.</p> : null}
|
||||
|
||||
<div className="entity-pagination">
|
||||
<button type="button" onClick={() => setClassPage((it) => Math.max(1, it - 1))} disabled={classPageSafe <= 1}>
|
||||
Previous
|
||||
</button>
|
||||
<span>
|
||||
Page {classPageSafe}/{classTotalPages} ({filteredClassOptions.length} total)
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setClassPage((it) => Math.min(classTotalPages, it + 1))}
|
||||
disabled={classPageSafe >= classTotalPages}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="entity-list-actions">
|
||||
<button
|
||||
type="button"
|
||||
@@ -4229,6 +4230,7 @@ function WikiView() {
|
||||
if (!characterDraft.selections.class) {
|
||||
return;
|
||||
}
|
||||
setPendingEntitySelection(null);
|
||||
openEntityPopover("class", characterDraft.selections.class.entityRef);
|
||||
}}
|
||||
disabled={!characterDraft.selections.class}
|
||||
@@ -4252,7 +4254,7 @@ function WikiView() {
|
||||
<div className="entity-layout">
|
||||
<div className="entity-list-panel entity-list-panel--solo">
|
||||
<div className="entity-card-grid">
|
||||
{speciesPageOptions.map((option) => {
|
||||
{filteredSpeciesOptions.map((option) => {
|
||||
const isSelected = characterDraft.selections.species?.entityRef === option.entityRef;
|
||||
const imageUrl = buildAssetUrl(wikiUrl, option.imagePath);
|
||||
const sourceBadge = getSourceBadgeText(option.source, option.sourceEdition);
|
||||
@@ -4263,13 +4265,7 @@ function WikiView() {
|
||||
key={option.entityRef}
|
||||
className={isSelected ? "entity-tile is-selected" : "entity-tile"}
|
||||
onClick={() => {
|
||||
updateDraft((draft) => ({
|
||||
...draft,
|
||||
selections: {
|
||||
...draft.selections,
|
||||
species: toEntityRef(option)
|
||||
}
|
||||
}));
|
||||
setPendingEntitySelection({ kind: "species", option });
|
||||
openEntityPopover("species", option.entityRef);
|
||||
}}
|
||||
>
|
||||
@@ -4288,22 +4284,6 @@ function WikiView() {
|
||||
|
||||
{filteredSpeciesOptions.length === 0 ? <p className="character-empty">No species match the selected source buckets.</p> : null}
|
||||
|
||||
<div className="entity-pagination">
|
||||
<button type="button" onClick={() => setSpeciesPage((it) => Math.max(1, it - 1))} disabled={speciesPageSafe <= 1}>
|
||||
Previous
|
||||
</button>
|
||||
<span>
|
||||
Page {speciesPageSafe}/{speciesTotalPages} ({filteredSpeciesOptions.length} total)
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setSpeciesPage((it) => Math.min(speciesTotalPages, it + 1))}
|
||||
disabled={speciesPageSafe >= speciesTotalPages}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="entity-list-actions">
|
||||
<button
|
||||
type="button"
|
||||
@@ -4312,6 +4292,7 @@ function WikiView() {
|
||||
if (!characterDraft.selections.species) {
|
||||
return;
|
||||
}
|
||||
setPendingEntitySelection(null);
|
||||
openEntityPopover("species", characterDraft.selections.species.entityRef);
|
||||
}}
|
||||
disabled={!characterDraft.selections.species}
|
||||
@@ -4337,7 +4318,7 @@ function WikiView() {
|
||||
<div className="entity-layout">
|
||||
<div className="entity-list-panel entity-list-panel--solo">
|
||||
<div className="entity-card-grid">
|
||||
{backgroundPageOptions.map((option) => {
|
||||
{filteredBackgroundOptions.map((option) => {
|
||||
const isSelected = characterDraft.selections.background?.entityRef === option.entityRef;
|
||||
const imageUrl = buildAssetUrl(wikiUrl, option.imagePath);
|
||||
const sourceBadge = getSourceBadgeText(option.source, option.sourceEdition);
|
||||
@@ -4348,21 +4329,7 @@ function WikiView() {
|
||||
key={option.entityRef}
|
||||
className={isSelected ? "entity-tile is-selected" : "entity-tile"}
|
||||
onClick={() => {
|
||||
updateDraft((draft) => ({
|
||||
...draft,
|
||||
selections: {
|
||||
...draft.selections,
|
||||
background: toEntityRef(option)
|
||||
},
|
||||
steps: {
|
||||
...draft.steps,
|
||||
abilityScores: {
|
||||
...draft.steps.abilityScores,
|
||||
backgroundBonusModeIndex: 0,
|
||||
backgroundBonusSelections: []
|
||||
}
|
||||
}
|
||||
}));
|
||||
setPendingEntitySelection({ kind: "background", option });
|
||||
openEntityPopover("background", option.entityRef);
|
||||
}}
|
||||
>
|
||||
@@ -4383,26 +4350,6 @@ function WikiView() {
|
||||
<p className="character-empty">No backgrounds match the selected source buckets.</p>
|
||||
) : null}
|
||||
|
||||
<div className="entity-pagination">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setBackgroundPage((it) => Math.max(1, it - 1))}
|
||||
disabled={backgroundPageSafe <= 1}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<span>
|
||||
Page {backgroundPageSafe}/{backgroundTotalPages} ({filteredBackgroundOptions.length} total)
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setBackgroundPage((it) => Math.min(backgroundTotalPages, it + 1))}
|
||||
disabled={backgroundPageSafe >= backgroundTotalPages}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="entity-list-actions">
|
||||
<button
|
||||
type="button"
|
||||
@@ -4411,6 +4358,7 @@ function WikiView() {
|
||||
if (!characterDraft.selections.background) {
|
||||
return;
|
||||
}
|
||||
setPendingEntitySelection(null);
|
||||
openEntityPopover("background", characterDraft.selections.background.entityRef);
|
||||
}}
|
||||
disabled={!characterDraft.selections.background}
|
||||
@@ -5973,7 +5921,7 @@ function WikiView() {
|
||||
<div
|
||||
className="entity-popover-backdrop"
|
||||
role="presentation"
|
||||
onClick={() => setEntityPopover(null)}
|
||||
onClick={closeEntityPopover}
|
||||
>
|
||||
<section
|
||||
className="entity-popover"
|
||||
@@ -5990,11 +5938,27 @@ function WikiView() {
|
||||
? "Species details"
|
||||
: "Background details"}
|
||||
</h4>
|
||||
<button type="button" className="is-subtle" onClick={() => setEntityPopover(null)}>
|
||||
Close
|
||||
<button type="button" className="is-subtle" onClick={closeEntityPopover}>
|
||||
{pendingEntitySelection ? "Cancel" : "Close"}
|
||||
</button>
|
||||
</header>
|
||||
{renderEntityDetailContent(entityPopoverDetail, entityPopover.kind)}
|
||||
<div className="entity-popover-body">{renderEntityDetailContent(entityPopoverDetail, entityPopover.kind)}</div>
|
||||
<footer className="entity-popover-footer">
|
||||
{pendingEntitySelection ? (
|
||||
<>
|
||||
<button type="button" className="is-subtle" onClick={closeEntityPopover}>
|
||||
Cancel
|
||||
</button>
|
||||
<button type="button" onClick={confirmPendingEntitySelection}>
|
||||
Add {pendingEntitySelection.kind}
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<button type="button" className="is-subtle" onClick={closeEntityPopover}>
|
||||
Close
|
||||
</button>
|
||||
)}
|
||||
</footer>
|
||||
</section>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
+30
-13
@@ -69,7 +69,7 @@ body {
|
||||
radial-gradient(circle at 16% 0%, rgba(71, 131, 206, 0.34), transparent 34%),
|
||||
radial-gradient(circle at 88% -8%, rgba(234, 163, 78, 0.28), transparent 40%),
|
||||
linear-gradient(180deg, rgba(14, 24, 40, 0.96), rgba(9, 16, 28, 0.97));
|
||||
backdrop-filter: blur(12px);
|
||||
/* backdrop-filter: blur(12px); */
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
isolation: isolate;
|
||||
@@ -516,9 +516,9 @@ body {
|
||||
border-radius: 16px;
|
||||
background: linear-gradient(180deg, rgba(14, 22, 35, 0.98), rgba(8, 14, 24, 0.99));
|
||||
box-shadow: var(--shadow);
|
||||
display: grid;
|
||||
grid-template-rows: auto auto 1fr;
|
||||
overflow: hidden;
|
||||
/* display: grid; */
|
||||
/* grid-template-rows: auto auto 1fr; */
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.character-modal button,
|
||||
@@ -1529,6 +1529,7 @@ body {
|
||||
.entity-card-grid {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
max-height: clamp(260px, 44vh, 560px);
|
||||
overflow: auto;
|
||||
padding-right: 4px;
|
||||
gap: 10px;
|
||||
@@ -1737,7 +1738,7 @@ body {
|
||||
color: #edf4ff;
|
||||
overflow: hidden;
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
padding: 0 !important;
|
||||
display: block;
|
||||
min-height: 0;
|
||||
aspect-ratio: 1 / 1;
|
||||
@@ -1837,17 +1838,18 @@ body {
|
||||
place-items: center;
|
||||
padding: 18px;
|
||||
background: rgba(2, 6, 12, 0.74);
|
||||
backdrop-filter: blur(2px);
|
||||
/* backdrop-filter: blur(2px); */
|
||||
}
|
||||
|
||||
.entity-popover {
|
||||
width: 70%;
|
||||
max-height: calc(70vh - 36px);
|
||||
overflow: auto;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid var(--line-strong);
|
||||
border-radius: 14px;
|
||||
background: rgba(8, 12, 20, 0.98);
|
||||
padding: 12px;
|
||||
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
@@ -1856,9 +1858,8 @@ body {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding-bottom: 10px;
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.entity-popover-header h4 {
|
||||
@@ -1867,6 +1868,22 @@ body {
|
||||
font-size: 1.05rem;
|
||||
}
|
||||
|
||||
.entity-popover-body {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.entity-popover-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding: 12px;
|
||||
border-top: 1px solid var(--line);
|
||||
background: rgba(5, 9, 16, 0.94);
|
||||
}
|
||||
|
||||
.entity-detail--popover {
|
||||
min-height: 0;
|
||||
}
|
||||
@@ -1886,6 +1903,7 @@ body {
|
||||
|
||||
.chooser-layout {
|
||||
min-height: 0;
|
||||
max-height: 62vh;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
gap: 12px;
|
||||
@@ -2249,10 +2267,10 @@ body {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ability-score-strip,
|
||||
/* .ability-score-strip,
|
||||
.ability-assignment-grid--ability-step {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
} */
|
||||
|
||||
.chooser-layout {
|
||||
grid-template-columns: 1fr;
|
||||
@@ -2305,7 +2323,6 @@ body {
|
||||
width: calc(100vw - 20px);
|
||||
max-height: calc(100vh - 20px);
|
||||
border-radius: 12px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.entity-popover-header {
|
||||
|
||||
Reference in new issue
Block a user