mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
[MIRROR] finish that up (#10340)
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
075b5ce8d1
commit
41b5caff60
@@ -74,6 +74,7 @@ VIRGO3B_TURF_CREATE(/turf/simulated/floor/reinforced)
|
|||||||
color = "#FFBBBB"
|
color = "#FFBBBB"
|
||||||
|
|
||||||
/turf/simulated/sky/virgo3b/Initialize(mapload)
|
/turf/simulated/sky/virgo3b/Initialize(mapload)
|
||||||
|
. = ..()
|
||||||
SSplanets.addTurf(src)
|
SSplanets.addTurf(src)
|
||||||
set_light(2, 2, "#FFBBBB")
|
set_light(2, 2, "#FFBBBB")
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ const logger = createLogger('dreamseeker');
|
|||||||
const instanceByPid = new Map();
|
const instanceByPid = new Map();
|
||||||
|
|
||||||
export class DreamSeeker {
|
export class DreamSeeker {
|
||||||
|
pid: number;
|
||||||
|
addr: string;
|
||||||
|
client: any;
|
||||||
|
static getInstancesByPids: (pids: any) => Promise<any[]>;
|
||||||
constructor(pid, addr) {
|
constructor(pid, addr) {
|
||||||
this.pid = pid;
|
this.pid = pid;
|
||||||
this.addr = addr;
|
this.addr = addr;
|
||||||
@@ -37,6 +41,8 @@ export class DreamSeeker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Entry = { pid: number; addr: string };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number[]} pids
|
* @param {number[]} pids
|
||||||
* @returns {DreamSeeker[]}
|
* @returns {DreamSeeker[]}
|
||||||
@@ -45,8 +51,8 @@ DreamSeeker.getInstancesByPids = async (pids) => {
|
|||||||
if (process.platform !== 'win32') {
|
if (process.platform !== 'win32') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const instances = [];
|
const instances: any[] = [];
|
||||||
const pidsToResolve = [];
|
const pidsToResolve: number[] = [];
|
||||||
for (let pid of pids) {
|
for (let pid of pids) {
|
||||||
const instance = instanceByPid.get(pid);
|
const instance = instanceByPid.get(pid);
|
||||||
if (instance) {
|
if (instance) {
|
||||||
@@ -64,7 +70,7 @@ DreamSeeker.getInstancesByPids = async (pids) => {
|
|||||||
});
|
});
|
||||||
// Line format:
|
// Line format:
|
||||||
// proto addr mask mode pid
|
// proto addr mask mode pid
|
||||||
const entries = [];
|
const entries: Entry[] = [];
|
||||||
const lines = stdout.split('\r\n');
|
const lines = stdout.split('\r\n');
|
||||||
for (let line of lines) {
|
for (let line of lines) {
|
||||||
const words = line.match(/\S+/g);
|
const words = line.match(/\S+/g);
|
||||||
@@ -16,13 +16,15 @@ const { parse: parseStackTrace } = require('stacktrace-parser');
|
|||||||
|
|
||||||
const logger = createLogger('retrace');
|
const logger = createLogger('retrace');
|
||||||
|
|
||||||
|
type SourceMapData = { file: string; consumer: any };
|
||||||
|
|
||||||
const { SourceMapConsumer } = SourceMap;
|
const { SourceMapConsumer } = SourceMap;
|
||||||
const sourceMaps = [];
|
const sourceMaps: SourceMapData[] = [];
|
||||||
|
|
||||||
export const loadSourceMaps = async (bundleDir) => {
|
export const loadSourceMaps = async (bundleDir) => {
|
||||||
// Destroy and garbage collect consumers
|
// Destroy and garbage collect consumers
|
||||||
while (sourceMaps.length !== 0) {
|
while (sourceMaps.length !== 0) {
|
||||||
const { consumer } = sourceMaps.shift();
|
const { consumer } = sourceMaps.shift() as SourceMapData;
|
||||||
consumer.destroy();
|
consumer.destroy();
|
||||||
}
|
}
|
||||||
// Load new sourcemaps
|
// Load new sourcemaps
|
||||||
@@ -22,6 +22,11 @@ export { loadSourceMaps };
|
|||||||
export const setupLink = () => new LinkServer();
|
export const setupLink = () => new LinkServer();
|
||||||
|
|
||||||
class LinkServer {
|
class LinkServer {
|
||||||
|
wss: any;
|
||||||
|
httpServer: http.Server<
|
||||||
|
typeof http.IncomingMessage,
|
||||||
|
typeof http.ServerResponse
|
||||||
|
>;
|
||||||
constructor() {
|
constructor() {
|
||||||
logger.log('setting up');
|
logger.log('setting up');
|
||||||
this.wss = null;
|
this.wss = null;
|
||||||
@@ -29,7 +29,7 @@ const SEARCH_LOCATIONS = [
|
|||||||
`/mnt/c/Users/*/*/BYOND/cache`,
|
`/mnt/c/Users/*/*/BYOND/cache`,
|
||||||
];
|
];
|
||||||
|
|
||||||
let cacheRoot;
|
let cacheRoot: string;
|
||||||
|
|
||||||
export const findCacheRoot = async () => {
|
export const findCacheRoot = async () => {
|
||||||
if (cacheRoot) {
|
if (cacheRoot) {
|
||||||
@@ -83,9 +83,10 @@ export const reloadByondCache = async (bundleDir) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Get dreamseeker instances
|
// Get dreamseeker instances
|
||||||
const pids = cacheDirs.map((cacheDir) =>
|
const pids = cacheDirs.map((cacheDir) => {
|
||||||
parseInt(cacheDir.split('/cache/tmp').pop(), 10),
|
const ourDir = cacheDir.split('/cache/tmp').pop();
|
||||||
);
|
return parseInt(ourDir ? ourDir : '', 10);
|
||||||
|
});
|
||||||
const dssPromise = DreamSeeker.getInstancesByPids(pids);
|
const dssPromise = DreamSeeker.getInstancesByPids(pids);
|
||||||
// Copy assets
|
// Copy assets
|
||||||
const assets = await resolveGlob(
|
const assets = await resolveGlob(
|
||||||
@@ -22,7 +22,7 @@ export const resolveGlob = (...sections) => {
|
|||||||
silent: true,
|
silent: true,
|
||||||
windowsPathsNoEscape: true,
|
windowsPathsNoEscape: true,
|
||||||
});
|
});
|
||||||
const safePaths = [];
|
const safePaths: string[] = [];
|
||||||
for (let path of unsafePaths) {
|
for (let path of unsafePaths) {
|
||||||
try {
|
try {
|
||||||
fs.statSync(path);
|
fs.statSync(path);
|
||||||
@@ -26,6 +26,9 @@ export const createCompiler = async (options) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class WebpackCompiler {
|
class WebpackCompiler {
|
||||||
|
webpack: any;
|
||||||
|
config: any;
|
||||||
|
bundleDir: string;
|
||||||
async setup(options) {
|
async setup(options) {
|
||||||
// Create a require context that is relative to project root
|
// Create a require context that is relative to project root
|
||||||
// and retrieve all necessary dependencies.
|
// and retrieve all necessary dependencies.
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Action, AnyAction, Dispatch, Middleware } from 'common/redux';
|
import type { Action, AnyAction, Dispatch, Middleware } from 'common/redux';
|
||||||
|
|
||||||
const EXCLUDED_PATTERNS = [/v4shim/i];
|
const EXCLUDED_PATTERNS = [/v4shim/i];
|
||||||
const loadedMappings: Record<string, string> = {};
|
const loadedMappings: Record<string, string> = {};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Flex, Section, Tabs } from 'tgui-core/components';
|
import { Section, Stack, Tabs } from 'tgui-core/components';
|
||||||
|
|
||||||
import { Pane, Window } from '../layouts';
|
import { Pane, Window } from '../layouts';
|
||||||
|
|
||||||
@@ -21,17 +21,17 @@ const r = require.context('../stories', false, /\.stories\.jsx$/);
|
|||||||
*/
|
*/
|
||||||
const getStories = () => r.keys().map((path) => r(path));
|
const getStories = () => r.keys().map((path) => r(path));
|
||||||
|
|
||||||
export const KitchenSink = (props) => {
|
export const KitchenSink = (props: { panel: boolean }) => {
|
||||||
const { panel } = props;
|
const { panel } = props;
|
||||||
const [theme] = useState(null);
|
const [theme] = useState(undefined);
|
||||||
const [pageIndex, setPageIndex] = useState(0);
|
const [pageIndex, setPageIndex] = useState(0);
|
||||||
const stories = getStories();
|
const stories = getStories();
|
||||||
const story = stories[pageIndex];
|
const story = stories[pageIndex];
|
||||||
const Layout = panel ? Pane : Window;
|
const Layout = panel ? Pane : Window;
|
||||||
return (
|
return (
|
||||||
<Layout title="Kitchen Sink" width={600} height={500} theme={theme}>
|
<Layout title="Kitchen Sink" width={600} height={500} theme={theme}>
|
||||||
<Flex height="100%">
|
<Stack fill>
|
||||||
<Flex.Item m={1} mr={0}>
|
<Stack.Item m={1} mr={0}>
|
||||||
<Section fill fitted>
|
<Section fill fitted>
|
||||||
<Tabs vertical>
|
<Tabs vertical>
|
||||||
{stories.map((story, i) => (
|
{stories.map((story, i) => (
|
||||||
@@ -46,11 +46,11 @@ export const KitchenSink = (props) => {
|
|||||||
))}
|
))}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</Section>
|
</Section>
|
||||||
</Flex.Item>
|
</Stack.Item>
|
||||||
<Flex.Item position="relative" grow={1}>
|
<Stack.Item position="relative" grow>
|
||||||
<Layout.Content scrollable>{story.meta.render()}</Layout.Content>
|
<Layout.Content scrollable>{story.meta.render()}</Layout.Content>
|
||||||
</Flex.Item>
|
</Stack.Item>
|
||||||
</Flex>
|
</Stack>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import type { AnyAction, Middleware } from 'common/redux';
|
||||||
import { globalEvents } from 'tgui-core/events';
|
import { globalEvents } from 'tgui-core/events';
|
||||||
import { acquireHotKey } from 'tgui-core/hotkeys';
|
import { acquireHotKey } from 'tgui-core/hotkeys';
|
||||||
import { KEY_BACKSPACE, KEY_F10, KEY_F11, KEY_F12 } from 'tgui-core/keycodes';
|
import { KEY_BACKSPACE, KEY_F10, KEY_F11, KEY_F12 } from 'tgui-core/keycodes';
|
||||||
@@ -20,15 +21,15 @@ const relayedTypes = [
|
|||||||
'chat/message',
|
'chat/message',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const debugMiddleware = (store) => {
|
export const debugMiddleware: Middleware = (store) => {
|
||||||
acquireHotKey(KEY_F11);
|
acquireHotKey(KEY_F11);
|
||||||
acquireHotKey(KEY_F12);
|
acquireHotKey(KEY_F12);
|
||||||
globalEvents.on('keydown', (key) => {
|
globalEvents.on('keydown', (key) => {
|
||||||
if (key.code === KEY_F11) {
|
if (key.code === KEY_F11) {
|
||||||
store.dispatch(toggleDebugLayout());
|
store.dispatch(toggleDebugLayout() as any);
|
||||||
}
|
}
|
||||||
if (key.code === KEY_F12) {
|
if (key.code === KEY_F12) {
|
||||||
store.dispatch(toggleKitchenSink());
|
store.dispatch(toggleKitchenSink() as any);
|
||||||
}
|
}
|
||||||
if (key.ctrl && key.alt && key.code === KEY_BACKSPACE) {
|
if (key.ctrl && key.alt && key.code === KEY_BACKSPACE) {
|
||||||
// NOTE: We need to call this in a timeout, because we need a clean
|
// NOTE: We need to call this in a timeout, because we need a clean
|
||||||
@@ -45,7 +46,7 @@ export const debugMiddleware = (store) => {
|
|||||||
return (next) => (action) => next(action);
|
return (next) => (action) => next(action);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const relayMiddleware = (store) => {
|
export const relayMiddleware: Middleware = (store) => {
|
||||||
const devServer = require('tgui-dev-server/link/client.cjs');
|
const devServer = require('tgui-dev-server/link/client.cjs');
|
||||||
const externalBrowser = location.search === '?external';
|
const externalBrowser = location.search === '?external';
|
||||||
if (externalBrowser) {
|
if (externalBrowser) {
|
||||||
@@ -62,12 +63,12 @@ export const relayMiddleware = (store) => {
|
|||||||
acquireHotKey(KEY_F10);
|
acquireHotKey(KEY_F10);
|
||||||
globalEvents.on('keydown', (key) => {
|
globalEvents.on('keydown', (key) => {
|
||||||
if (key === KEY_F10) {
|
if (key === KEY_F10) {
|
||||||
store.dispatch(openExternalBrowser());
|
store.dispatch(openExternalBrowser() as any);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return (next) => (action) => {
|
return (next) => (action) => {
|
||||||
const { type, payload, relayed } = action;
|
const { type, payload, relayed } = action as AnyAction;
|
||||||
if (type === openExternalBrowser.type) {
|
if (type === openExternalBrowser.type) {
|
||||||
window.open(location.href + '?external', '_blank');
|
window.open(location.href + '?external', '_blank');
|
||||||
return;
|
return;
|
||||||
@@ -4,7 +4,11 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const debugReducer = (state = {}, action) => {
|
import type { ActionData } from './types';
|
||||||
|
|
||||||
|
type StateData = { kitchenSink: boolean; debugLayout: boolean };
|
||||||
|
|
||||||
|
export const debugReducer = (state = {} as StateData, action: ActionData) => {
|
||||||
const { type, payload } = action;
|
const { type, payload } = action;
|
||||||
if (type === 'debug/toggleKitchenSink') {
|
if (type === 'debug/toggleKitchenSink') {
|
||||||
return {
|
return {
|
||||||
1
tgui/packages/tgui/debug/types.ts
Normal file
1
tgui/packages/tgui/debug/types.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export type ActionData = { type: string; payload: any; relayed: boolean };
|
||||||
@@ -10,9 +10,23 @@ import { Box, Button, Image } from 'tgui-core/components';
|
|||||||
|
|
||||||
import { Window } from './Window';
|
import { Window } from './Window';
|
||||||
|
|
||||||
|
type Header = { icon: string };
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
PC_device_theme: string;
|
||||||
|
PC_batteryicon: string;
|
||||||
|
PC_showbatteryicon: boolean;
|
||||||
|
PC_batterypercent: number;
|
||||||
|
PC_ntneticon: string;
|
||||||
|
PC_stationdate: string;
|
||||||
|
PC_stationtime: string;
|
||||||
|
PC_programheaders: Header[];
|
||||||
|
PC_showexitprogram: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export const NtosWindow = (props) => {
|
export const NtosWindow = (props) => {
|
||||||
const { title, width = 575, height = 700, children } = props;
|
const { title, width = 575, height = 700, children } = props;
|
||||||
const { act, data } = useBackend();
|
const { act, data } = useBackend<Data>();
|
||||||
const {
|
const {
|
||||||
PC_device_theme,
|
PC_device_theme,
|
||||||
PC_batteryicon,
|
PC_batteryicon,
|
||||||
20
tgui/packages/tgui/stories/Blink.stories.tsx
Normal file
20
tgui/packages/tgui/stories/Blink.stories.tsx
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @copyright 2021 Aleksej Komarov
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Blink, Section } from 'tgui-core/components';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
title: 'Blink',
|
||||||
|
render: () => <Story />,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Story = (props) => {
|
||||||
|
return (
|
||||||
|
<Section>
|
||||||
|
<Blink>Blink</Blink>
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
};
|
||||||
24
tgui/packages/tgui/stories/BlockQuote.stories.tsx
Normal file
24
tgui/packages/tgui/stories/BlockQuote.stories.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @copyright 2021 Aleksej Komarov
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { BlockQuote, Section } from 'tgui-core/components';
|
||||||
|
|
||||||
|
import { BoxWithSampleText } from './common';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
title: 'BlockQuote',
|
||||||
|
render: () => <Story />,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Story = (props) => {
|
||||||
|
return (
|
||||||
|
<Section>
|
||||||
|
<BlockQuote>
|
||||||
|
<BoxWithSampleText />
|
||||||
|
</BlockQuote>
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -34,7 +34,6 @@ const Story = (props) => {
|
|||||||
<Box mb={1}>
|
<Box mb={1}>
|
||||||
<Button>Simple</Button>
|
<Button>Simple</Button>
|
||||||
<Button selected>Selected</Button>
|
<Button selected>Selected</Button>
|
||||||
<Button altSelected>Alt Selected</Button>
|
|
||||||
<Button disabled>Disabled</Button>
|
<Button disabled>Disabled</Button>
|
||||||
<Button color="transparent">Transparent</Button>
|
<Button color="transparent">Transparent</Button>
|
||||||
<Button icon="cog">Icon</Button>
|
<Button icon="cog">Icon</Button>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { logger } from 'tgui/logging';
|
import { logger } from 'tgui/logging';
|
||||||
import { Box, Button, ByondUi, Section } from 'tgui-core/components';
|
import { Button, ByondUi, Section, TextArea } from 'tgui-core/components';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
title: 'ByondUi',
|
title: 'ByondUi',
|
||||||
@@ -52,14 +52,13 @@ const Story = (props) => {
|
|||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Box
|
<TextArea
|
||||||
as="textarea"
|
|
||||||
width="100%"
|
width="100%"
|
||||||
height="10em"
|
height="10em"
|
||||||
onChange={(e) => setCode(e.target.value)}
|
onChange={(_, value) => setCode(value)}
|
||||||
>
|
>
|
||||||
{code}
|
{code}
|
||||||
</Box>
|
</TextArea>
|
||||||
</Section>
|
</Section>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -23,23 +23,28 @@ const Story = (props) => {
|
|||||||
const [progress, setProgress] = useState(0.5);
|
const [progress, setProgress] = useState(0.5);
|
||||||
const [color, setColor] = useState('');
|
const [color, setColor] = useState('');
|
||||||
|
|
||||||
const color_data = color
|
|
||||||
? { color: color }
|
|
||||||
: {
|
|
||||||
ranges: {
|
|
||||||
good: [0.5, Infinity],
|
|
||||||
bad: [-Infinity, 0.1],
|
|
||||||
average: [0, 0.5],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<ProgressBar {...color_data} minValue={-1} maxValue={1} value={progress}>
|
{color ? (
|
||||||
Value: {Number(progress).toFixed(1)}
|
<ProgressBar color={color} minValue={-1} maxValue={1} value={progress}>
|
||||||
</ProgressBar>
|
Value: {Number(progress).toFixed(1)}
|
||||||
<Box mt={1}>
|
</ProgressBar>
|
||||||
<LabeledList mt="2em">
|
) : (
|
||||||
|
<ProgressBar
|
||||||
|
ranges={{
|
||||||
|
good: [0.5, Infinity],
|
||||||
|
bad: [-Infinity, 0.1],
|
||||||
|
average: [0, 0.5],
|
||||||
|
}}
|
||||||
|
minValue={-1}
|
||||||
|
maxValue={1}
|
||||||
|
value={progress}
|
||||||
|
>
|
||||||
|
Value: {Number(progress).toFixed(1)}
|
||||||
|
</ProgressBar>
|
||||||
|
)}
|
||||||
|
<Box mt={1} mb="2em">
|
||||||
|
<LabeledList>
|
||||||
<LabeledList.Item label="Adjust value">
|
<LabeledList.Item label="Adjust value">
|
||||||
<Button onClick={() => setProgress(progress - 0.1)}>-0.1</Button>
|
<Button onClick={() => setProgress(progress - 0.1)}>-0.1</Button>
|
||||||
<Button onClick={() => setProgress(progress + 0.1)}>+0.1</Button>
|
<Button onClick={() => setProgress(progress + 0.1)}>+0.1</Button>
|
||||||
@@ -12,10 +12,19 @@ export const meta = {
|
|||||||
render: () => <Story />,
|
render: () => <Story />,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type TabProps = {
|
||||||
|
vertical: boolean;
|
||||||
|
leftSlot: boolean;
|
||||||
|
rightSlot: boolean;
|
||||||
|
icon: boolean;
|
||||||
|
fluid: boolean;
|
||||||
|
centered: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
const TAB_RANGE = ['Tab #1', 'Tab #2', 'Tab #3', 'Tab #4'];
|
const TAB_RANGE = ['Tab #1', 'Tab #2', 'Tab #3', 'Tab #4'];
|
||||||
|
|
||||||
const Story = (props) => {
|
const Story = (props) => {
|
||||||
const [tabProps, setTabProps] = useState({});
|
const [tabProps, setTabProps] = useState({} as TabProps);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Section>
|
<Section>
|
||||||
@@ -93,23 +102,23 @@ const Story = (props) => {
|
|||||||
</Button.Checkbox>
|
</Button.Checkbox>
|
||||||
</Section>
|
</Section>
|
||||||
<Section fitted>
|
<Section fitted>
|
||||||
<TabsPrefab />
|
<TabsPrefab tabProps={tabProps} />
|
||||||
</Section>
|
</Section>
|
||||||
<Section title="Normal section">
|
<Section title="Normal section">
|
||||||
<TabsPrefab />
|
<TabsPrefab tabProps={tabProps} />
|
||||||
Some text
|
Some text
|
||||||
</Section>
|
</Section>
|
||||||
<Section>
|
<Section>
|
||||||
Section-less tabs appear the same as tabs in a fitted section:
|
Section-less tabs appear the same as tabs in a fitted section:
|
||||||
</Section>
|
</Section>
|
||||||
<TabsPrefab />
|
<TabsPrefab tabProps={tabProps} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const TabsPrefab = (props) => {
|
const TabsPrefab = (props: { tabProps: TabProps }) => {
|
||||||
const [tabIndex, setTabIndex] = useState(0);
|
const [tabIndex, setTabIndex] = useState(0);
|
||||||
const [tabProps] = useState({});
|
const { tabProps } = props;
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
vertical={tabProps.vertical}
|
vertical={tabProps.vertical}
|
||||||
@@ -120,7 +129,7 @@ const TabsPrefab = (props) => {
|
|||||||
<Tabs.Tab
|
<Tabs.Tab
|
||||||
key={i}
|
key={i}
|
||||||
selected={i === tabIndex}
|
selected={i === tabIndex}
|
||||||
icon={tabProps.icon && 'info-circle'}
|
icon={tabProps.icon ? 'info-circle' : undefined}
|
||||||
leftSlot={
|
leftSlot={
|
||||||
tabProps.leftSlot && (
|
tabProps.leftSlot && (
|
||||||
<Button circular compact color="transparent" icon="times" />
|
<Button circular compact color="transparent" icon="times" />
|
||||||
@@ -4,24 +4,25 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState } from 'react';
|
|
||||||
import { Input, LabeledList, Section } from 'tgui-core/components';
|
import { Input, LabeledList, Section } from 'tgui-core/components';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
title: 'Themes',
|
title: 'Themes',
|
||||||
render: () => <Story />,
|
render: (theme, setTheme) => <Story theme={theme} setTheme={setTheme} />,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Story = (props) => {
|
const Story = (props: {
|
||||||
const [theme, setTheme] = useState('kitchenSinkTheme');
|
readonly theme: string;
|
||||||
|
readonly setTheme: Function;
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<LabeledList>
|
<LabeledList>
|
||||||
<LabeledList.Item label="Use theme">
|
<LabeledList.Item label="Use theme">
|
||||||
<Input
|
<Input
|
||||||
placeholder="theme_name"
|
placeholder="theme_name"
|
||||||
value={theme}
|
value={props.theme}
|
||||||
onInput={(e, value) => setTheme(value)}
|
onInput={(e, value) => props.setTheme(value)}
|
||||||
/>
|
/>
|
||||||
</LabeledList.Item>
|
</LabeledList.Item>
|
||||||
</LabeledList>
|
</LabeledList>
|
||||||
Reference in New Issue
Block a user