settings page
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import { Section, Row, SubHeading, Toggle, Input, Segmented, type PrefsLike } from '../_ui'
|
||||
import { subtitleClasses } from '../../../lib/subtitle-style'
|
||||
|
||||
export function AudioSection({ prefs }: { prefs: PrefsLike }) {
|
||||
const preview = subtitleClasses({
|
||||
subtitleFontSize: prefs.subtitleFontSize,
|
||||
subtitleFontFamily: prefs.subtitleFontFamily,
|
||||
subtitleBackground: prefs.subtitleBackground,
|
||||
subtitleEdge: prefs.subtitleEdge,
|
||||
subtitlePosition: prefs.subtitlePosition,
|
||||
subtitleColor: prefs.subtitleColor,
|
||||
})
|
||||
const previewClass = preview.className
|
||||
.replace(/\babsolute\b|\binset-x-0\b|\bbottom-32\b|\btop-24\b/g, '')
|
||||
return (
|
||||
<Section id="audio" title="Audio & Subtitles" description="Default tracks for new playback sessions">
|
||||
<SubHeading label="Languages & loudness" />
|
||||
<Row label="Subtitle mode" hint="When subtitles should appear by default">
|
||||
<Segmented
|
||||
value={prefs.subtitleMode}
|
||||
onChange={v => prefs.setPreference('subtitleMode', v)}
|
||||
options={[
|
||||
{ value: 'none', label: 'Off' },
|
||||
{ value: 'default', label: 'Default' },
|
||||
{ value: 'always', label: 'Always' },
|
||||
]}
|
||||
/>
|
||||
</Row>
|
||||
<Row label="Subtitle language" hint="ISO 639 code, e.g. eng, fra, spa">
|
||||
<Input value={prefs.subtitleLanguage} onChange={v => prefs.setPreference('subtitleLanguage', v)} placeholder="eng" width="w-24" />
|
||||
</Row>
|
||||
<Row label="Audio language" hint="ISO 639 code, e.g. eng, jpn, fra">
|
||||
<Input value={prefs.audioLanguage} onChange={v => prefs.setPreference('audioLanguage', v)} placeholder="eng" width="w-24" />
|
||||
</Row>
|
||||
<Row label="Volume boost" hint="Allow volume past 100% via Web Audio gain (1.0 - 3.0)">
|
||||
<Segmented
|
||||
value={String(prefs.volumeBoost)}
|
||||
onChange={v => prefs.setPreference('volumeBoost', Number(v))}
|
||||
options={[
|
||||
{ value: '1', label: '100%' },
|
||||
{ value: '1.5', label: '150%' },
|
||||
{ value: '2', label: '200%' },
|
||||
{ value: '3', label: '300%' },
|
||||
]}
|
||||
/>
|
||||
</Row>
|
||||
<Row label="Night mode" hint="Compress dynamic range - lifts dialogue, tames action">
|
||||
<Toggle value={prefs.nightMode} onChange={v => prefs.setPreference('nightMode', v)} />
|
||||
</Row>
|
||||
<Row label="Audio passthrough" hint="Request bitstream passthrough for Dolby TrueHD / DTS-HD MA. Requires receiver support and may not work in all browsers.">
|
||||
<Toggle value={prefs.audioPassthrough} onChange={v => prefs.setPreference('audioPassthrough', v)} />
|
||||
</Row>
|
||||
|
||||
<SubHeading label="Subtitle styling" />
|
||||
<Row label={`Subtitle size (${prefs.subtitleFontSize}px)`} hint="Caption text size">
|
||||
<input
|
||||
type="range"
|
||||
min={12}
|
||||
max={72}
|
||||
step={1}
|
||||
value={prefs.subtitleFontSize}
|
||||
onChange={e => prefs.setPreference('subtitleFontSize', Number(e.target.value))}
|
||||
className="subtitle-size-slider w-full max-w-[200px] h-7 appearance-none bg-transparent cursor-pointer"
|
||||
/>
|
||||
</Row>
|
||||
<Row label="Background" hint="Box behind the caption text">
|
||||
<Segmented
|
||||
value={prefs.subtitleBackground}
|
||||
onChange={v => prefs.setPreference('subtitleBackground', v)}
|
||||
options={[
|
||||
{ value: 'none', label: 'None' },
|
||||
{ value: 'subtle', label: 'Subtle' },
|
||||
{ value: 'solid', label: 'Solid' },
|
||||
]}
|
||||
/>
|
||||
</Row>
|
||||
<Row label="Text edge" hint="Shadow or outline to separate text from the picture">
|
||||
<Segmented
|
||||
value={prefs.subtitleEdge}
|
||||
onChange={v => prefs.setPreference('subtitleEdge', v)}
|
||||
options={[
|
||||
{ value: 'none', label: 'None' },
|
||||
{ value: 'shadow', label: 'Shadow' },
|
||||
{ value: 'outline', label: 'Outline' },
|
||||
]}
|
||||
/>
|
||||
</Row>
|
||||
<Row label="Position" hint="Where captions sit on screen">
|
||||
<Segmented
|
||||
value={prefs.subtitlePosition}
|
||||
onChange={v => prefs.setPreference('subtitlePosition', v)}
|
||||
options={[
|
||||
{ value: 'bottom', label: 'Bottom' },
|
||||
{ value: 'top', label: 'Top' },
|
||||
]}
|
||||
/>
|
||||
</Row>
|
||||
<Row label="Text colour" hint="Caption colour - pick what stays readable on your content">
|
||||
<Segmented
|
||||
value={prefs.subtitleColor}
|
||||
onChange={v => prefs.setPreference('subtitleColor', v)}
|
||||
options={[
|
||||
{ value: 'white', label: 'White' },
|
||||
{ value: 'yellow', label: 'Yellow' },
|
||||
{ value: 'cyan', label: 'Cyan' },
|
||||
]}
|
||||
/>
|
||||
</Row>
|
||||
<Row label="Font family" hint="Typeface used for caption text">
|
||||
<Segmented
|
||||
value={prefs.subtitleFontFamily}
|
||||
onChange={v => prefs.setPreference('subtitleFontFamily', v)}
|
||||
options={[
|
||||
{ value: 'sans', label: 'Sans' },
|
||||
{ value: 'serif', label: 'Display' },
|
||||
{ value: 'mono', label: 'Mono' },
|
||||
]}
|
||||
/>
|
||||
</Row>
|
||||
|
||||
<div className="pt-2 pb-1">
|
||||
<p className="text-[11.5px] uppercase tracking-[0.14em] text-text-3 mb-2 font-medium">Preview</p>
|
||||
<div className="relative h-44 rounded-xl overflow-hidden border border-border bg-[radial-gradient(ellipse_at_30%_20%,rgba(245,182,66,0.12),transparent_55%),radial-gradient(ellipse_at_75%_80%,rgba(64,80,120,0.35),transparent_60%),linear-gradient(180deg,#1a1610_0%,#0c0a08_100%)]">
|
||||
<div className={`flex ${prefs.subtitlePosition === 'top' ? 'items-start pt-5' : 'items-end pb-5'} justify-center h-full px-6`}>
|
||||
<div className={previewClass} style={preview.style}>
|
||||
<span data-cue>The signal cuts through the static, just for a moment.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user