♻️ refactor(client): 浏览器半拆成 src 模块,client.js 改由构建产出

This commit is contained in:
pyh
2026-10-04 19:01:22 +08:00
parent 3986aac863
commit 68ab60273e
30 changed files with 3506 additions and 1394 deletions
+98
View File
@@ -0,0 +1,98 @@
/**
* This plugin's configuration, rendered on its own page in the plugin
* manager (`plugins.bundle.config`, keyed by this package's name).
*
* The owner asks for two views: `summary` (a one-liner that stands in for the
* row's description) and `page` (the whole form). Everything visible here
* belongs to this package, including the platform-specific permission hint.
*
* @module @dsh-plugin/session-notify/client/ui/ConfigSection
*/
import * as React from 'react'
import { KINDS } from '../constants.js'
import { windowIsAway } from '../platform.js'
import { KindRow } from './KindRow.js'
import { seatTranslator, useOwnStore } from './hooks.js'
import { CSS } from './styles.js'
const h = React.createElement
export function ConfigSection(props) {
const snapshot = useOwnStore(props.store)
const tr = seatTranslator(props, props.fallbackT)
if (props.view === 'summary') return h(React.Fragment, null, tr('settings.description'))
const permission = snapshot.permission
const supported = permission !== 'unsupported'
const failed = permission === 'denied' || snapshot.promptError !== ''
const statusKey = permission === 'granted'
? 'settings.permission.granted'
: permission === 'denied'
? 'settings.permission.denied'
: supported
? 'settings.permission.default'
: 'settings.permission.unsupported'
const permissionText = snapshot.promptError === ''
? `${tr(statusKey)}${permission === 'denied' || !supported ? ` · ${tr(`settings.permission.hint.${props.platform}`)}` : ''}`
: snapshot.promptError
const health = snapshot.health
const healthText = health.state === 'watching'
? tr('settings.health.watching')
: health.state === 'noHooks'
? tr('settings.health.noHooks')
: health.state === 'error'
? tr('settings.health.error', { message: health.message })
: tr('settings.health.starting')
const healthFailed = health.state !== 'watching' && health.state !== 'starting'
return h(React.Fragment, null,
h('style', null, CSS),
h('div', { className: 'dsn-sections' },
// The page header already shows this bundle's title and description, so
// this section opens with what the header cannot say: how alerts are
// carried, and what this form changes.
h('section', { className: 'dsn-section' },
h('p', { className: 'dsn-section-desc' }, tr('config.intro'))),
h('section', { className: 'dsn-section' },
h('h3', { className: 'dsn-section-title' }, tr('config.section.kinds')),
KINDS.map((kind) => h(KindRow, {
key: kind,
label: tr(`settings.kind.${kind}`),
checked: snapshot.kinds[kind] === true,
disabled: false,
onToggle: () => props.setKind(kind, snapshot.kinds[kind] !== true),
})),
h('p', { className: 'dsn-section-desc' }, tr('config.saveNote'))),
h('section', { className: 'dsn-section' },
h('h3', { className: 'dsn-section-title' }, tr('config.section.permission')),
h('div', { className: 'dsn-row' },
h('div', { className: 'dsn-row-text' },
h('p', {
className: `dsn-status${failed ? ' dsn-status-error' : ''}`,
role: failed ? 'alert' : 'status',
}, permissionText)),
h('button', {
type: 'button',
className: 'dsn-button',
disabled: !supported,
onClick: permission === 'granted' ? props.testSystem : props.ask,
}, tr(!supported
? 'settings.action.unsupported'
: permission === 'granted' ? 'settings.action.testSystem' : 'settings.action.allow'))),
h('p', { className: 'dsn-section-desc' }, tr('config.testHint'))),
h('section', { className: 'dsn-section' },
h('h3', { className: 'dsn-section-title' }, tr('config.section.status')),
h('div', { className: 'dsn-row' },
h('div', { className: 'dsn-row-text' },
h('p', { className: 'dsn-status' }, `${tr('config.diag.window')}: ${tr(windowIsAway() ? 'config.diag.away' : 'config.diag.inFront')}`),
h('p', {
className: `dsn-status${healthFailed ? ' dsn-status-error' : ''}`,
role: healthFailed ? 'alert' : 'status',
}, healthText),
h('p', { className: 'dsn-status' }, props.copy.describeDelivery(snapshot.lastDelivery, tr)),
h('p', { className: 'dsn-status' }, props.copy.describeReplay(props.replayCount(), tr))),
h('button', {
type: 'button',
className: 'dsn-button',
onClick: props.testAny,
}, tr('settings.action.testAny'))))))
}