New user profile UI in User Settings (#12548)
* New user profile UI in User Settings Using new Edit In Place component. * Show avatar upload error * Fix avatar upload error * Wire up errors & feedback for display name setting * Implement avatar upload / remove progress toast * Add 768px breakpoint * Fix room profile display * Update to released compund-web with required components / fixes * Require compound-web 4.4.0 because we do need it * Update snapshots Because of course all the auto-generated IDs of unrelated things have changed. * Fix duplicate import * Fix CSS comment * Update snapshot * Run all the tests so the ids stay the same * Start of a test for ProfileSettings * More tests * Test that a toast appears * Test ToastRack * Update snapshots * Add the usernamee control * Fix playwright tests * New compound version for editinplace fixes * Fix useId to not just generate a constant ID * Use the label in the username component * Fix widths of test boxes * Update screenshots * Put ^ back on compound-web version * Split CSS for room & user profile settings and name the components correspondingly * Fix playwright test * Update room settings screenshot * Use original screenshot instead * Fix styling of unrelated buttons Needed to be added in other places otherwise the specificity changes. Also put the old screenshots back. * Add copyright year * Fix copyright year
This commit is contained in:
parent
c4c1faff97
commit
cfa322cd62
25 changed files with 919 additions and 307 deletions
93
src/contexts/ToastContext.tsx
Normal file
93
src/contexts/ToastContext.tsx
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { ReactNode, createContext, useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||
|
||||
/**
|
||||
* A ToastContext helps components display any kind of toast message and can be provided
|
||||
* by a parent component such that their children can display toasts, eg. a settings dialog
|
||||
* can provide a ToastContext such that controls within it can display toasts at the bottom
|
||||
* of the dialog.
|
||||
*
|
||||
* It is not (at time of writing) used by the *other* toasts that appear in the top right
|
||||
* corner of the app, however the name 'toast' as used in this class refers to the component
|
||||
* of the same name in compound that it is written to manage.
|
||||
*/
|
||||
export const ToastContext = createContext(null as any);
|
||||
ToastContext.displayName = "ToastContext";
|
||||
|
||||
/**
|
||||
* Returns the ToastRack in context in order to display toasts
|
||||
*/
|
||||
export function useToastContext(): ToastRack {
|
||||
return useContext(ToastContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* For components that wish to display toasts, return the currently active toast and
|
||||
* the ToastRack object that should be provided to the context
|
||||
*/
|
||||
export function useActiveToast(): [ReactNode | undefined, ToastRack] {
|
||||
const toastRack = useRef(new ToastRack());
|
||||
|
||||
const [activeToast, setActiveToast] = useState<ReactNode | undefined>(toastRack.current.getActiveToast());
|
||||
|
||||
const updateCallback = useCallback(() => {
|
||||
setActiveToast(toastRack.current.getActiveToast());
|
||||
}, [setActiveToast, toastRack]);
|
||||
|
||||
useEffect(() => {
|
||||
toastRack.current.setCallback(updateCallback);
|
||||
}, [toastRack, updateCallback]);
|
||||
|
||||
return [activeToast, toastRack.current];
|
||||
}
|
||||
|
||||
interface DisplayedToast {
|
||||
id: number;
|
||||
contents: ReactNode;
|
||||
}
|
||||
|
||||
type RemoveCallback = () => void;
|
||||
|
||||
export class ToastRack {
|
||||
private currentToast: DisplayedToast | undefined;
|
||||
private updateCallback?: () => void;
|
||||
private idSeq = 0;
|
||||
|
||||
public setCallback(cb: () => void): void {
|
||||
this.updateCallback = cb;
|
||||
}
|
||||
|
||||
public displayToast(contents: ReactNode): RemoveCallback {
|
||||
const newToastId = ++this.idSeq;
|
||||
|
||||
this.currentToast = { id: newToastId, contents: contents };
|
||||
this.updateCallback?.();
|
||||
const removeFn = (): void => {
|
||||
if (this.currentToast?.id === newToastId) {
|
||||
this.currentToast = undefined;
|
||||
this.updateCallback?.();
|
||||
}
|
||||
};
|
||||
|
||||
return removeFn;
|
||||
}
|
||||
|
||||
public getActiveToast(): ReactNode | undefined {
|
||||
return this.currentToast?.contents;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue