Add collapsible footer help panel
This commit is contained in:
@@ -66,13 +66,16 @@
|
|||||||
class="hidden"
|
class="hidden"
|
||||||
aria-label="Chat Grid, press question mark for help."
|
aria-label="Chat Grid, press question mark for help."
|
||||||
></canvas>
|
></canvas>
|
||||||
<div id="instructions" class="hidden"></div>
|
|
||||||
|
|
||||||
<footer id="appFooter">
|
<footer id="appFooter">
|
||||||
<small id="appVersion">Another AI experiment with Jage. Version</small>
|
<small id="appVersion">Another AI experiment with Jage. Version</small>
|
||||||
<small id="appGithubLinkWrap">
|
<small id="appGithubLinkWrap">
|
||||||
<a id="appGithubLink" href="https://www.github.com/jage9/chat_grid">Chat Grid on Github</a>
|
<a id="appGithubLink" href="https://www.github.com/jage9/chat_grid">Chat Grid on Github</a>
|
||||||
</small>
|
</small>
|
||||||
|
<section id="helpSection" class="updates-section hidden">
|
||||||
|
<h2>Help</h2>
|
||||||
|
<button id="helpToggle" type="button" aria-expanded="false" aria-controls="instructions">Show help</button>
|
||||||
|
<div id="instructions" class="hidden" hidden></div>
|
||||||
|
</section>
|
||||||
<section id="updatesSection" class="updates-section">
|
<section id="updatesSection" class="updates-section">
|
||||||
<h2>Latest Updates</h2>
|
<h2>Latest Updates</h2>
|
||||||
<button id="updatesToggle" type="button" aria-expanded="false" aria-controls="updatesPanel">
|
<button id="updatesToggle" type="button" aria-expanded="false" aria-controls="updatesPanel">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Maintainer-controlled web client version metadata.
|
// Maintainer-controlled web client version metadata.
|
||||||
window.CHGRID_RELEASE_VERSION = "0.1.0";
|
window.CHGRID_RELEASE_VERSION = "0.1.0";
|
||||||
window.CHGRID_BUILD_REVISION = "R340";
|
window.CHGRID_BUILD_REVISION = "R341";
|
||||||
window.CHGRID_WEB_VERSION = `${window.CHGRID_RELEASE_VERSION} ${window.CHGRID_BUILD_REVISION}`;
|
window.CHGRID_WEB_VERSION = `${window.CHGRID_RELEASE_VERSION} ${window.CHGRID_BUILD_REVISION}`;
|
||||||
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
||||||
window.CHGRID_TIME_ZONE = "America/Detroit";
|
window.CHGRID_TIME_ZONE = "America/Detroit";
|
||||||
|
|||||||
@@ -113,6 +113,8 @@ type Dom = {
|
|||||||
authSessionText: HTMLParagraphElement;
|
authSessionText: HTMLParagraphElement;
|
||||||
authModeSeparator: HTMLElement;
|
authModeSeparator: HTMLElement;
|
||||||
showRegisterButton: HTMLButtonElement;
|
showRegisterButton: HTMLButtonElement;
|
||||||
|
helpSection: HTMLElement;
|
||||||
|
helpToggle: HTMLButtonElement;
|
||||||
updatesSection: HTMLElement;
|
updatesSection: HTMLElement;
|
||||||
updatesToggle: HTMLButtonElement;
|
updatesToggle: HTMLButtonElement;
|
||||||
updatesPanel: HTMLDivElement;
|
updatesPanel: HTMLDivElement;
|
||||||
@@ -148,6 +150,8 @@ const dom: Dom = {
|
|||||||
authSessionText: requiredById('authSessionText'),
|
authSessionText: requiredById('authSessionText'),
|
||||||
authModeSeparator: requiredById('authModeSeparator'),
|
authModeSeparator: requiredById('authModeSeparator'),
|
||||||
showRegisterButton: requiredById('showRegisterButton'),
|
showRegisterButton: requiredById('showRegisterButton'),
|
||||||
|
helpSection: requiredById('helpSection'),
|
||||||
|
helpToggle: requiredById('helpToggle'),
|
||||||
updatesSection: requiredById('updatesSection'),
|
updatesSection: requiredById('updatesSection'),
|
||||||
updatesToggle: requiredById('updatesToggle'),
|
updatesToggle: requiredById('updatesToggle'),
|
||||||
updatesPanel: requiredById('updatesPanel'),
|
updatesPanel: requiredById('updatesPanel'),
|
||||||
@@ -435,13 +439,18 @@ function setUpdatesExpanded(expanded: boolean): void {
|
|||||||
dom.updatesPanel.classList.toggle('hidden', !expanded);
|
dom.updatesPanel.classList.toggle('hidden', !expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Toggles help panel visibility and syncs associated ARIA state. */
|
||||||
|
function setHelpExpanded(expanded: boolean): void {
|
||||||
|
dom.helpToggle.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
||||||
|
dom.helpToggle.textContent = expanded ? 'Hide help' : 'Show help';
|
||||||
|
dom.instructions.hidden = !expanded;
|
||||||
|
dom.instructions.classList.toggle('hidden', !expanded);
|
||||||
|
}
|
||||||
|
|
||||||
/** Renders help sections into the footer help container and builds linearized viewer lines. */
|
/** Renders help sections into the footer help container and builds linearized viewer lines. */
|
||||||
function renderHelp(help: HelpData): void {
|
function renderHelp(help: HelpData): void {
|
||||||
const lines = buildHelpLines(help);
|
const lines = buildHelpLines(help);
|
||||||
dom.instructions.innerHTML = '';
|
dom.instructions.innerHTML = '';
|
||||||
const heading = document.createElement('h2');
|
|
||||||
heading.textContent = 'Help';
|
|
||||||
dom.instructions.appendChild(heading);
|
|
||||||
for (const section of help.sections) {
|
for (const section of help.sections) {
|
||||||
const sectionHeading = document.createElement('h3');
|
const sectionHeading = document.createElement('h3');
|
||||||
sectionHeading.textContent = section.title;
|
sectionHeading.textContent = section.title;
|
||||||
@@ -458,6 +467,8 @@ function renderHelp(help: HelpData): void {
|
|||||||
mainHelpViewerLines = lines;
|
mainHelpViewerLines = lines;
|
||||||
helpViewerLines = lines;
|
helpViewerLines = lines;
|
||||||
helpViewerIndex = 0;
|
helpViewerIndex = 0;
|
||||||
|
dom.helpSection.classList.remove('hidden');
|
||||||
|
setHelpExpanded(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Loads runtime help content from `help.json` and applies it when available. */
|
/** Loads runtime help content from `help.json` and applies it when available. */
|
||||||
@@ -465,15 +476,21 @@ async function loadHelp(): Promise<void> {
|
|||||||
try {
|
try {
|
||||||
const response = await fetch(withBase('help.json'), { cache: 'no-store' });
|
const response = await fetch(withBase('help.json'), { cache: 'no-store' });
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
dom.helpSection.classList.add('hidden');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const help = (await response.json()) as HelpData;
|
const help = (await response.json()) as HelpData;
|
||||||
if (!Array.isArray(help.sections) || help.sections.length === 0) {
|
if (!Array.isArray(help.sections) || help.sections.length === 0) {
|
||||||
|
dom.helpSection.classList.add('hidden');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderHelp(help);
|
renderHelp(help);
|
||||||
|
dom.helpToggle.addEventListener('click', () => {
|
||||||
|
const expanded = dom.helpToggle.getAttribute('aria-expanded') === 'true';
|
||||||
|
setHelpExpanded(!expanded);
|
||||||
|
});
|
||||||
} catch {
|
} catch {
|
||||||
// Keep existing/static help if loading fails.
|
dom.helpSection.classList.add('hidden');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ body {
|
|||||||
margin: 0.35rem 0;
|
margin: 0.35rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#helpToggle,
|
||||||
#updatesToggle {
|
#updatesToggle {
|
||||||
margin-bottom: 0.35rem;
|
margin-bottom: 0.35rem;
|
||||||
}
|
}
|
||||||
@@ -202,10 +203,16 @@ canvas {
|
|||||||
#instructions {
|
#instructions {
|
||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
margin: 0.75rem auto;
|
margin: 0.35rem auto 0;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#instructions h3 {
|
||||||
|
color: #cbd5e1;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
margin: 0.35rem 0 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user