diff --git a/components/contentMenu.tsx b/components/contentMenu.tsx
index 37b02c8..6bc52d5 100644
--- a/components/contentMenu.tsx
+++ b/components/contentMenu.tsx
@@ -3,18 +3,23 @@ interface ContentItem {
color?: string;
}
-interface TextContentItem extends ContentItem {
+interface TextCI extends ContentItem {
type: 'text';
text: string;
onClick: React.MouseEventHandler;
}
-interface SeparatorContentItem extends ContentItem {
+interface SeparatorCI extends ContentItem {
type: 'separator';
height: number;
}
-type Content = TextContentItem | SeparatorContentItem;
+interface TitleCI extends ContentItem {
+ type: 'title';
+ text: string;
+}
+
+type Content = TextCI | SeparatorCI | TitleCI;
export interface ContentMenuSet {
x: number;
@@ -27,11 +32,12 @@ export default function ContentMenu({ set }: { set: ContentMenuSet }) {
let array = set.content.map((v, i) => {
const { color = '#000' } = v;
if (v.type === 'text') return (
-
+
);
- if (v.type === 'separator') return
;
+ if (v.type === 'separator') return (
);
+ if (v.type === 'title') return (
{v.text}
);
});
return (<>
{set.display && ()}
diff --git a/components/i18n/config/chat.ts b/components/i18n/config/chat.ts
index 3a9c98b..ffd7445 100644
--- a/components/i18n/config/chat.ts
+++ b/components/i18n/config/chat.ts
@@ -103,5 +103,21 @@ const chat = {
'zh-CN': '编辑',
'zh-TW': '編輯',
},
+ idConfirmTitle: {
+ 'zh-CN': '确定删除',
+ 'zh-TW': '確定刪除',
+ },
+ idConfirmInfo: {
+ 'zh-CN': '确定删除与$0的聊天吗',
+ 'zh-TW': '確定刪除於$0的聊天嗎',
+ },
+ confirm: {
+ 'zh-CN': '确定',
+ 'zh-TW': '確定',
+ },
+ cancel: {
+ 'zh-CN': '取消',
+ 'zh-TW': '取消',
+ },
}
export default chat;
\ No newline at end of file
diff --git a/components/i18n/index.ts b/components/i18n/index.ts
index 0fda5f4..8ad5386 100644
--- a/components/i18n/index.ts
+++ b/components/i18n/index.ts
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
-import { useSetting } from "../setting";
+import { getSettingFun } from "../setting";
export type Locales = 'zh-CN' | 'zh-TW';
@@ -13,7 +13,7 @@ export function fillBlank(i18n: string, ...fills: (string | undefined)[]): strin
export function useLocale
(i18n: T) {
const [lo, setLo] = useState('');
- const { getSetting } = useSetting();
+ const { getSetting } = getSettingFun();
useEffect(() => setLo(getSetting().locale || window.navigator.language), []);
function locale(key: K, loc?: string) {
return (i18n as Record>)[key][loc || lo];
diff --git a/components/main.tsx b/components/main.tsx
index b04922a..a138e97 100644
--- a/components/main.tsx
+++ b/components/main.tsx
@@ -1,6 +1,6 @@
//Components
import Link from 'next/link';
-import { SettingForm, useSetting } from '@/components/setting';
+import { SettingForm, getSettingFun } from '@/components/setting';
//Styles
import styles from '@/styles/MainNode.module.scss';
@@ -9,9 +9,9 @@ import styles from '@/styles/MainNode.module.scss';
import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import Window, { AllWindow, AllWindows, getWindowFun } from './window';
-import { Locales, i18nContents, useLocale } from './i18n';
+import { Locales, useLocale } from './i18n';
import main from './i18n/config/main';
-import { SettingState, SettingArg } from '@/components/setting';
+import { Settings, SettingArg } from '@/components/setting';
function MomoTalkIcon() {
return (
@@ -37,7 +37,7 @@ function MTBarLink({ type }: { type: string }) {
);
}
-function MTStart({ animation }: { animation: SettingState['animation'] }) {
+function MTStart() {
const [ani, setAni] = useState<'true' | 'false'>('false');
useEffect(() => {
const { animation } = window.sessionStorage;
@@ -48,6 +48,12 @@ function MTStart({ animation }: { animation: SettingState['animation'] }) {
}
}, []);
+ const [animation, setAnimation] = useState();
+ const { getSetting } = getSettingFun();
+ useEffect(() => {
+ setAnimation(getSetting().animation);
+ }, []);
+
const userAni = (() => {
if (animation === 'none' || animation === undefined) return 'false';
else if (animation === 'first') return ani;
@@ -69,18 +75,13 @@ export default function MainNode({ children, onBodyClick }: {
}) {
const { lo, locale, localeType } = useLocale(main);
- const { setting, setSetting } = useSetting({
- locale: lo,
- animation: 'first',
- fileName: 'untitled',
- });
+ const { setSetting, windowOnload } = getSettingFun();
+ useEffect(windowOnload, []);
- const {
- allWindow,
- addNewWindow,
- openWindow,
- closeWindow,
- } = getWindowFun(useState({ all: [], component: {} }));
+ const { allWindow, addNewWindow, openWindow, closeWindow } = getWindowFun(useState({
+ all: [],
+ component: {},
+ }));
const Setting = new Window('Setting');
@@ -116,7 +117,7 @@ export default function MainNode({ children, onBodyClick }: {
}}
done={locale('done')}
onSubmit={data => {
- setSetting(data as SettingState);
+ setSetting(data as Settings);
close();
}}
/>
@@ -130,7 +131,7 @@ export default function MainNode({ children, onBodyClick }: {
return (
-
+
diff --git a/components/setting.tsx b/components/setting.tsx
index 7d216a0..76e7cb5 100644
--- a/components/setting.tsx
+++ b/components/setting.tsx
@@ -77,32 +77,28 @@ export function SettingForm
({ option, done, onSubmit }: Settin
)
}
-export interface SettingState {
+export interface Settings {
locale?: string;
animation?: 'none' | 'first' | 'every';
fileName?: string;
}
export interface SettingArg {
- setting: SettingState;
- setSetting: SetStateFun;
+ setting: Settings;
+ setSetting: SetStateFun;
}
-export function useSetting(state?: SettingState) {
- const [setting, setSetting] = getClassState(
- useState(state || {}),
- newSet => {
- window.localStorage.set = JSON.stringify(newSet)
- }
- );
- useEffect(() => {
- let setting: string = window.localStorage.set;
- if (setting !== undefined) {
- setSetting(JSON.parse(setting));
- }
- }, []);
- function getSetting(): SettingState {
- return JSON.parse(window.localStorage.set);
+export function getSettingFun(defaultSet?: Settings) {
+ function getSetting(): Settings {
+ return JSON.parse(window.localStorage.set as string);
}
- return { setting, setSetting, getSetting };
+ function setSetting(newSet: Partial, first?: boolean): void {
+ const preSet = first ? {} : getSetting();
+ //console.log({ preSet, newSet, localStorage: JSON.parse(localStorage.set) });
+ window.localStorage.set = JSON.stringify({ ...preSet, ...newSet });
+ }
+ function windowOnload() {
+ if (window.localStorage.set === undefined && defaultSet !== undefined) setSetting(defaultSet, true);
+ }
+ return { getSetting, setSetting, windowOnload };
}
\ No newline at end of file
diff --git a/components/students/index.tsx b/components/students/index.tsx
index a9b7fe1..6f412d8 100644
--- a/components/students/index.tsx
+++ b/components/students/index.tsx
@@ -3,16 +3,25 @@ import { getStudentInfo } from './studentsMethods';
import ImgCol from '../imgCol';
interface StudentProps {
- id: number,
- allInfo: studentsJson,
- onClick: React.MouseEventHandler,
- select: boolean,
+ id: number;
+ allInfo: studentsJson;
+ onClick: React.MouseEventHandler;
+ select: boolean;
+ onContentMenu?: React.MouseEventHandler;
}
-export default function Student({ id, allInfo, onClick, select }: StudentProps) {
+export default function Student({ id, allInfo, onClick, select, onContentMenu }: StudentProps) {
const info = getStudentInfo(allInfo, id);
return (
-
+
{
+ e.preventDefault();
+ onContentMenu?.(e);
+ }}
+ className={select ? 'select' : ''}
+ title={`id:${id}`}
+ >
({
student: 0,
studentsList: [10000, 10045],
@@ -327,6 +331,9 @@ export default function Chat() {
const sendMessageInputRef = useRef('');
const SendMessage = new Window('SendMessage');
+ //Confirm
+ const IdConfirm = new Window('IdConfirm');
+
useEffect(() => {
addNewWindow(IdPrompt, (zIndex, id, display, { studentsList, type }, all) => (
));
+ addNewWindow(IdConfirm, (zIndex, id, display, { student, textInfo, studentsList }, all) => (
+ closeWindow(all, id)}
+ element={close => (<>
+ {fillBlank(locale('idConfirmInfo'), textInfo)}
+
+
+
+
+ >)}
+ zIndex={zIndex}
+ display={display}
+ />
+ ));
}, [lo]);
useEffect(() => {
@@ -463,18 +498,14 @@ export default function Chat() {
{locale('student')}({listState.studentsList?.length})
-
{
- openWindow(allWindow.all, IdPrompt, {
- studentsList: listState.studentsList,
- type: '+'
- });
- }}>+
-
{
- openWindow(allWindow.all, IdPrompt, {
- studentsList: listState.studentsList,
- type: '-'
- });
- }}>-
+ {(['+', '-'] as ('+' | '-')[]).map(v => (
+
{
+ openWindow(allWindow.all, IdPrompt, {
+ studentsList: listState.studentsList,
+ type: v,
+ });
+ }}>{v}
+ ))}
@@ -487,17 +518,37 @@ export default function Chat() {
v + 1}
- components={v => {
+ func={i => i + 1}
+ components={i => {
if (!listState.studentsJson || !listState.studentsList) return;
- const id = listState.studentsList[v];
+ const id = listState.studentsList[i];
return (
setListState({ student: id })}
select={listState.student === id}
+ onContentMenu={e => {
+ const info = getStudentInfo(listState.studentsJson?.data as studentsJson, id);
+ setContentMenu({
+ x: e.clientX,
+ y: e.clientY,
+ content: [
+ { type: 'title', text: `${info.schale?.Name} id: ${id}` },
+ { type: 'separator', color: '#ccc', height: 1 },
+ {
+ type: 'text', text: locale('delete'), onClick() {
+ openWindow(allWindow.all, IdConfirm, {
+ student: id,
+ textInfo: info.schale?.Name as string,
+ studentsList: listState.studentsList,
+ });
+ }
+ },
+ ],
+ display: true,
+ });
+ }}
/>
);
}}
diff --git a/styles/globals.scss b/styles/globals.scss
index 6b647a5..ca02585 100644
--- a/styles/globals.scss
+++ b/styles/globals.scss
@@ -187,6 +187,11 @@ div.window {
border-radius: 5px;
margin: 5px;
height: 25px;
+
+ &.cancel {
+ background-color: #bbb;
+ color: #fff;
+ }
}
p {
@@ -212,13 +217,14 @@ div.window {
div#contentMenu {
backdrop-filter: blur(30px);
position: absolute;
- width: 60px;
+ width: max-content;
+ min-width: 60px;
padding: 5px;
border-radius: 5px;
box-shadow: rgb(0 0 0 / 30%) 0 0 20px;
z-index: 10000;
- > div {
+ > div.text {
padding: 1px;
border-radius: 5px;
transition-duration: 0.2s;
@@ -233,4 +239,14 @@ div#contentMenu {
font-size: 14px;
}
}
+
+ > div.separator {
+ margin: 5px;
+ }
+
+ > p {
+ user-select: none;
+ margin: 0 5px;
+ font-size: 14px;
+ }
}