From 5d79c2690d8771c490b718355f1b718d2be424a6 Mon Sep 17 00:00:00 2001 From: pd-redis Date: Mon, 28 Jul 2025 12:39:57 +0300 Subject: [PATCH 1/3] add playground --- .../ui/src/components/main-router/config.ts | 1 + .../main-router/constants/commonRoutes.ts | 11 ++- .../ui/src/pages/playground/Colors.tsx | 85 +++++++++++++++++++ .../ui/src/pages/playground/Gallery.tsx | 49 +++++++++++ .../src/pages/playground/PlaygroundPage.tsx | 65 ++++++++++++++ .../ui/src/pages/playground/Theme.tsx | 27 ++++++ 6 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 redisinsight/ui/src/pages/playground/Colors.tsx create mode 100644 redisinsight/ui/src/pages/playground/Gallery.tsx create mode 100644 redisinsight/ui/src/pages/playground/PlaygroundPage.tsx create mode 100644 redisinsight/ui/src/pages/playground/Theme.tsx diff --git a/redisinsight/ui/src/components/main-router/config.ts b/redisinsight/ui/src/components/main-router/config.ts index 6ece43863f..b9ce5776dd 100644 --- a/redisinsight/ui/src/components/main-router/config.ts +++ b/redisinsight/ui/src/components/main-router/config.ts @@ -4,6 +4,7 @@ import { getConfig } from 'uiSrc/config' const riConfig = getConfig() export const LAZY_LOAD = riConfig?.app?.lazyLoad +export const LOAD_PLAYGROUND = riConfig?.app?.env !== 'production' export const ROUTES_EXCLUDED_BY_ENV = riConfig?.app?.routesExcludedByEnv diff --git a/redisinsight/ui/src/components/main-router/constants/commonRoutes.ts b/redisinsight/ui/src/components/main-router/constants/commonRoutes.ts index b20420c6ec..0fad97da88 100644 --- a/redisinsight/ui/src/components/main-router/constants/commonRoutes.ts +++ b/redisinsight/ui/src/components/main-router/constants/commonRoutes.ts @@ -6,7 +6,9 @@ import { SentinelDatabasesResultPage, SentinelPage, } from 'uiSrc/pages/autodiscover-sentinel' -import { LAZY_LOAD } from '../config' +import { PlaygroundPage } from 'uiSrc/pages/playground/PlaygroundPage' + +import { LAZY_LOAD, LOAD_PLAYGROUND } from '../config' const LazySettingsPage = lazy(() => import('uiSrc/pages/settings')) const LazySentinelDatabasesPage = lazy( @@ -44,4 +46,11 @@ const ROUTES: IRoute[] = [ }, ] +if (LOAD_PLAYGROUND) { + ROUTES.push({ + path: '/playground', + component: PlaygroundPage, + }) +} + export default ROUTES diff --git a/redisinsight/ui/src/pages/playground/Colors.tsx b/redisinsight/ui/src/pages/playground/Colors.tsx new file mode 100644 index 0000000000..d1d762ce85 --- /dev/null +++ b/redisinsight/ui/src/pages/playground/Colors.tsx @@ -0,0 +1,85 @@ +import React from 'react' +import { useTheme } from '@redis-ui/styles' +import { Col, Grid } from 'uiSrc/components/base/layout/flex' +import { Text } from 'uiSrc/components/base/text' +import { Title } from 'uiSrc/components/base/text/Title' + +const ColorItem = ({ + color, + colorName, +}: { + color: string + colorName: string +}) => ( + + {colorName} +
+ {color} + +) +const ColorSectionTitle = ({ title }: { title: string }) => ( + + {title} + +) + +const ColorSection = ({ + title, + colors, +}: { + title: string + colors: [string, string][] +}) => ( + <> + + + {colors.map(([colorName, color]) => ( + + ))} + + +) + +export const Colors = () => { + const theme = useTheme() + const { color: rootColors, semantic } = theme + const { color: semanticColors } = semantic + return ( + <> + + + {Object.entries(semanticColors).map(([colorSection, colors]) => ( + + ))} + + ) +} diff --git a/redisinsight/ui/src/pages/playground/Gallery.tsx b/redisinsight/ui/src/pages/playground/Gallery.tsx new file mode 100644 index 0000000000..e8bc1b36b8 --- /dev/null +++ b/redisinsight/ui/src/pages/playground/Gallery.tsx @@ -0,0 +1,49 @@ +import React from 'react' +import { FlexItem, Grid } from 'uiSrc/components/base/layout/flex' +import { AllIconsType, RiIcon } from 'uiSrc/components/base/icons/RiIcon' +import * as Icons from 'uiSrc/components/base/icons/iconRegistry' + +const skip = [ + 'IconProps', + 'Icon', + 'IconSizeType', + 'IconColorType', + 'ColorIconProps', + 'MonochromeIconProps', + 'IconType', +] +export const Gallery = () => ( + + {Object.keys(Icons).map((icon) => { + if (skip.includes(icon)) { + return null + } + return ( + + + {icon} + + ) + })} + +) diff --git a/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx b/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx new file mode 100644 index 0000000000..ba781f238b --- /dev/null +++ b/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx @@ -0,0 +1,65 @@ +import React from 'react' +import { Col, Row } from 'uiSrc/components/base/layout/flex' +import { Title } from 'uiSrc/components/base/text/Title' +import { Theme } from './Theme' +import { Gallery } from './Gallery' +import { Colors } from './Colors' + +export const PlaygroundPage = () => ( + + + Playground + + + + + Theme + + + + Icons + + + + + Colors + + + + +) diff --git a/redisinsight/ui/src/pages/playground/Theme.tsx b/redisinsight/ui/src/pages/playground/Theme.tsx new file mode 100644 index 0000000000..e3e3e810c8 --- /dev/null +++ b/redisinsight/ui/src/pages/playground/Theme.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import { useTheme } from '@redis-ui/styles' +import ReactMonacoEditor from 'react-monaco-editor' +import { Col } from 'uiSrc/components/base/layout/flex' + +export const Theme = () => { + const theme = useTheme() + const monacoOptions = { + readOnly: true, + automaticLayout: true, + minimap: { + enabled: false, + }, + } + return ( + + + + ) +} From 42e9f44ad306167d077fa770ab3c0309c2decfe9 Mon Sep 17 00:00:00 2001 From: pd-redis Date: Mon, 28 Jul 2025 12:55:32 +0300 Subject: [PATCH 2/3] improve styles --- redisinsight/ui/src/pages/playground/PlaygroundPage.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx b/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx index ba781f238b..5d62375be0 100644 --- a/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx +++ b/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx @@ -13,6 +13,8 @@ export const PlaygroundPage = () => ( // backgroundColor: 'yellow', maxWidth: '100%', position: 'relative', + maxHeight: '100%', + overflow: 'auto', }} > Date: Mon, 28 Jul 2025 19:04:41 +0300 Subject: [PATCH 3/3] add some formatted theme output --- .../ui/src/pages/playground/Colors.tsx | 4 +- .../src/pages/playground/PlaygroundPage.tsx | 3 +- .../ui/src/pages/playground/Theme.tsx | 341 +++++++++++++++++- 3 files changed, 334 insertions(+), 14 deletions(-) diff --git a/redisinsight/ui/src/pages/playground/Colors.tsx b/redisinsight/ui/src/pages/playground/Colors.tsx index d1d762ce85..d1750633b6 100644 --- a/redisinsight/ui/src/pages/playground/Colors.tsx +++ b/redisinsight/ui/src/pages/playground/Colors.tsx @@ -17,7 +17,7 @@ const ColorItem = ({ alignItems: 'center', backgroundColor: '#aaa', opacity: 0.8, - padding: 20, + padding: 10, minWidth: 200, }} > @@ -34,7 +34,7 @@ const ColorItem = ({ ) const ColorSectionTitle = ({ title }: { title: string }) => ( - + <Title size="S" style={{ textAlign: 'center', marginTop: 10 }}> {title} ) diff --git a/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx b/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx index 5d62375be0..51777a7777 100644 --- a/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx +++ b/redisinsight/ui/src/pages/playground/PlaygroundPage.tsx @@ -41,7 +41,7 @@ export const PlaygroundPage = () => ( - + Theme @@ -50,7 +50,6 @@ export const PlaygroundPage = () => ( Icons - { + // If it's already in pixels, return as is + if (value.endsWith('px')) { + return { original: value, pixels: value } + } + + // Handle rem values + if (value.endsWith('rem')) { + const remValue = parseFloat(value) + // Get the root font size (default to 16px if not set) + const rootFontSize = + parseFloat(getComputedStyle(document.documentElement).fontSize) || 16 + const pixelValue = remValue * rootFontSize + return { original: value, pixels: `${pixelValue.toFixed(2)}px` } + } + + // Handle em values (would need the element's font size) + // This is more complex as it depends on the parent element + + // For other units, return null for pixels + return { original: value, pixels: null } +} export const Theme = () => { const theme = useTheme() @@ -12,16 +49,300 @@ export const Theme = () => { enabled: false, }, } + const [viewTab, setViewTab] = useState(ThemeTabs.raw) + const tabs: TabInfo[] = useMemo(() => { + const visibleTabs: TabInfo[] = [ + { + value: ThemeTabs.raw, + content: ( + <ReactMonacoEditor + language="json" + value={JSON.stringify(theme, null, 2)} + options={monacoOptions} + theme="light" + height={500} + width={900} + /> + ), + label: <Text>Raw</Text>, + }, + { + value: ThemeTabs.formatted, + content: ( + <Col style={{ padding: 20 }} gap="l"> + <Title size="M"> + Name:{' '} + <ColorText variant="semiBold" color="accent"> + {theme.name} + </ColorText> + + + <Link href="#colors" isExternalLink={false} target="_self"> + Colors + </Link> + + Core + Spaces + + Shadows + + Fonts + + Z-Index + + {Object.entries(theme.core.zIndex).map(([name, value]) => ( + + ))} + + Focus +
+ {Object.entries(theme.core.focus).map(([name, value]) => ( + +
{name}
+
{value}
+
+ ))} +
+ + ), + label: Formatted, + }, + ] + + return visibleTabs + }, [viewTab]) + const handleTabChange = (id: string) => { + if (viewTab === id) return + setViewTab(id as ThemeTabs) + } return ( - - + + + ) +} +/* + + "focus": { + "margin": "2px", + "size": "2px", + "color": "#091a23" + } + */ +const ZIndexItem = ({ name, value }: { name: string; value: string }) => ( + +
+
{name}
+
+ {value} +
+
+ +) + +const Fonts = ({ + fonts, +}: { + fonts: { + fontFamily: Record + fontSize: Record + } +}) => ( + + Font faces + {Object.entries(fonts.fontFamily).map(([name, value]) => ( +
+
+
{name}
+
+ + {value} + +
+
+
+ ))} + Font sizes + + {Object.entries(fonts.fontSize).map(([name, value]) => ( + + ))} + +) + +const FontItem = ({ + name, + value, + fontFaces, +}: { + name: string + value: string + fontFaces: Record +}) => { + const { pixels } = convertToPixels(value) + + return ( + +
+
{name}
+
+ + {value} {pixels && `(${pixels})`} + + {Object.values(fontFaces).map((fontFace) => ( + + Sample text 0124 ,.;: + + ))} +
+
+ + ) +} + +const Shadows = ({ shadows }: { shadows: Record }) => ( + + {Object.entries(shadows).map(([name, value]) => ( + + ))} + +) + +const ShadowItem = ({ name, value }: { name: string; value: string }) => { + const style = { + width: '100%', + height: 35, + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + backgroundColor: 'transparent', + border: '1px solid #00000022', + boxShadow: value, + } + + return ( + +
+ + {name} + +
+ + ) +} +const Spaces = ({ spaces }: { spaces: Record }) => ( + + {Object.entries(spaces).map(([name, value]) => ( + + ))} + +) + +const SpaceItem = ({ name, value }: { name: string; value: string }) => { + const style = { + width: 50, + height: 15, + backgroundColor: 'transparent', + border: '1px solid black', + } + + const { pixels } = convertToPixels(value) + + return ( + +
+
{name}
+
+ + {value} {pixels && `(${pixels})`} + +
+
+ + +
+
+ ) }