release: v0.19.0
Release v0.19.0. See the `## [0.19.0] — 2026-09-29` section of [CHANGELOG.md](https://github.com/ralksta/immich-folio/blob/dev/CHANGELOG.md) for the full list. Highlights: client proofing links (#683), custom content pages (#738), asset picker search (#740), concurrent-edit detection (#742), env-locked settings (#739), an accessibility baseline (#741), three security fixes with advisories (#737, #755, #759), and a pre-release quality pass (#780–#797). --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: ralksta <ralksta@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Ralf <rohlenbo79@gmail.com> Co-authored-by: Paul Thies <110185070+ImScheinox@users.noreply.github.com> Co-authored-by: lancetm714 <108419425+lancetm714@users.noreply.github.com> Co-authored-by: Lance Martin <lancetaylor95@gmail.com>
This commit is contained in:
82
app/admin/components/journal/PageSettingsPanel.tsx
Normal file
82
app/admin/components/journal/PageSettingsPanel.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import type { ParsedJournal } from '@/lib/journal';
|
||||
import PasswordField from '../fields/PasswordField';
|
||||
import { IconX } from '../Icons';
|
||||
|
||||
type Frontmatter = ParsedJournal['frontmatter'];
|
||||
|
||||
interface PageSettingsPanelProps {
|
||||
frontmatter: Frontmatter;
|
||||
onChange: (updates: Partial<Frontmatter>) => void;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A content page's settings inside the editor (#722): a side panel rather than
|
||||
* the journal's modal, so the preview stays in view. The slug and the menu
|
||||
* place are edited in Pages, where the collision check and the menu live.
|
||||
*/
|
||||
export function PageSettingsPanel({ frontmatter, onChange, onClose }: PageSettingsPanelProps) {
|
||||
useEffect(() => {
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') onClose();
|
||||
};
|
||||
window.addEventListener('keydown', onKey);
|
||||
return () => window.removeEventListener('keydown', onKey);
|
||||
}, [onClose]);
|
||||
|
||||
return (
|
||||
<aside className="page-settings-panel" aria-label="Page settings">
|
||||
<div className="page-settings-panel-head">
|
||||
<h3>Page settings</h3>
|
||||
<button type="button" className="admin-btn-icon" onClick={onClose} title="Close">
|
||||
<IconX size={14} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="admin-field">
|
||||
<label htmlFor="page-settings-description">SEO description</label>
|
||||
<textarea
|
||||
id="page-settings-description"
|
||||
rows={3}
|
||||
value={frontmatter.description || ''}
|
||||
placeholder="One or two sentences for search engines and link previews"
|
||||
// One line in the frontmatter: a line break would end the value.
|
||||
onChange={(e) => onChange({ description: e.target.value.replace(/\s*\n\s*/g, ' ') })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="setting-row"
|
||||
onClick={() => onChange({ draft: !frontmatter.draft })}
|
||||
aria-pressed={!!frontmatter.draft}
|
||||
>
|
||||
<span className="setting-row-info">
|
||||
<span className="setting-row-title">Draft</span>
|
||||
<span className="setting-row-desc">
|
||||
Only you can see a draft, and it stays out of the menu and the sitemap.
|
||||
</span>
|
||||
</span>
|
||||
<span className={`switch-toggle switch-toggle--sm ${frontmatter.draft ? 'on' : ''}`}>
|
||||
<span className="switch-slider" />
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div className="admin-field">
|
||||
<span className="admin-field-label">Password (optional)</span>
|
||||
<PasswordField
|
||||
value={frontmatter.password || undefined}
|
||||
onChange={(password) => onChange({ password: password ?? '' })}
|
||||
label="Page password"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<p className="page-settings-panel-note">
|
||||
Settings are saved with the page. The URL and the menu place are set in Pages.
|
||||
</p>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user