Somewhere to type the words
Two places, because the words are two kinds. The ones that mean you wherever they are said go in Settings, next to the rest of what a message looks like; the ones that only mean you on one network go on that account's own card, under the name it calls you by. Neither is a preference of this window. Both read and write the daemon's own lists, because a highlight kept here could colour a line and could never reach a phone - so the global one is not a StringSetting, though it is built to look exactly like its neighbours. Both say the two things somebody will otherwise find out by surprise: whole words only, and they apply to what arrives after they are added rather than to what is already in the log. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+1
-1
Submodule nobilis updated: c6c6a07177...9577b117c5
@@ -340,6 +340,27 @@ function AccountRow({ account }: { account: Account }): JSX.Element {
|
||||
you does not change.
|
||||
</div>
|
||||
|
||||
{/* The other half of being addressed: your name is simply the one
|
||||
word everybody has. Per account rather than everywhere, because
|
||||
a word that means you on one network is somebody's ordinary
|
||||
vocabulary on another - the words that apply everywhere are in
|
||||
Settings. */}
|
||||
<LabeledInput
|
||||
label="Highlight keywords"
|
||||
defaultValue={(account.highlightKeywords ?? []).join(', ')}
|
||||
placeholder="a project, a name you also answer to"
|
||||
onCommit={(words) =>
|
||||
call('setHighlightKeywords', {
|
||||
accountId: account.id,
|
||||
keywords: words.split(',')
|
||||
})
|
||||
}
|
||||
/>
|
||||
<div className="small muted">
|
||||
Separate them with commas. Whole words only, and case does not
|
||||
matter. They apply to messages that arrive after you add them.
|
||||
</div>
|
||||
|
||||
<GroupIcons accountId={account.id} />
|
||||
<HiddenAndMuted accountId={account.id} />
|
||||
|
||||
|
||||
@@ -11,6 +11,68 @@ import { useChat, usePref, useStore } from '../../state/hooks'
|
||||
import { Icon } from '../Icon'
|
||||
import type { Account, DccPrefs } from '../../../../shared/wire'
|
||||
|
||||
/**
|
||||
* The words that count on every account.
|
||||
*
|
||||
* Not a `StringSetting`, which writes to this window's own preferences: a
|
||||
* highlight is decided in the daemon, where it becomes the flag the mentions
|
||||
* inbox reads and the notification that reaches a phone. So this reads and
|
||||
* writes the daemon's own list, and looks exactly like the settings either
|
||||
* side of it.
|
||||
*/
|
||||
function GlobalHighlightKeywords(): JSX.Element {
|
||||
const store = useStore()
|
||||
const [words, setWords] = useState('')
|
||||
const [saved, setSaved] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
void window.moho
|
||||
.rpc<{ global: string[] }>('getHighlightKeywords')
|
||||
.then((answer) => {
|
||||
const text = (answer.global || []).join(', ')
|
||||
setWords(text)
|
||||
setSaved(text)
|
||||
})
|
||||
.catch(() => {
|
||||
/* An empty box is what somebody with no keywords sees anyway. */
|
||||
})
|
||||
}, [])
|
||||
|
||||
const commit = (): void => {
|
||||
if (words === saved) return
|
||||
void window.moho
|
||||
.rpc<{ global: string[] }>('setHighlightKeywords', { keywords: words.split(',') })
|
||||
// The daemon tidies the list - blanks out, repeats out - so what it
|
||||
// says it kept is what the box should show.
|
||||
.then((answer) => {
|
||||
const text = (answer.global || []).join(', ')
|
||||
setWords(text)
|
||||
setSaved(text)
|
||||
})
|
||||
.catch((e: Error) => store.toast('error', e.message))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="setting-row">
|
||||
<div className="setting-text">
|
||||
<div>Words</div>
|
||||
<div className="small muted">
|
||||
Separated by commas. Whole words only, and case does not matter. They apply to messages
|
||||
that arrive after you add them.
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
className="text-field setting-input"
|
||||
value={words}
|
||||
placeholder="a project, a surname, a name you also answer to"
|
||||
onChange={(e) => setWords(e.target.value)}
|
||||
onBlur={commit}
|
||||
onKeyDown={(e) => e.key === 'Enter' && commit()}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Structured by service, so adding a protocol later means adding a rail entry
|
||||
* and its own panel rather than redesigning this file - a left-hand list of
|
||||
@@ -252,6 +314,13 @@ function GeneralSettings(): JSX.Element {
|
||||
/>
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection
|
||||
title="Highlight keywords"
|
||||
description="Words that light a message up and notify you, the same way your own name does. These apply on every account; an account can add its own in the Accounts pane, for words that only mean you on one network."
|
||||
>
|
||||
<GlobalHighlightKeywords />
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection title="Media">
|
||||
<ToggleSetting
|
||||
settingKey="media.autoplay"
|
||||
|
||||
@@ -34,6 +34,8 @@ export interface Account {
|
||||
* member list is you, and therefore whether you hold op.
|
||||
*/
|
||||
currentNick: string
|
||||
/** Words that highlight a message on this account, besides its own name. */
|
||||
highlightKeywords?: string[]
|
||||
/**
|
||||
* Whether the connection is encrypted. Only IRC is ever false - every other
|
||||
* service here is HTTPS or WSS by construction.
|
||||
|
||||
Reference in New Issue
Block a user