Frontend: Keep Input Focus on Change
This commit is contained in:
parent
090d85f215
commit
372c4410e6
@ -1,19 +1,20 @@
|
||||
FROM node:16-alpine3.14
|
||||
RUN addgroup app && adduser -SG app app
|
||||
RUN mkdir /app && chown app:app /app `
|
||||
RUN mkdir /app && chown app:app /app
|
||||
USER app
|
||||
|
||||
WORKDIR /app/backend
|
||||
COPY --chown=app:app backend/package*.json ./
|
||||
RUN npm i
|
||||
|
||||
WORKDIR /app/frontend
|
||||
COPY --chown=app:app frontend/package*.json ./
|
||||
RUN npm i
|
||||
# WORKDIR /app/frontend
|
||||
# COPY --chown=app:app ./frontend/package*.json ./
|
||||
# RUN ln -s ./frontend/src/types /app
|
||||
# RUN npm i
|
||||
|
||||
WORKDIR /app
|
||||
COPY --chown=app:app . .
|
||||
|
||||
# WORKDIR /app/backend
|
||||
# COPY --chown=app:app ./backend/package*.json ./
|
||||
# RUN npm i
|
||||
|
||||
EXPOSE 3000
|
||||
EXPOSE 4200
|
||||
CMD ./bin/start-dev.sh
|
@ -42,7 +42,7 @@ export default class Themes extends DBWrapper<string, ThemeDocument> {
|
||||
public parse(styles: string) {
|
||||
try { parseCSS(styles) }
|
||||
catch (error: any) {
|
||||
throw new TypeError(`CSS Error: ${styles}`)
|
||||
throw new TypeError(`CSS Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,9 +14,9 @@ services:
|
||||
ports: [3000:3000, 4200:4200]
|
||||
env_file: [./backend/.env, ./frontend/env/.env.dev]
|
||||
volumes:
|
||||
- ./backend/src:/app/src
|
||||
- ./backend/assets:/app/assets
|
||||
- ./backend/logs:/app/logs
|
||||
- ./frontend/src:/app/src
|
||||
- ./backend/src:/app/backend/src
|
||||
- ./backend/assets:/app/backend/assets
|
||||
- ./backend/logs:/app/backend/logs
|
||||
- ./frontend/src:/app/frontend/src
|
||||
volumes:
|
||||
accord:
|
@ -10,7 +10,7 @@ const FileInput: React.FunctionComponent<FileInputProps> = (props) => {
|
||||
<Input
|
||||
accept="image/*"
|
||||
className="pt-5"
|
||||
label="Avatar Image"
|
||||
label={props.label ?? 'Image'}
|
||||
register={(): any => {}}
|
||||
type="file"
|
||||
{...props}
|
||||
|
@ -8,3 +8,7 @@ input:hover {
|
||||
input:focus {
|
||||
border: 1px solid var(--link);
|
||||
}
|
||||
input:disabled {
|
||||
color: var(--muted);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ export interface InputProps {
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
tooltip?: string;
|
||||
setFocusedInputId?: (val: any) => any;
|
||||
}
|
||||
|
||||
const Input: React.FunctionComponent<InputProps & React.AllHTMLAttributes<HTMLInputElement>> = (props) => {
|
||||
@ -50,6 +51,7 @@ const Input: React.FunctionComponent<InputProps & React.AllHTMLAttributes<HTMLIn
|
||||
type={type ?? 'text'}
|
||||
autoFocus={autoFocus}
|
||||
disabled={disabled}
|
||||
onFocus={(e) => props.setFocusedInputId?.(e.currentTarget.id)}
|
||||
{...filterProps(props)}
|
||||
{...register?.(name, { ...options })}
|
||||
size={60}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { TextareaAutosize } from '@material-ui/core';
|
||||
import classNames from 'classnames';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
@ -20,12 +19,20 @@ const UserSettingsThemes: React.FunctionComponent = () => {
|
||||
const themes = useSelector((s: Store.AppState) => s.entities.themes);
|
||||
const [themeId, setTab] = useState(selfUser.activeThemeId);
|
||||
const [addMode, enableAddMode] = useState(false);
|
||||
const [focusedInputId, setFocusedInputId] = useState('');
|
||||
|
||||
const theme = getTheme(themeId, themes);
|
||||
useEffect(() => {
|
||||
if (!theme) setTab('default');
|
||||
}, [theme, themeId]);
|
||||
|
||||
const refreshFocus = () => {
|
||||
if (!focusedInputId) return;
|
||||
|
||||
const input: HTMLInputElement | null = document.querySelector(`#${focusedInputId}`);
|
||||
input?.focus();
|
||||
}
|
||||
|
||||
const SideIcons: React.FunctionComponent = () => (
|
||||
<div className="flex items-center flex-col">
|
||||
{themes.map(t => (
|
||||
@ -80,7 +87,7 @@ const UserSettingsThemes: React.FunctionComponent = () => {
|
||||
|
||||
<div className="mb-10">
|
||||
<Input
|
||||
className="float-left w-1/3 mr-3"
|
||||
className="float-left w-1/3 mr-3 disabled"
|
||||
label="Code"
|
||||
name="code"
|
||||
register={register}
|
||||
@ -124,6 +131,7 @@ const UserSettingsThemes: React.FunctionComponent = () => {
|
||||
label="Name"
|
||||
name="name"
|
||||
register={register}
|
||||
setFocusedInputId={setFocusedInputId}
|
||||
options={{ value: theme.name }} />
|
||||
<Input
|
||||
tooltip="The code that is used to share themes."
|
||||
@ -131,12 +139,16 @@ const UserSettingsThemes: React.FunctionComponent = () => {
|
||||
label="Code"
|
||||
name="code"
|
||||
register={register}
|
||||
options={{ value: theme.code }} />
|
||||
options={{ value: theme.code }}
|
||||
setFocusedInputId={setFocusedInputId}
|
||||
disabled />
|
||||
<FileInput
|
||||
className="w-1/3"
|
||||
name="iconURL"
|
||||
label="Icon"
|
||||
options={{ value: theme.iconURL }}
|
||||
tooltip="An optional icon for your theme."
|
||||
setFocusedInputId={setFocusedInputId}
|
||||
onChange={(e) => {
|
||||
const file = e.currentTarget?.files?.[0];
|
||||
if (!file) return;
|
||||
@ -148,9 +160,11 @@ const UserSettingsThemes: React.FunctionComponent = () => {
|
||||
<textarea
|
||||
className="p-2 rounded bg-bg-secondary outline-none border-bg-tertiary hover:border w-1/2 mt-2"
|
||||
defaultValue={theme.styles}
|
||||
onFocus={(e) => setFocusedInputId?.(e.currentTarget.id)}
|
||||
{...register('styles', { value: theme.styles })} />
|
||||
|
||||
<SaveChanges
|
||||
onOpen={refreshFocus}
|
||||
setValue={setValue}
|
||||
onSave={onSave}
|
||||
obj={theme} />
|
||||
|
@ -8,6 +8,7 @@ import NormalButton from './buttons/normal-button';
|
||||
|
||||
export interface SaveChangesProps {
|
||||
onSave: (e) => any;
|
||||
onOpen?: () => any;
|
||||
onReset?: (e) => any;
|
||||
/** @deprecated */
|
||||
setValue?: UseFormSetValue<FieldValues>;
|
||||
@ -28,6 +29,7 @@ const SaveChanges: React.FunctionComponent<SaveChangesProps> = (props) => {
|
||||
key: 'saveChanges',
|
||||
persist: true,
|
||||
});
|
||||
props.onOpen?.();
|
||||
}, [isOpen]);
|
||||
|
||||
const onClickSave = (e) => {
|
||||
|
4
frontend/types/global.d.ts
vendored
Normal file
4
frontend/types/global.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
declare global {
|
||||
const events: EventEmitter;
|
||||
}
|
||||
export {};
|
@ -5,6 +5,7 @@
|
||||
"dc:down": "docker-compose -f docker-compose.dev.yml down",
|
||||
"dc:logs": "docker-compose -f docker-compose.dev.yml logs -t",
|
||||
"dc:ps": "docker-compose -f docker-compose.dev.yml ps",
|
||||
"dc:inspect": "docker-compose -f docker-compose.dev.yml ps",
|
||||
"dc:build:prod": "docker-compose -f docker-compose.prod.yml build",
|
||||
"dc:up:prod": "docker-compose -f docker-compose.prod.yml up -d --build",
|
||||
"dc:down:prod": "docker-compose -f docker-compose.prod.yml down",
|
||||
|
Loading…
x
Reference in New Issue
Block a user