1
0
Fork 0
forked from Mirrors/gomuks

web/settings: add custom css editor

This commit is contained in:
Tulir Asokan 2024-11-17 14:46:57 +02:00
parent 63a1aa6cb7
commit 2487c8c88f
2 changed files with 105 additions and 3 deletions

View file

@ -3,7 +3,7 @@ div.settings-view {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
> h2 { h2, h3 {
margin: 0; margin: 0;
} }
@ -14,4 +14,56 @@ div.settings-view {
display: flex; display: flex;
} }
} }
> div.custom-css-input {
display: flex;
flex-direction: column;
gap: .5rem;
margin-right: 1rem;
> div.header {
display: flex;
gap: .5rem;
}
> textarea {
width: 100%;
box-sizing: border-box;
resize: vertical;
border: 1px solid var(--border-color);
outline: none;
height: 10rem;
min-height: 3rem;
font-family: var(--monospace-font-stack);
}
> div.buttons {
display: flex;
justify-content: right;
gap: .5rem;
> button {
padding: .5rem 1rem;
&.save {
background-color: var(--primary-color);
color: var(--inverted-text-color);
font-weight: bold;
&:hover, &:focus {
background-color: var(--primary-color-dark);
}
}
&.delete {
font-weight: bold;
&:hover, &:focus {
background-color: var(--error-color);
color: var(--inverted-text-color);
}
}
}
}
}
} }

View file

@ -13,9 +13,10 @@
// //
// You should have received a copy of the GNU Affero General Public License // You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
import { use, useCallback } from "react" import { use, useCallback, useState } from "react"
import { RoomStateStore, usePreferences } from "@/api/statestore" import { RoomStateStore, usePreferences } from "@/api/statestore"
import { Preference, PreferenceContext, PreferenceValueType, Preferences, preferences } from "@/api/types/preferences" import { Preference, PreferenceContext, PreferenceValueType, Preferences, preferences } from "@/api/types/preferences"
import useEvent from "@/util/useEvent.ts"
import ClientContext from "../ClientContext.ts" import ClientContext from "../ClientContext.ts"
import JSONView from "../util/JSONView.tsx" import JSONView from "../util/JSONView.tsx"
import Toggle from "../util/Toggle.tsx" import Toggle from "../util/Toggle.tsx"
@ -85,12 +86,15 @@ interface PreferenceRowProps {
const PreferenceRow = ({ const PreferenceRow = ({
name, pref, setPref, globalServer, globalLocal, roomServer, roomLocal, name, pref, setPref, globalServer, globalLocal, roomServer, roomLocal,
}: PreferenceRowProps) => { }: PreferenceRowProps) => {
const prefType = typeof pref.defaultValue
if (prefType !== "boolean" && !pref.allowedValues) {
return null
}
const makeContentCell = ( const makeContentCell = (
context: PreferenceContext, context: PreferenceContext,
val: PreferenceValueType | undefined, val: PreferenceValueType | undefined,
inheritedVal: PreferenceValueType, inheritedVal: PreferenceValueType,
) => { ) => {
const prefType = typeof pref.defaultValue
if (prefType === "boolean") { if (prefType === "boolean") {
return <BooleanPreferenceCell return <BooleanPreferenceCell
name={name} name={name}
@ -127,6 +131,51 @@ interface SettingsViewProps {
room: RoomStateStore room: RoomStateStore
} }
const CustomCSSInput = ({ setPref, room }: { setPref: SetPrefFunc, room: RoomStateStore }) => {
const client = use(ClientContext)!
const [context, setContext] = useState(PreferenceContext.Account)
const [text, setText] = useState("")
const onChangeContext = useCallback((evt: React.ChangeEvent<HTMLSelectElement>) => {
const newContext = evt.target.value as PreferenceContext
setContext(newContext)
if (newContext === PreferenceContext.Account) {
setText(client.store.serverPreferenceCache.custom_css ?? "")
} else if (newContext === PreferenceContext.Device) {
setText(client.store.localPreferenceCache.custom_css ?? "")
} else if (newContext === PreferenceContext.RoomAccount) {
setText(room.serverPreferenceCache.custom_css ?? "")
} else if (newContext === PreferenceContext.RoomDevice) {
setText(room.localPreferenceCache.custom_css ?? "")
}
}, [client, room])
const onChangeText = useCallback((evt: React.ChangeEvent<HTMLTextAreaElement>) => {
setText(evt.target.value)
}, [])
const onSave = useEvent(() => {
setPref(context, "custom_css", text)
})
const onDelete = useEvent(() => {
setPref(context, "custom_css", undefined)
setText("")
})
return <div className="custom-css-input">
<div className="header">
<h3>Custom CSS</h3>
<select value={context} onChange={onChangeContext}>
<option value={PreferenceContext.Account}>Account</option>
<option value={PreferenceContext.Device}>Device</option>
<option value={PreferenceContext.RoomAccount}>Room (account)</option>
<option value={PreferenceContext.RoomDevice}>Room (device)</option>
</select>
</div>
<textarea value={text} onChange={onChangeText}/>
<div className="buttons">
<button className="delete" onClick={onDelete}>Delete</button>
<button className="save" onClick={onSave}>Save</button>
</div>
</div>
}
const SettingsView = ({ room }: SettingsViewProps) => { const SettingsView = ({ room }: SettingsViewProps) => {
const client = use(ClientContext)! const client = use(ClientContext)!
const setPref = useCallback((context: PreferenceContext, key: keyof Preferences, value: PreferenceValueType | undefined)=> { const setPref = useCallback((context: PreferenceContext, key: keyof Preferences, value: PreferenceValueType | undefined)=> {
@ -186,6 +235,7 @@ const SettingsView = ({ room }: SettingsViewProps) => {
/>)} />)}
</tbody> </tbody>
</table> </table>
<CustomCSSInput setPref={setPref} room={room} />
<JSONView data={room.preferences} /> <JSONView data={room.preferences} />
</> </>
} }