mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-18 18:44:48 +01:00
[TGchat] Annihilation Dropdowns & Tweaks (#24502)
* New TGchat settings section * New Chat Settings Tab & Reorder Tabs * Annihilate dropdowns * Normal Divider * Max Total Messages 10000 -> 2000 * Remove removed things * Rebuild
This commit is contained in:
@@ -13,7 +13,13 @@ import {
|
||||
Section,
|
||||
Stack,
|
||||
} from 'tgui/components';
|
||||
import { removeChatPage, toggleAcceptedType, updateChatPage } from './actions';
|
||||
import {
|
||||
moveChatPageLeft,
|
||||
moveChatPageRight,
|
||||
removeChatPage,
|
||||
toggleAcceptedType,
|
||||
updateChatPage,
|
||||
} from './actions';
|
||||
import { MESSAGE_TYPES } from './constants';
|
||||
import { selectCurrentChatPage } from './selectors';
|
||||
|
||||
@@ -23,7 +29,22 @@ export const ChatPageSettings = (props, context) => {
|
||||
return (
|
||||
<Section fill>
|
||||
<Stack align="center">
|
||||
<Stack.Item grow>
|
||||
{!page.isMain && (
|
||||
<Stack.Item>
|
||||
<Button
|
||||
tooltip={'Reorder tab to the left'}
|
||||
icon={'angle-left'}
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
moveChatPageLeft({
|
||||
pageId: page.id,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
)}
|
||||
<Stack.Item grow ml={0.5}>
|
||||
<Input
|
||||
width="100%"
|
||||
value={page.name}
|
||||
@@ -37,6 +58,21 @@ export const ChatPageSettings = (props, context) => {
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
{!page.isMain && (
|
||||
<Stack.Item ml={0.5}>
|
||||
<Button
|
||||
tooltip={'Reorder tab to the right'}
|
||||
icon={'angle-right'}
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
moveChatPageRight({
|
||||
pageId: page.id,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
)}
|
||||
<Stack.Item>
|
||||
<Button.Checkbox
|
||||
content="Mute"
|
||||
@@ -58,6 +94,7 @@ export const ChatPageSettings = (props, context) => {
|
||||
content="Remove"
|
||||
icon="times"
|
||||
color="red"
|
||||
disabled={page.isMain}
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
removeChatPage({
|
||||
|
||||
@@ -20,3 +20,5 @@ export const toggleAcceptedType = createAction('chat/toggleAcceptedType');
|
||||
export const removeChatPage = createAction('chat/removePage');
|
||||
export const changeScrollTracking = createAction('chat/changeScrollTracking');
|
||||
export const saveChatToDisk = createAction('chat/saveToDisk');
|
||||
export const moveChatPageLeft = createAction('chat/movePageLeft');
|
||||
export const moveChatPageRight = createAction('chat/movePageRight');
|
||||
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
changeScrollTracking,
|
||||
clearChat,
|
||||
loadChat,
|
||||
moveChatPageLeft,
|
||||
moveChatPageRight,
|
||||
rebuildChat,
|
||||
toggleAcceptedType,
|
||||
updateMessageCount,
|
||||
@@ -152,7 +154,9 @@ export const chatMiddleware = (store) => {
|
||||
type === changeChatPage.type ||
|
||||
type === addChatPage.type ||
|
||||
type === removeChatPage.type ||
|
||||
type === toggleAcceptedType.type
|
||||
type === toggleAcceptedType.type ||
|
||||
type === moveChatPageLeft.type ||
|
||||
type === moveChatPageRight.type
|
||||
) {
|
||||
next(action);
|
||||
const page = selectCurrentChatPage(store.getState());
|
||||
|
||||
@@ -18,8 +18,9 @@ export const createPage = (obj) => {
|
||||
}
|
||||
|
||||
return {
|
||||
id: createUuid(),
|
||||
name: 'New Tab',
|
||||
id: createUuid(),
|
||||
isMain: false,
|
||||
acceptedTypes: acceptedTypes,
|
||||
unreadCount: 0,
|
||||
hideUnreadCount: false,
|
||||
@@ -35,6 +36,7 @@ export const createMainPage = () => {
|
||||
}
|
||||
return createPage({
|
||||
name: 'Main',
|
||||
isMain: true,
|
||||
acceptedTypes,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
updateChatPage,
|
||||
updateMessageCount,
|
||||
changeScrollTracking,
|
||||
moveChatPageLeft,
|
||||
moveChatPageRight,
|
||||
} from './actions';
|
||||
import { canPageAcceptType, createMainPage } from './model';
|
||||
|
||||
@@ -188,5 +190,52 @@ export const chatReducer = (state = initialState, action) => {
|
||||
}
|
||||
return nextState;
|
||||
}
|
||||
if (type === moveChatPageLeft.type) {
|
||||
const { pageId } = payload;
|
||||
const nextState = {
|
||||
...state,
|
||||
pages: [...state.pages],
|
||||
pageById: {
|
||||
...state.pageById,
|
||||
},
|
||||
};
|
||||
const tmpPage = nextState.pageById[pageId];
|
||||
const fromIndex = nextState.pages.indexOf(tmpPage.id);
|
||||
const toIndex = fromIndex - 1;
|
||||
// don't ever move leftmost page
|
||||
if (fromIndex > 0) {
|
||||
// don't ever move anything to the leftmost page
|
||||
if (toIndex > 0) {
|
||||
const tmp = nextState.pages[fromIndex];
|
||||
nextState.pages[fromIndex] = nextState.pages[toIndex];
|
||||
nextState.pages[toIndex] = tmp;
|
||||
}
|
||||
}
|
||||
return nextState;
|
||||
}
|
||||
|
||||
if (type === moveChatPageRight.type) {
|
||||
const { pageId } = payload;
|
||||
const nextState = {
|
||||
...state,
|
||||
pages: [...state.pages],
|
||||
pageById: {
|
||||
...state.pageById,
|
||||
},
|
||||
};
|
||||
const tmpPage = nextState.pageById[pageId];
|
||||
const fromIndex = nextState.pages.indexOf(tmpPage.id);
|
||||
const toIndex = fromIndex + 1;
|
||||
// don't ever move leftmost page
|
||||
if (fromIndex > 0) {
|
||||
// don't ever move anything out of the array
|
||||
if (toIndex < nextState.pages.length) {
|
||||
const tmp = nextState.pages[fromIndex];
|
||||
nextState.pages[fromIndex] = nextState.pages[toIndex];
|
||||
nextState.pages[toIndex] = tmp;
|
||||
}
|
||||
}
|
||||
return nextState;
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { capitalize } from 'common/string';
|
||||
import { toFixed } from 'common/math';
|
||||
import { useLocalState } from 'tgui/backend';
|
||||
import { useDispatch, useSelector } from 'common/redux';
|
||||
@@ -12,7 +13,6 @@ import {
|
||||
Button,
|
||||
ColorBox,
|
||||
Divider,
|
||||
Dropdown,
|
||||
Input,
|
||||
LabeledList,
|
||||
NumberInput,
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
Stack,
|
||||
Tabs,
|
||||
TextArea,
|
||||
Collapsible,
|
||||
} from 'tgui/components';
|
||||
import { ChatPageSettings } from '../chat';
|
||||
import { clearChat, rebuildChat, saveChatToDisk } from '../chat/actions';
|
||||
@@ -82,118 +83,144 @@ export const SettingsGeneral = (props, context) => {
|
||||
const dispatch = useDispatch(context);
|
||||
const [freeFont, setFreeFont] = useLocalState(context, 'freeFont', false);
|
||||
return (
|
||||
<Section height="150px">
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Theme">
|
||||
<Dropdown
|
||||
selected={theme}
|
||||
options={THEMES}
|
||||
onSelected={(value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
theme: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Font style">
|
||||
<Stack inline align="baseline">
|
||||
<Section fill>
|
||||
<Stack fill vertical>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Theme">
|
||||
{THEMES.map((THEME) => (
|
||||
<Button
|
||||
key={THEME}
|
||||
content={capitalize(THEME)}
|
||||
selected={theme === THEME}
|
||||
color="transparent"
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
theme: THEME,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Font style">
|
||||
<Stack.Item>
|
||||
{(!freeFont && (
|
||||
<Dropdown
|
||||
selected={fontFamily}
|
||||
options={FONTS}
|
||||
onSelected={(value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
fontFamily: value,
|
||||
})
|
||||
)
|
||||
<Collapsible
|
||||
title={fontFamily}
|
||||
width={'100%'}
|
||||
buttons={
|
||||
<Button
|
||||
content="Custom font"
|
||||
icon={freeFont ? 'lock-open' : 'lock'}
|
||||
color={freeFont ? 'good' : 'bad'}
|
||||
onClick={() => {
|
||||
setFreeFont(!freeFont);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
>
|
||||
{FONTS.map((FONT) => (
|
||||
<Button
|
||||
key={FONT}
|
||||
content={FONT}
|
||||
fontFamily={FONT}
|
||||
selected={fontFamily === FONT}
|
||||
color="transparent"
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
fontFamily: FONT,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Collapsible>
|
||||
)) || (
|
||||
<Input
|
||||
value={fontFamily}
|
||||
onChange={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
fontFamily: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Stack>
|
||||
<Input
|
||||
width={'100%'}
|
||||
value={fontFamily}
|
||||
onChange={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
fontFamily: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
ml={0.5}
|
||||
content="Custom font"
|
||||
icon={freeFont ? 'lock-open' : 'lock'}
|
||||
color={freeFont ? 'good' : 'bad'}
|
||||
onClick={() => {
|
||||
setFreeFont(!freeFont);
|
||||
}}
|
||||
/>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
content="Custom font"
|
||||
icon={freeFont ? 'lock-open' : 'lock'}
|
||||
color={freeFont ? 'good' : 'bad'}
|
||||
onClick={() => {
|
||||
setFreeFont(!freeFont);
|
||||
}}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Font size">
|
||||
<NumberInput
|
||||
width="4.2em"
|
||||
step={1}
|
||||
stepPixelSize={10}
|
||||
minValue={8}
|
||||
maxValue={32}
|
||||
value={fontSize}
|
||||
unit="px"
|
||||
format={(value) => toFixed(value)}
|
||||
onChange={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
fontSize: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Line height">
|
||||
<NumberInput
|
||||
width="4.2em"
|
||||
step={0.01}
|
||||
stepPixelSize={2}
|
||||
minValue={0.8}
|
||||
maxValue={5}
|
||||
value={lineHeight}
|
||||
format={(value) => toFixed(value, 2)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
lineHeight: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Divider />
|
||||
<Stack fill>
|
||||
<Stack.Item grow mt={0.15}>
|
||||
<Button
|
||||
content="Save chat log"
|
||||
icon="save"
|
||||
tooltip="Export current tab history into HTML file"
|
||||
onClick={() => dispatch(saveChatToDisk())}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item mt={0.15}>
|
||||
<Button.Confirm
|
||||
icon="trash"
|
||||
confirmContent="Are you sure?"
|
||||
content="Clear chat"
|
||||
tooltip="Erase current tab history"
|
||||
onClick={() => dispatch(clearChat())}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Font size">
|
||||
<NumberInput
|
||||
width="4.2em"
|
||||
step={1}
|
||||
stepPixelSize={10}
|
||||
minValue={8}
|
||||
maxValue={32}
|
||||
value={fontSize}
|
||||
unit="px"
|
||||
format={(value) => toFixed(value)}
|
||||
onChange={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
fontSize: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Line height">
|
||||
<NumberInput
|
||||
width="4.2em"
|
||||
step={0.01}
|
||||
stepPixelSize={2}
|
||||
minValue={0.8}
|
||||
maxValue={5}
|
||||
value={lineHeight}
|
||||
format={(value) => toFixed(value, 2)}
|
||||
onDrag={(e, value) =>
|
||||
dispatch(
|
||||
updateSettings({
|
||||
lineHeight: value,
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
<Divider />
|
||||
<Stack>
|
||||
<Stack.Item grow>
|
||||
<Button
|
||||
content="Save chat log"
|
||||
icon="save"
|
||||
tooltip="Export current tab history into HTML file"
|
||||
onClick={() => dispatch(saveChatToDisk())}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
icon="trash"
|
||||
confirmContent="Are you sure?"
|
||||
content="Clear chat"
|
||||
tooltip="Erase current tab history"
|
||||
onClick={() => dispatch(clearChat())}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Section>
|
||||
);
|
||||
|
||||
@@ -9,7 +9,6 @@ export const SETTINGS_TABS = [
|
||||
id: 'general',
|
||||
name: 'General',
|
||||
},
|
||||
|
||||
{
|
||||
id: 'textHighlight',
|
||||
name: 'Text Highlights',
|
||||
|
||||
@@ -8,6 +8,7 @@ import { BooleanLike, classes, pureComponentHooks } from 'common/react';
|
||||
import { InfernoNode } from 'inferno';
|
||||
import { Box, unit } from './Box';
|
||||
import { Divider } from './Divider';
|
||||
import { Tooltip } from './Tooltip';
|
||||
|
||||
type LabeledListProps = {
|
||||
children: InfernoNode;
|
||||
@@ -27,6 +28,7 @@ type LabeledListItemProps = {
|
||||
color?: string | BooleanLike;
|
||||
textAlign?: string | BooleanLike;
|
||||
buttons?: InfernoNode;
|
||||
tooltip?: string | BooleanLike;
|
||||
/** @deprecated */
|
||||
content?: any;
|
||||
children?: InfernoNode;
|
||||
@@ -40,10 +42,11 @@ const LabeledListItem = (props: LabeledListItemProps) => {
|
||||
color,
|
||||
textAlign,
|
||||
buttons,
|
||||
tooltip,
|
||||
content,
|
||||
children,
|
||||
} = props;
|
||||
return (
|
||||
let listItem = (
|
||||
<tr className={classes(['LabeledList__row', className])}>
|
||||
<Box
|
||||
as="td"
|
||||
@@ -67,6 +70,12 @@ const LabeledListItem = (props: LabeledListItemProps) => {
|
||||
)}
|
||||
</tr>
|
||||
);
|
||||
|
||||
if (tooltip) {
|
||||
listItem = <Tooltip content={tooltip}>{listItem}</Tooltip>;
|
||||
}
|
||||
|
||||
return listItem;
|
||||
};
|
||||
|
||||
LabeledListItem.defaultHooks = pureComponentHooks;
|
||||
|
||||
+120
-120
File diff suppressed because one or more lines are too long
+67
-67
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user