feat: improved layout

This commit is contained in:
Jixun Wu 2023-06-09 23:11:30 +01:00
parent fc847eaf58
commit 1f87a655ac
9 changed files with 1222 additions and 707 deletions

View File

@ -17,7 +17,7 @@
},
"dependencies": {
"@chakra-ui/icons": "^2.0.19",
"@chakra-ui/react": "^2.6.1",
"@chakra-ui/react": "^2.7.0",
"@emotion/react": "^11.11.0",
"@emotion/styled": "^11.11.0",
"@jixun/libparakeet": "0.1.1",

File diff suppressed because it is too large Load Diff

View File

@ -32,11 +32,11 @@ export function AppRoot() {
</Tab>
</TabList>
<TabPanels overflow="auto" minW={0}>
<TabPanels overflow="auto" minW={0} flexDir="column" flex={1} display="flex">
<TabPanel>
<MainTab />
</TabPanel>
<TabPanel>
<TabPanel flex={1} display="flex">
<SettingsTab />
</TabPanel>
</TabPanels>

View File

@ -0,0 +1,20 @@
import { Tab, TabList, TabPanel, TabPanels, Tabs, Text } from '@chakra-ui/react';
import { PanelQMC } from './panels/PanelQMC';
export function Settings() {
return (
<Tabs orientation="vertical" align="start" variant="line-i" flex={1}>
<TabList minW={0} width="8em" textAlign="right" justifyContent="center">
<Tab>QQ </Tab>
<Tab></Tab>
</TabList>
<TabPanels>
<PanelQMC />
<TabPanel>
<Text></Text>
</TabPanel>
</TabPanels>
</Tabs>
);
}

View File

@ -0,0 +1,153 @@
import {
Box,
Button,
ButtonGroup,
Flex,
HStack,
Heading,
Icon,
IconButton,
Input,
InputGroup,
InputLeftElement,
InputRightElement,
List,
ListItem,
Menu,
MenuButton,
MenuDivider,
MenuItem,
MenuList,
Spacer,
TabPanel,
Text,
VStack,
} from '@chakra-ui/react';
import { useSelector } from 'react-redux';
import { selectQM2CSettings } from '../settingsSlice';
import React, { useEffect, useState } from 'react';
import { nanoid } from 'nanoid';
import { produce } from 'immer';
import { MdAdd, MdDeleteForever, MdExpandMore, MdFileUpload, MdVpnKey } from 'react-icons/md';
interface InternalQMCKeys {
id: string;
name: string;
key: string;
}
export function PanelQMC() {
const qmcSettings = useSelector(selectQM2CSettings);
const [qmcKeys, setQMCKeys] = useState<InternalQMCKeys[]>([]);
const resetQmcKeys = () => {
const result: InternalQMCKeys[] = [];
for (const [name, key] of Object.entries(qmcSettings.keys)) {
result.push({ id: name, name, key });
}
setQMCKeys(result);
};
const addRow = () => {
setQMCKeys((prev) => [...prev, { id: nanoid(), key: '', name: '' }]);
};
const updateKey = (prop: 'name' | 'key', id: string, e: React.ChangeEvent<HTMLInputElement>) => {
setQMCKeys((prev) =>
produce(prev, (draft) => {
const item = draft.find((item) => item.id === id);
if (item) {
item[prop] = e.target.value;
}
})
);
};
const applyChanges = () => {
//
};
const clearAll = () => setQMCKeys([]);
useEffect(resetQmcKeys, [qmcSettings.keys]);
return (
<Flex as={TabPanel} flexDir="column" h="100%">
<Box flex={1} minH={0} overflow="auto">
<Heading as="h2" size="lg">
</Heading>
<Box p="4" pr="0" borderStart="2px solid" borderColor="gray.200">
<List spacing={3}>
{qmcKeys.map(({ id, key, name }, i) => (
<ListItem key={id}>
<HStack>
<Text w="2em" textAlign="center">
{i + 1}
</Text>
<VStack flex={1}>
<Input
variant="flushed"
placeholder="文件名"
value={name}
onChange={(e) => updateKey('name', id, e)}
/>
<InputGroup size="xs">
<InputLeftElement pr="2">
<Icon as={MdVpnKey} />
</InputLeftElement>
<Input
variant="flushed"
placeholder="密钥"
value={key}
onChange={(e) => updateKey('key', id, e)}
/>
<InputRightElement>
<Text pl="2" color={key.length ? 'green.500' : 'red.500'}>
<code>{key.length || '?'}</code>
</Text>
</InputRightElement>
</InputGroup>
</VStack>
</HStack>
</ListItem>
))}
</List>
{qmcKeys.length === 0 && <Text></Text>}
</Box>
</Box>
<VStack mt="4" alignItems="flex-start">
<Text>使</Text>
<Flex flexDir="row" gap="2" w="full">
<Box>
<ButtonGroup isAttached variant="outline">
<Button onClick={addRow}>
<Icon as={MdAdd} />
</Button>
<Menu>
<MenuButton as={IconButton} icon={<MdExpandMore />}>
<Icon as={MdExpandMore} />1
</MenuButton>
<MenuList>
<MenuItem onClick={() => alert('TODO!')} icon={<Icon as={MdFileUpload} h={18} w={18} />}>
(JSON)
</MenuItem>
<MenuDivider />
<MenuItem color="red" onClick={clearAll} icon={<Icon as={MdDeleteForever} h={18} w={18} />}>
</MenuItem>
</MenuList>
</Menu>
</ButtonGroup>
</Box>
<Spacer />
<Box>
<Button onClick={resetQmcKeys} colorScheme="red" variant="ghost">
</Button>
<Button onClick={applyChanges}></Button>
</Box>
</Flex>
</VStack>
</Flex>
);
}

View File

@ -1,5 +1,6 @@
import { createSlice } from '@reduxjs/toolkit';
import type { PayloadAction } from '@reduxjs/toolkit';
import type { RootState } from '~/store';
export interface QMCSettings {
keys: Record<string, string>; // { [fileName]: ekey }
@ -28,4 +29,6 @@ export const settingsSlice = createSlice({
export const { updateSettings, resetConfig } = settingsSlice.actions;
export const selectQM2CSettings = (state: RootState) => state.settings.qmc2;
export default settingsSlice.reducer;

View File

@ -1,10 +1,10 @@
import { Container, Flex } from '@chakra-ui/react';
import { Settings } from '~/features/settings/Settings';
export function SettingsTab() {
return (
<div>
<p>Hallo</p>
<p>Thank you, thank you very much.</p>
<p>Ha-Halo, thank you</p>
<p>Thank you very much!</p>
</div>
<Container as={Flex} maxW="container.lg">
<Settings />
</Container>
);
}

View File

@ -1,4 +1,5 @@
import { extendTheme } from '@chakra-ui/react';
import { tabsTheme } from './themes/Tabs';
export const theme = extendTheme({
fonts: {
@ -18,6 +19,17 @@ export const theme = extendTheme({
colorScheme: 'teal',
},
},
Tabs: tabsTheme,
Heading: {
baseStyle: {
userSelect: 'none',
},
},
Text: {
baseStyle: {
userSelect: 'none',
},
},
},
styles: {
global: {

64
src/themes/Tabs.tsx Normal file
View File

@ -0,0 +1,64 @@
import { tabsAnatomy } from '@chakra-ui/anatomy';
import { createMultiStyleConfigHelpers, cssVar } from '@chakra-ui/react';
const $fg = cssVar('tabs-color');
const $bg = cssVar('tabs-bg');
const { definePartsStyle, defineMultiStyleConfig } = createMultiStyleConfigHelpers(tabsAnatomy.keys);
const variantLineInvert = definePartsStyle((props) => {
const { colorScheme: c, orientation } = props;
const isVertical = orientation === 'vertical';
const borderProp = isVertical ? 'borderEnd' : 'borderTop';
const marginProp = isVertical ? 'marginEnd' : 'marginTop';
return {
tablist: {
[borderProp]: '2px solid',
borderColor: 'inherit',
},
tab: {
[borderProp]: '2px solid',
borderColor: 'transparent',
[marginProp]: '-2px',
justifyContent: 'flex-end',
_selected: {
[$fg.variable]: `colors.${c}.600`,
_dark: {
[$fg.variable]: `colors.${c}.300`,
},
borderColor: 'currentColor',
},
_active: {
[$bg.variable]: 'colors.gray.200',
_dark: {
[$bg.variable]: 'colors.whiteAlpha.300',
},
},
_disabled: {
_active: { bg: 'none' },
},
color: $fg.reference,
bg: $bg.reference,
},
root: {
gap: 8,
},
};
});
export const tabsTheme = defineMultiStyleConfig({
baseStyle: {
tablist: {
userSelect: 'none',
},
tabpanel: {
minHeight: 0,
overflow: 'auto',
maxHeight: '100%',
},
},
variants: {
'line-i': variantLineInvert,
},
});