forked from Mirrors/gomuks
web/settings: add custom css editor
This commit is contained in:
parent
63a1aa6cb7
commit
2487c8c88f
2 changed files with 105 additions and 3 deletions
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue