From 81b0f7cde8914ec235489e88b29aae4fbfa57dc5 Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Tue, 8 Apr 2025 12:01:52 +0100 Subject: [PATCH 1/5] initial code widget --- .../managing-data/core-concepts/partitions.md | 2 +- docusaurus.config.en.js | 3 +- package.json | 13 +- plugins/tailwind-config.js | 9 + postcss.config.js | 5 + src/components/CodeViewer/CodeInterpreter.tsx | 296 ++++++ src/components/CodeViewer/CodeResults.tsx | 347 +++++++ .../CodeViewer/charts/bar/index.tsx | 271 ++++++ .../CodeViewer/charts/candlestick/index.tsx | 231 +++++ .../CodeViewer/charts/heatmap/index.tsx | 260 ++++++ .../charts/heatmap/styles.module.css | 31 + src/components/CodeViewer/charts/index.tsx | 122 +++ .../CodeViewer/charts/line/index.tsx | 357 +++++++ .../CodeViewer/charts/line/styles.module.css | 37 + .../CodeViewer/charts/pie/index.tsx | 183 ++++ .../CodeViewer/copy/copyGridElements.tsx | 179 ++++ src/components/CodeViewer/index.tsx | 88 ++ src/components/CodeViewer/types.tsx | 87 ++ src/components/CodeViewer/utils.ts | 58 ++ src/css/custom.scss | 7 +- src/theme/CodeBlock/index.js | 8 +- static/images/loading.svg | 9 + tailwind.config.js | 406 ++++++++ yarn.lock | 874 +++++++++++++++++- 24 files changed, 3868 insertions(+), 15 deletions(-) create mode 100644 plugins/tailwind-config.js create mode 100644 postcss.config.js create mode 100644 src/components/CodeViewer/CodeInterpreter.tsx create mode 100644 src/components/CodeViewer/CodeResults.tsx create mode 100644 src/components/CodeViewer/charts/bar/index.tsx create mode 100644 src/components/CodeViewer/charts/candlestick/index.tsx create mode 100644 src/components/CodeViewer/charts/heatmap/index.tsx create mode 100644 src/components/CodeViewer/charts/heatmap/styles.module.css create mode 100644 src/components/CodeViewer/charts/index.tsx create mode 100644 src/components/CodeViewer/charts/line/index.tsx create mode 100644 src/components/CodeViewer/charts/line/styles.module.css create mode 100644 src/components/CodeViewer/charts/pie/index.tsx create mode 100644 src/components/CodeViewer/copy/copyGridElements.tsx create mode 100644 src/components/CodeViewer/index.tsx create mode 100644 src/components/CodeViewer/types.tsx create mode 100644 src/components/CodeViewer/utils.ts create mode 100644 static/images/loading.svg create mode 100644 tailwind.config.js diff --git a/docs/managing-data/core-concepts/partitions.md b/docs/managing-data/core-concepts/partitions.md index fc07dc6d34a..d43499970ff 100644 --- a/docs/managing-data/core-concepts/partitions.md +++ b/docs/managing-data/core-concepts/partitions.md @@ -25,7 +25,7 @@ Partitioning can be enabled when a table is initially defined via the [PARTITION To illustrate this, we [enhance](https://sql.clickhouse.com/?query=U0hPVyBDUkVBVEUgVEFCTEUgdWsudWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQ&run_query=true&tab=results) the [What are table parts](/parts) example table by adding a `PARTITION BY toStartOfMonth(date)` clause, which organizes the table`s data parts based on the months of property sales: -```sql +```sql runnable=true view=chart show_statistics=false CREATE TABLE uk.uk_price_paid_simple_partitioned ( date Date, diff --git a/docusaurus.config.en.js b/docusaurus.config.en.js index 74485aedd4f..3aa26d0e5e4 100644 --- a/docusaurus.config.en.js +++ b/docusaurus.config.en.js @@ -355,7 +355,8 @@ const config = { [ pluginLlmsTxt, {} - ] + ], + ['./plugins/tailwind-config.js', {}], ], customFields: { blogSidebarLink: "/docs/knowledgebase", // Used for KB article page diff --git a/package.json b/package.json index b76d7ee167b..55b777f839c 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,8 @@ "run-markdown-linter": "yarn markdownlint-cli2 --config ./scripts/.markdownlint-cli2.yaml 'docs/**/*.md'" }, "dependencies": { + "@clickhouse/click-ui": "^0.0.199", + "@clickhouse/client-web": "^1.11.0", "@docusaurus/core": "3.7.0", "@docusaurus/faster": "^3.7.0", "@docusaurus/plugin-client-redirects": "^3.7.0", @@ -41,8 +43,11 @@ "axios": "^1.8.2", "clsx": "^2.1.0", "docusaurus-plugin-sass": "^0.2.6", + "echarts": "^5.6.0", + "echarts-for-react": "^3.0.2", "esbuild": "^0.25.0", "esbuild-loader": "^4.0.3", + "filesize": "^10.1.6", "flexsearch": "^0.7.43", "gray-matter": "^4.0.3", "hast-util-is-element": "1.1.0", @@ -50,6 +55,7 @@ "katex": "^0.16.21", "markdownlint-cli2": "^0.17.2", "node-fetch": "^3.3.2", + "numeral": "^2.0.6", "prism-react-renderer": "^2.4.1", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -59,18 +65,23 @@ "remark-link-rewrite": "^1.0.7", "remark-math": "^6.0.0", "sass": "^1.86.1", - "search-insights": "^2.17.3" + "search-insights": "^2.17.3", + "short-uuid": "^5.2.0" }, "devDependencies": { "@argos-ci/cli": "^2.5.5", "@argos-ci/playwright": "^3.9.4", "@docusaurus/module-type-aliases": "3.7.0", "@playwright/test": "^1.51.1", + "@tailwindcss/postcss": "^4.1.3", + "@tailwindcss/typography": "^0.5.16", "@types/react": "^19.0.4", "@types/styled-jsx": "^3.4.4", "cheerio": "^1.0.0", "markdownlint-rule-helpers": "^0.28.0", + "postcss": "^8.5.3", "rsync": "^0.6.1", + "tailwindcss": "^4.1.3", "typescript": "^5.8.2" }, "browserslist": { diff --git a/plugins/tailwind-config.js b/plugins/tailwind-config.js new file mode 100644 index 00000000000..f2ded6a68fb --- /dev/null +++ b/plugins/tailwind-config.js @@ -0,0 +1,9 @@ +module.exports = function tailwindPlugin(context, options) { + return { + name: 'tailwind-plugin', + configurePostCss(postcssOptions) { + postcssOptions.plugins = [require('@tailwindcss/postcss')] + return postcssOptions + } + } +} \ No newline at end of file diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000000..241bd693e33 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + '@tailwindcss/postcss': {}, + } +} \ No newline at end of file diff --git a/src/components/CodeViewer/CodeInterpreter.tsx b/src/components/CodeViewer/CodeInterpreter.tsx new file mode 100644 index 00000000000..c76e7fe55a9 --- /dev/null +++ b/src/components/CodeViewer/CodeInterpreter.tsx @@ -0,0 +1,296 @@ +import { Button, Icon, RadioGroup, Tooltip } from '@clickhouse/click-ui/bundled' +import { createClient as createWebClient } from '@clickhouse/client-web' +import { parse } from 'json5' +import { useEffect, useState } from 'react' +import short from 'short-uuid' +import CodeResults, { DefaultView } from './CodeResults' +import { + ChartConfig, + ChartType, + QueryParameter, + QueryResponse, + QueryResults +} from './types' +import { formatBytes, formatReadableRows, roundToDynamicPrecision } from './utils' +import { getGoogleAnalyticsUserIdFromBrowserCookie } from '../../lib/google/google' + + +interface Props { + queryString: string + runnable: boolean + link: string + run: boolean + view: DefaultView + chart?: { type: ChartType; config?: ChartConfig } + settings: string + show_statistics: boolean +} + +function CodeInterpreter({ + queryString, + runnable, + link, + run, + view, + chart, + settings, + show_statistics +}: Props) { + const [results, setResults] = useState(null) + const [showResultsPanel, setShowResultsPanel] = useState(false) + const [queryRunning, setQueryRunning] = useState(false) + const [currentView, setCurrentView] = useState(view) + const [runByUser, setRunByUser] = useState(false) + + const clickhouse_settings = JSON.parse(settings) + const clickhouse_web = createWebClient({ + url: 'https://sql-clickhouse.clickhouse.com', + username: 'demo', + password: '', + clickhouse_settings: { + ...clickhouse_settings, + allow_experimental_analyzer: 1, + result_overflow_mode: 'break', + read_overflow_mode: 'break' + } + }) + + function generateId(): string { + return short.generate().toUpperCase().slice(0, 27) + } + + async function query( + query: string, + query_id: string, + params: Array, + runManually: boolean + ): Promise { + if (!query) { + return { error: 'Query not provided', status: 400, query_id: query_id } + } + query = query.replace(/;$/, '').trim() + + const query_params: { [key: string]: string } = {} + params.forEach((param) => { + if (param.type && /^(Array|Map|Tuple|Nested)/.test(param.type)) { + try { + query_params[param.name] = parse(param.value) + } catch (e) { + // just send and let clickhouse error + query_params[param.name] = param.value + } + } else { + query_params[param.name] = param.value + } + }) + + try { + // Inject metadata as log comment + const currentPath = typeof window !== 'undefined' ? window.location.pathname : '' + let jsonLogComment: Record = {} + if (typeof window !== "undefined") { + let gaId = getGoogleAnalyticsUserIdFromBrowserCookie('_ga') + if (gaId) { + jsonLogComment['ga_id'] = gaId + } + } + if (currentPath) { + jsonLogComment['url_path'] = currentPath + } + jsonLogComment['auto_run'] = !runManually + + const res = await clickhouse_web.query({ + query: query, + query_id: query_id, + query_params: query_params, + clickhouse_settings: { + log_comment: JSON.stringify(jsonLogComment), + } + }) + const json = (await res.json()) as QueryResults + if (json.exception) { + console.error('Error while running query', json.exception) + return { + query: query, + status: 500, + response: json, + query_id: query_id, + error: json.exception + } + } + return { query: query, status: 200, response: json, query_id: query_id } + } catch (error) { + console.error('Error while running query', error) + return { error: error, status: 500, query_id: query_id } + } + } + + useEffect(() => { + if (run) { + handleRunQuery(false) + } + }, [run]) + + const handleRunQuery = async (runManually: boolean) => { + + const query_run_id = generateId() + setResults({}) + setQueryRunning(true) + setShowResultsPanel(true) + + const res = await query(queryString, query_run_id, [], runManually) + setQueryRunning(false) + setResults({ + response: res.response, + query_id: res.query_id, + error: res.error + }) + setRunByUser(runManually) + } + + const closeResultPanel = (event: any) => { + event.preventDefault() + setShowResultsPanel(false) + } + + const openTableResultPanel = (event: any) => { + event.preventDefault() + setShowResultsPanel(true) + } + + const runBy = () => { + if (runByUser) { + return 'Executed by user.' + } else { + if (run) { + return 'Executed on load.' + } + } + } + + const hideTableResultButton = () => { + if (results) { + const show_results = showResultsPanel ? ( + + + + + Close the results + + ) : ( + + + + + Open the results + + ) + + return ( +
+ {show_results} + {chart && ( +
+ + { + setCurrentView(DefaultView.Table) + }} + value={DefaultView.Table} + /> + { + setCurrentView(DefaultView.Chart) + }} + value={DefaultView.Chart} + /> + +
+ )} + +
+ ) + } + } + + const runButton = () => { + if (runnable) { + return ( +
+
+
{hideTableResultButton()}
+
+ {show_statistics && results?.response?.statistics && ( +
+ {`${runBy()} Read ${formatReadableRows(results.response.statistics.rows_read)} rows and ${formatBytes(results.response.statistics.bytes_read)} in ${roundToDynamicPrecision(results.response.statistics.elapsed)} seconds`} +
+ )} +
+
+ +
+
+ + + + + Run the query + +
+ {link && ( + + + + + + + Open in Play + + )} +
+
+ ) + } + } + + return ( + <> + {runButton()} +
+ {showResultsPanel && ( + + )} +
+ + ) +} + +export default CodeInterpreter diff --git a/src/components/CodeViewer/CodeResults.tsx b/src/components/CodeViewer/CodeResults.tsx new file mode 100644 index 00000000000..a57a3264228 --- /dev/null +++ b/src/components/CodeViewer/CodeResults.tsx @@ -0,0 +1,347 @@ +import { + CellProps, + createToast, + Grid, + Icon, + SelectedRegion, + SelectionFocus, + Tooltip, +} from '@clickhouse/click-ui/bundled' + +import { useCallback, useRef, useMemo, useState } from 'react' +import Chart from './charts' +import copyGridElements from './copy/copyGridElements' +import { ChartConfig, ChartType, QueryResults } from './types' +import LoadingSVG from '@site/static/images/loading.svg' + +export enum DefaultView { + Chart = 'chart', + Table = 'table' +} + +interface ResultsProps { + results?: { response?: QueryResults; query_id?: string; error: string } + queryRunning: boolean + view: DefaultView + chart?: { type: ChartType; config?: ChartConfig } +} + +export enum Position { + Start = 'start', + End = 'end', + Center = 'center' +} + +interface LoadingProps { + position?: Position + className?: string +} + +const Loading: React.FC = ({ + position = Position.Start, + className = '' +}) => { + return ( +
+
+ + Loading +
+
+ ) +} + +const rowStart = 1 +export const PIXEL_PER_CHAR = 7 + +export function getValueOfCell( + value: string | null, + isFocused: boolean, + maxPx: number +): string | null { + if (value === null) { + return null + } + + if (isFocused) { + return value + } + + // lets assume 7px per character + const maxStrWidth = maxPx / PIXEL_PER_CHAR + + if (value.length <= maxStrWidth) { + return value + } + + return value.substring(0, maxStrWidth) + '...' +} + +interface SelectedCell { + row: number, + column: number +} + +function CodeResults(props: ResultsProps) { + const [selectedCell, setSelectedCell] = useState({ row: 1, column: 0 }); + const response = props.results?.response + const error = props.results?.error + const gridRef = useRef(null) + + const isNumeric = (columnType: string) => { + return columnType.startsWith('UInt') || columnType.startsWith('Int') || columnType.startsWith('Float') || columnType.startsWith('Decimal'); + } + + const isHyperlink = (value: string | null) => { + return value && value.startsWith('http'); + } + + const extreme = useMemo(() => { + if (!response) return {}; + let res: Record = {}; + for (let i = 0; i < response.meta.length; i++) { + const columnType = response.meta[i].type; + const columnName = response.meta[i].name; + if (isNumeric(columnType)) { + const values = response.data.map(item => item[columnName]); + const max = Math.max(...values); + const min = Math.min(...values); + res[columnName] = { max, min }; + } + } + return res; + }, [response]); + + + const cellValue = useCallback( + (rowIndex: number, columnIndex: number): string | null => { + const columnName = response?.meta?.[columnIndex]?.name + const cellData = columnName + ? response?.data?.[rowIndex - 1]?.[columnName] + : '' + if (cellData === null || cellData === undefined) { + return null + } + + return typeof cellData === 'object' + ? JSON.stringify(cellData) + : cellData.toString() + }, + [response?.data, response?.meta] + ) + + const onCellClick = (e: any) => { + e.stopPropagation() + if (e.detail > 1) { + const cell = (e.target as HTMLElement).closest( + '[data-grid-row][data-grid-column]' + ) + if (cell && cell.dataset.gridRow && cell.dataset.gridColumn) { + const value = cellValue( + Number(cell.dataset.gridRow), + Number(cell.dataset.gridColumn) + ) + isHyperlink(value) && window.open(value || '', '_blank') + // props.handleCellClick(value) + } + } + } + + const Cell: CellProps = ({ + type, + rowIndex, + columnIndex, + isScrolling, + width, + ...props + }) => { + const columnType = response?.meta?.[columnIndex]?.type || '' + const columnName = response?.meta?.[columnIndex]?.name || '' + if (type === 'header-cell') { + return ( + + + + {response?.meta?.at(columnIndex)?.name} + + + + {response?.meta?.at(columnIndex)?.name} -{' '} + {response?.meta?.at(columnIndex)?.type} + + + ) + } + + const textAlign = columnType && isNumeric(columnType) ? "right" : "left"; + const value = cellValue(rowIndex, columnIndex); + + if (isNumeric(columnType) && response && response.data.length > 1) { + const ratio = value ? 100 * Number(value) / Number(extreme[columnName].max) : 100; + const bgColor = rowIndex === selectedCell.row? "lch(15.8 0 0)" : "#1f201b"; + const background = `linear-gradient(to right, #35372f 0%, #35372f ${ratio}%, ${bgColor} ${ratio}%, ${bgColor} 100%)` + return ( + {getValueOfCell(cellValue(rowIndex, columnIndex), false, width)} + ) + } else if (isHyperlink(value)) { + return ( + + {getValueOfCell(cellValue(rowIndex, columnIndex), false, width)} + + ) + } else { + return ( + + {getValueOfCell(cellValue(rowIndex, columnIndex), false, width)} + + ) + } + } + + const getMenuOptions = (selection: SelectedRegion, focus: SelectionFocus) => { + return [ + { + label: 'Copy to TSV', + onSelect: () => { + onCopyTSV(selection, focus) + } + } + ] + } + + const onCopyTSV = (selection: SelectedRegion, focus: SelectionFocus) => { + try { + copyGridElements({ + cell: Cell, + selection: selection, + focus: focus, + rowCount: response ? response.rows : 0, + columnCount: response?.meta?.length ?? 0, + outerRef: gridRef, + columnNames: response?.meta ? response.meta : [], + type: 'tsv' + }) + + createToast({ + title: 'Copied TSV successfully', + description: 'Now you can paste the content', + type: 'success' + }) + } catch (e) { + console.error(e) + + createToast({ + title: 'Failed to copy', + description: + 'Encountered an error while copying. Try again after sometime', + type: 'danger' + }) + } + } + + const onGridCopyMarkdown = ( + selection: SelectedRegion, + focus: SelectionFocus + ) => { + try { + copyGridElements({ + cell: Cell, + selection: selection, + focus: focus, + rowCount: response ? response.rows : 0, + columnCount: response?.meta?.length ?? 0, + outerRef: gridRef, + columnNames: response?.meta ? response.meta : [], + type: 'markdown' + }) + + createToast({ + title: 'Copied markdown successfully', + description: 'Now you can paste the content', + type: 'success' + }) + } catch (e) { + console.error(e) + + createToast({ + title: 'Failed to copy', + description: + 'Encountered an error while copying. Try again after sometime', + type: 'danger' + }) + } + } + + if (props.queryRunning) { + return ( +
+ +
+ ) + } + + let results = null + if (props.view == DefaultView.Chart && props.chart) { + results = + } else if (props.view == DefaultView.Table) { + results = response && response.rows > 0 && ( + <> + {}} + onCopy={onGridCopyMarkdown} + getMenuOptions={getMenuOptions} + className='scrollbar scrollbar-thin scrollbar-thumb-neutral-700 scrollbar-track-neutral-725'> + + ) + } + const height_table = props.chart + ? 300 + : Math.min(Math.ceil(((response?.rows || 0) + 1) * 33), 300) + + return ( + <> + {error ? ( +
+ +

+ An error occurred while processing your request. Please check the + browser console for more details. +

+
+ ) : ( +
+ {results} +
+ )} + + ) +} + +export default CodeResults diff --git a/src/components/CodeViewer/charts/bar/index.tsx b/src/components/CodeViewer/charts/bar/index.tsx new file mode 100644 index 00000000000..0bb0a6c0c0b --- /dev/null +++ b/src/components/CodeViewer/charts/bar/index.tsx @@ -0,0 +1,271 @@ +'use client' +import ReactECharts, { EChartsOption } from 'echarts-for-react' +import type { XAXisOption, YAXisOption } from 'echarts/types/dist/shared' +import isEqual from 'lodash/isEqual' +import { useEffect, useMemo, useState } from 'react' +import { ChartConfig, Column } from '../../types' +import { nonNullType, roundToDynamicPrecision } from '../../utils' + +const MAX_SERIES = 9 + +function getSupportedColumns(columns: Column[]): { + xaxis: string[] + yaxis: string[] + series: string[] +} { + return { + xaxis: columns + .filter( + (col) => + nonNullType(col.type).startsWith('Date') || + nonNullType(col.type).includes('String') || + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') || + nonNullType(col.type).startsWith("Enum") || + nonNullType(col.type).startsWith("LowCardinality") + ) + .map((col) => col.name), + yaxis: columns + .filter( + (col) => + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') || + nonNullType(col.type).startsWith('Decimal') || + nonNullType(col.type).startsWith('Float') + ) + .map((col) => col.name), + series: columns + .filter((col) => + nonNullType(col.type).includes("String") || + nonNullType(col.type).startsWith("Enum") || + nonNullType(col.type).startsWith("LowCardinality") + ) + .map((col) => col.name) + } +} + +export default function Bar(props: { + data: Record[] + config: ChartConfig + horizontal?: boolean + columns: Column[] +}) { + const columns = getSupportedColumns(props.columns) + const xaxis = + props.config.xaxis && columns.xaxis.includes(props.config.xaxis) + ? props.config.xaxis + : undefined + const yaxis = + props.config.yaxis && columns.yaxis.includes(props.config.yaxis) + ? props.config.yaxis + : undefined + const series_col = + props.config.series && columns.series.includes(props.config.series) + ? props.config.series + : undefined + + // Declare hooks at the top level unconditionally + const [windowWidth, setWindowWidth] = useState(window.innerWidth) + + useEffect(() => { + const handleResize = () => setWindowWidth(window.innerWidth) + window.addEventListener('resize', handleResize) + return () => window.removeEventListener('resize', handleResize) + }, []) + + const xAxis = useMemo(() => { + if (xaxis === undefined || yaxis === undefined) { + return [] + } + return Array.from(new Set(props.data.map((p) => p[xaxis!]))) + }, [props.data, props.config]) + + const values = useMemo(() => { + if (xaxis === undefined || yaxis === undefined) { + return {} + } + let series_count = 0 + const initialValues = props.data.reduce( + (accumulator, val) => { + const seriesName = + series_col && series_col in val ? val[series_col] : 'all' + if (!(seriesName in accumulator)) { + if (series_count < MAX_SERIES) { + accumulator[seriesName] = { + name: seriesName, + data: new Array(xAxis.length).fill(0) + } + } else { + accumulator['_other_'] = { + name: '_other_', + data: new Array(xAxis.length).fill(0) + } + } + series_count++ + } + return accumulator + }, + {} as Record + ) + + props.data.forEach((p) => { + const seriesName = series_col && series_col in p ? p[series_col] : 'all' + if (seriesName in initialValues) { + initialValues[seriesName].data[xAxis.indexOf(p[xaxis!])] = p[yaxis!] + } else { + initialValues['_other_'].data[xAxis.indexOf(p[xaxis!])] = p[yaxis!] + } + }) + + return initialValues + }, [props.data, props.config, xAxis]) + + const colors = useMemo( + () => [ + '#faff69', + '#FC74FF', + '#66ff73', + '#6df8e1', + '#33e4ff', + '#6d9bf3', + '#cc66ff', + '#fb63d6', + '#fdcf33', + '#fd9050', + '#fd7575', + '#b3b6bd' + ], + [] + ) + + const series:any = useMemo(() => { + const mappedColors: { [key: string]: string } = {} + return Object.values(values).map((series, i) => { + let color = colors[i % colors.length] + if (series.name in mappedColors) { + color = mappedColors[series.name] + } else { + mappedColors[series.name] = color + } + return props.config.stack + ? { + type: 'bar', + name: series.name, + data: series.data, + color: color, + stack: 'series' + } + : { + type: 'bar', + name: series.name, + data: series.data, + color: color + } + }) + }, [values, props.config.stack, colors]) + + if (xaxis === undefined || yaxis === undefined) { + return <> + } + const categoryAxis = { + show: true, + type: 'category', + data: xAxis, + axisLabel: { + hideOverlap: true + } + } + + const numberAxis = { + splitLine: { + show: true, + lineStyle: { + color: '#808691', + opacity: 0.3 + } + }, + axisLabel: { + hideOverlap: true + } + } + + const longestLabelLength = props.horizontal + ? Math.max(...xAxis.map((label) => String(label).length), 0) + : 0 + const leftPadding = props.horizontal + ? Math.max(48, longestLabelLength * 7) // Estimate width based on character count + : 24 + + const bottomPadding = windowWidth >= 1536 && series.length > 1 ? '48px' : '12px' + const options: EChartsOption = { + title: { + text: props.config.title, + textStyle: { + width: '100%', + fontSize: 16, + color: '#808691', + fontWeight: 'normal' + }, + left: 'center' + }, + animation: false, + grid: { + left: '8px', + right: '8px', + bottom: bottomPadding, + top: '24px', + containLabel: true + }, + tooltip: { + trigger: 'item', + textStyle: { + color: '#FAFF69', + fontWeight: 'bold', + fontSize: 16, + lineHeight: 24 + }, + backgroundColor: '#181818', + borderWidth: 0, + valueFormatter: (value: any) => + roundToDynamicPrecision(value as number).toString() + }, + xAxis: props.horizontal + ? (numberAxis as XAXisOption) + : (categoryAxis as XAXisOption), + legend: + windowWidth >= 1536 && series_col + ? { + bottom: '0%', + right: '0px', + orient: 'horizontal', + textStyle: { + color: '#FFFFFFF', + fontSize: 14 + }, + icon: 'circle', + borderRadius: 5, + borderWidth: 1, + borderColor: '#626262', + padding: 10 + } + : undefined, + yAxis: props.horizontal + ? (categoryAxis as YAXisOption) + : (numberAxis as YAXisOption), + series: series + } + + return ( +
+ { + return !isEqual(prevProps.option, currentProps.option) + }} + /> +
+ ) +} diff --git a/src/components/CodeViewer/charts/candlestick/index.tsx b/src/components/CodeViewer/charts/candlestick/index.tsx new file mode 100644 index 00000000000..b64cf4ed632 --- /dev/null +++ b/src/components/CodeViewer/charts/candlestick/index.tsx @@ -0,0 +1,231 @@ +'use client' +import EChartsReact from 'echarts-for-react' +import isEqual from 'lodash/isEqual' +import { useMemo, useRef } from 'react' +import { Column, XAxisConfig, YAxisConfig } from '../../types' +import { nonNullType, roundByScale, roundToDynamicPrecision } from '../../utils' +/* + +example query to generate data: + +SELECT + toDateTime('2024-01-01 00:00:00') + INTERVAL number WEEK AS timestamp, any(close) OVER (ORDER BY timestamp ASC ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS open, + round(randNormal(1000, 100), 2) AS close, + min2 (open, close) - round(randNormal(0, 10), 2) AS low, + max2 (open, close) + round(randNormal(0, 10), 2) AS high +FROM + numbers(0, 52) +ORDER BY + timestamp; +*/ + +function getSupportedColumns(columns: Column[]): { + xaxis: string[] + open: string[] + close: string[] + high: string[] + low: string[] +} { + return { + xaxis: columns + .filter( + (col) => + nonNullType(col.type).startsWith('Date') || + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') + ) + .map((col) => col.name), + open: columns + .filter( + (col) => + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') || + nonNullType(col.type).startsWith('Decimal') || + nonNullType(col.type).startsWith('Float') + ) + .map((col) => col.name), + close: columns + .filter( + (col) => + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') || + nonNullType(col.type).startsWith('Decimal') || + nonNullType(col.type).startsWith('Float') + ) + .map((col) => col.name), + low: columns + .filter( + (col) => + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') || + nonNullType(col.type).startsWith('Decimal') || + nonNullType(col.type).startsWith('Float') + ) + .map((col) => col.name), + high: columns + .filter( + (col) => + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') || + nonNullType(col.type).startsWith('Decimal') || + nonNullType(col.type).startsWith('Float') + ) + .map((col) => col.name) + } +} + +export type CandleStickChartConfig = XAxisConfig & + YAxisConfig & { + title?: string + high?: string + low?: string + open?: string + close?: string + } + +const CandleStickChart = (props: { + data: Record[] + config: CandleStickChartConfig + columns: Column[] +}) => { + const columns = getSupportedColumns(props.columns) + const xaxis = + props.config.xaxis && columns.xaxis.includes(props.config.xaxis) + ? props.config.xaxis + : undefined + const high = + props.config.high && columns.high.includes(props.config.high) + ? props.config.high + : undefined + const low = + props.config.low && columns.low.includes(props.config.low) + ? props.config.low + : undefined + const open = + props.config.open && columns.high.includes(props.config.open) + ? props.config.open + : undefined + const close = + props.config.close && columns.close.includes(props.config.close) + ? props.config.close + : undefined + + const chartRef = useRef(null) + const xAxis = useMemo(() => { + if ( + xaxis === undefined || + high === undefined || + low === undefined || + open === undefined || + close === undefined + ) { + return [] + } + return Array.from(new Set(props.data.map((p) => p[xaxis!]))) + }, [props.data, xaxis, high, low, open, close]) + + const values = useMemo(() => { + if ( + xaxis === undefined || + high === undefined || + low === undefined || + open === undefined || + close === undefined + ) { + return [] + } + const initialValues = props.data.map((p) => [ + p[open], + p[close], + p[low], + p[high] + ]) + return initialValues + }, [props.data, props.config]) + + const options:any = { + title: { + text: props.config.title, + textStyle: { + width: '100%', + fontSize: 16, + color: '#808691', + fontWeight: 'normal' + }, + left: 'center' + }, + animation: false, + grid: { + left: '36px', + right: '16x', + bottom: '24px', + top: '24px' + }, + xAxis: { + show: true, + type: 'category', + data: xAxis, + nameLocation: 'middle', + min: 0, + max: xAxis.length - 1 + }, + yAxis: { + type: 'value', + splitLine: { + show: true, + lineStyle: { + color: '#808691', + opacity: 0.3 + } + }, + min: (value: { min: number; max: number }) => { + return props.config.yaxis_min !== undefined + ? props.config.yaxis_min + : roundByScale(value.min * 0.9) + }, + max: props.config.yaxis_max ? props.config.yaxis_max : undefined + }, + series: { + type: 'candlestick', + data: values, + itemStyle: { + color: '#99FFA1', + borderColor: '#99FFA1', + color0: '#FF7575', + borderColor0: '#FF7575' + } + }, + tooltip: { + backgroundColor: '#302e32', + borderColor: '#302e32 transparent transparent transparent', + textStyle: { + color: '#FAFF69', + fontWeight: 'bold', + fontSize: 16, + lineHeight: 24 + }, + trigger: 'axis', + axisPointer: { + axis: 'x' + }, + valueFormatter: (value: number) => roundToDynamicPrecision(value) + } + } + + return ( +
+ { + return !isEqual(prevProps, currentProps) + }} + /> +
+ ) +} + +export default CandleStickChart diff --git a/src/components/CodeViewer/charts/heatmap/index.tsx b/src/components/CodeViewer/charts/heatmap/index.tsx new file mode 100644 index 00000000000..48654671382 --- /dev/null +++ b/src/components/CodeViewer/charts/heatmap/index.tsx @@ -0,0 +1,260 @@ +'use client' +import { + default as EChartsReact, + default as ReactECharts +} from 'echarts-for-react' +import isEqual from 'lodash/isEqual' +import { useMemo, useRef } from 'react' +import { ChartConfig, Column } from '../../types' +import { nonNullType } from '../../utils' +import styles from './styles.module.css' + +const MAX_SERIES = 9 + +export type HeatmapChartConfig = ChartConfig & { + zaxis?: string +} + +function getSupportedColumns(columns: Column[]): { + xaxis: string[] + yaxis: string[] + zaxis: string[] +} { + return { + xaxis: columns + .filter( + (col) => + nonNullType(col.type).includes('String') || + nonNullType(col.type).startsWith("Enum") || + nonNullType(col.type).startsWith("LowCardinality") || + nonNullType(col.type).includes('Date') + ) + .map((col) => col.name), + yaxis: columns + .filter( + (col) => + nonNullType(col.type).includes('String') || + nonNullType(col.type).startsWith("Enum") || + nonNullType(col.type).startsWith("LowCardinality") || + nonNullType(col.type).includes('Date') + ) + .map((col) => col.name), + zaxis: columns + .filter( + (col) => + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') || + nonNullType(col.type).startsWith('Decimal') || + nonNullType(col.type).startsWith('Float') + ) + .map((col) => col.name) + } +} + +export default function HeatMap(props: { + data: Record[] + config: HeatmapChartConfig + columns: Column[] +}) { + const columns = getSupportedColumns(props.columns) + const xaxis = + props.config.xaxis && columns.xaxis.includes(props.config.xaxis) + ? props.config.xaxis + : undefined + const yaxis = + props.config.yaxis && columns.yaxis.includes(props.config.yaxis) + ? props.config.yaxis + : undefined + const zaxis = + props.config.zaxis && columns.zaxis.includes(props.config.zaxis) + ? props.config.zaxis + : undefined + + const chartRef = useRef(null) + + const xValues = useMemo(() => { + if (xaxis === undefined || yaxis === undefined || zaxis === undefined) { + return [] + } + return props.data + .map((p) => p[xaxis!]) + .filter((item, pos, ary) => { + return !pos || item != ary[pos - 1] + }) + }, [props.data, props.config]) + + const yValues = useMemo(() => { + if (xaxis === undefined || yaxis === undefined || zaxis === undefined) { + return [] + } + return props.data + .map((p) => p[yaxis!]) + .sort() + .filter((item, pos, ary) => { + return !pos || item != ary[pos - 1] + }) + }, [props.data, props.config]) + + const values = useMemo(() => { + if (xaxis === undefined || yaxis === undefined || zaxis === undefined) { + return {} + } + return props.data.reduce( + (vals, val) => { + val[xaxis!] in vals + ? (vals[val[xaxis!]][val[yaxis!]] = Number(val[zaxis!])) + : (vals[val[xaxis!]] = { [val[yaxis!]]: Number(val[zaxis!]) }) + return vals + }, + {} as Record + ) + }, [props.data, props.config]) + + const longestYLabelLength = Math.max( + ...yValues.map((label) => String(label).length), + 0 + ) + const leftPadding = longestYLabelLength * 8 + + const options:any = { + title: { + text: props.config.title, + textStyle: { + width: '100%', + fontSize: 16, + color: '#808691', + fontWeight: 'normal' + }, + left: 'center' + }, + grid: { + left: `${leftPadding}px`, + right: '16px', + bottom: '36px', + top: '32px' + }, + xAxis: { + type: 'category', + offset: 15, + data: xValues, + splitArea: { + show: true + }, + axisLine: { + onZero: false + } + }, + toolBox: { + show: false + }, + yAxis: { + type: 'category', + offset: 15, + splitArea: { + show: true + }, + data: yValues, + axisLine: { + onZero: false + } + }, + tooltip: { + trigger: 'item', + textStyle: { + color: '#FAFF69', + fontWeight: 'bold', + fontSize: 16, + lineHeight: 24 + }, + backgroundColor: '#181818', + borderWidth: 0, + formatter: (params: any) => { + return `
${ + yValues[params.value[1]] + } - ${xValues[params.value[0]]} - ${Number( + params.value[2] + ).toLocaleString('en-US')} +
` + }, + position: (point: any, params: any, dom: any, rect: any, size: any) => { + const echartsInstance = chartRef.current?.getEchartsInstance() + if (echartsInstance) { + const pos = echartsInstance.convertToPixel({ seriesIndex: 0 }, [ + params.value[0], + params.value[1] + ]) + const xOffset = pos[0] - size.contentSize[1] * 2 + const yOffset = pos[1] - size.contentSize[1] - 10 + return [xOffset, yOffset] + } + return [point[0], point[1]] + }, + extraCssText: 'visibility: hidden;padding:0px;' + }, + visualMap: { + min: Math.min( + ...props.data.map((p) => + props.config.zaxis ? p[props.config.zaxis] : 0 + ) + ), + max: Math.max( + ...props.data.map((p) => + props.config.zaxis ? p[props.config.zaxis] : 0 + ) + ), + calculable: true, + orient: 'horizontal', + color: [ + 'rgba(252, 255, 116, 1)', + 'rgba(252, 255, 116, 0.9)', + 'rgba(252, 255, 116, 0.8)', + 'rgba(252, 255, 116, 0.7)', + 'rgba(252, 255, 116, 0.6)', + 'rgba(252, 255, 116, 0.5)', + 'rgba(252, 255, 116, 0.4)', + 'rgba(252, 255, 116, 0.3)', + 'rgba(252, 255, 116, 0.2)', + 'rgba(252, 255, 116, 0.1)', + '#262626' + ], + show: false + }, + series: [ + { + type: 'heatmap', + data: xValues + .map((x, xi) => + yValues.map((y, yi) => [xi, yi, y in values[x] ? values[x][y] : 0]) + ) + .flat(), + label: { + show: false + }, + emphasis: { + itemStyle: { + color: '#FAFF69' // Color on emphasis for better visibility + } + }, + itemStyle: { + borderWidth: 1, + borderColor: '#262626' // Set a distinct border to see each cell + } + } + ], + legend: null + } + + return ( +
+ { + return !isEqual(prevProps, currentProps) + }} + /> +
+ ) +} diff --git a/src/components/CodeViewer/charts/heatmap/styles.module.css b/src/components/CodeViewer/charts/heatmap/styles.module.css new file mode 100644 index 00000000000..82aca2f9557 --- /dev/null +++ b/src/components/CodeViewer/charts/heatmap/styles.module.css @@ -0,0 +1,31 @@ +.tooltip { + position: relative; + visibility: visible; + display: inline-block; +} + +.tooltip .tooltiptext { + visibility: visible; + background-color: #302e32; + text-align: center; + border-radius: 6px; + padding: 5px; + position: absolute; + z-index: 1; + margin-left: -64px; + margin-top: -20px; + +} + +.tooltip .tooltiptext::after { + content: ""; + visibility: visible; + position: absolute; + background-color: transparent; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 10px; + border-style: solid; + border-color: #302e32 transparent transparent transparent; +} diff --git a/src/components/CodeViewer/charts/index.tsx b/src/components/CodeViewer/charts/index.tsx new file mode 100644 index 00000000000..c211adeddca --- /dev/null +++ b/src/components/CodeViewer/charts/index.tsx @@ -0,0 +1,122 @@ +import { Panel } from '@clickhouse/click-ui/bundled' +import { useEffect, useState } from 'react' +import { ChartConfig, ChartType, QueryResults } from '../types' +import BarChart from './bar' +import CandleStickChart from './candlestick' +import HeatMap from './heatmap' +import LineChart from './line' +import PieChart from './pie' + +const chartTypes = Object.values(ChartType) + +const Chart = (props: { + results?: QueryResults + chart: { type: ChartType; config?: ChartConfig } +}) => { + const [windowWidth, setWindowWidth] = useState(0) + + useEffect(() => { + const handleResize = () => setWindowWidth(window.innerWidth) + handleResize() + window.addEventListener('resize', handleResize) + return () => window.removeEventListener('resize', handleResize) + }, []) + + if (!props.results) { + return
+ } + + let chart = null + + if (props.chart.config) { + switch (props.chart.type) { + case ChartType.Line: + case ChartType.Area: + case ChartType.Scatter: { + chart = ( +
+ +
+ ) + break + } + case ChartType.HorizontalBar: + case ChartType.Bar: { + chart = ( +
+ +
+ ) + break + } + case ChartType.Pie: { + chart = ( +
+ +
+ ) + break + } + case ChartType.HeatMap: { + chart = ( +
+ +
+ ) + break + } + case ChartType.CandleStick: { + chart = ( +
+ +
+ ) + break + } + default: { + chart = null + } + } + } + + return ( +
+ + {chart} + +
+ ) +} + +export default Chart diff --git a/src/components/CodeViewer/charts/line/index.tsx b/src/components/CodeViewer/charts/line/index.tsx new file mode 100644 index 00000000000..75ada112771 --- /dev/null +++ b/src/components/CodeViewer/charts/line/index.tsx @@ -0,0 +1,357 @@ +'use client' +import EChartsReact from 'echarts-for-react' +import isEqual from 'lodash/isEqual' +import { useEffect, useMemo, useRef, useState } from 'react' +import { ChartConfig, Column } from '../../types' +import { nonNullType, roundByScale, roundToDynamicPrecision } from '../../utils' +import styles from './styles.module.css' + +const MAX_SERIES = 9 + +function getSupportedColumns(columns: Column[]): { + xaxis: string[] + yaxis: string[] + series: string[] +} { + return { + xaxis: columns + .filter( + (col) => + nonNullType(col.type).startsWith('Date') || + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') + ) + .map((col) => col.name), + yaxis: columns + .filter( + (col) => + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') || + nonNullType(col.type).startsWith('Decimal') || + nonNullType(col.type).startsWith('Float') + ) + .map((col) => col.name), + series: columns + .filter((col) => + nonNullType(col.type).includes("String") || + nonNullType(col.type).startsWith("Enum") || + nonNullType(col.type).startsWith("LowCardinality") + ) + .map((col) => col.name) + } +} + +const LineChart = (props: { + data: Record[] + config: ChartConfig + scatter?: boolean + fill_area?: boolean + columns: Column[] +}) => { + const columns = getSupportedColumns(props.columns) + const xaxis = + props.config.xaxis && columns.xaxis.includes(props.config.xaxis) + ? props.config.xaxis + : undefined + const yaxis = + props.config.yaxis && columns.yaxis.includes(props.config.yaxis) + ? props.config.yaxis + : undefined + const series_col = + props.config.series && columns.series.includes(props.config.series) + ? props.config.series + : undefined + + const chartRef = useRef(null) + const [windowWidth, setWindowWidth] = useState(window.innerWidth) + + useEffect(() => { + const handleResize = () => setWindowWidth(window.innerWidth) + window.addEventListener('resize', handleResize) + return () => window.removeEventListener('resize', handleResize) + }, []) + + const xAxis = useMemo(() => { + if (xaxis === undefined || yaxis === undefined) { + return [] + } + return Array.from(new Set(props.data.map((p) => p[xaxis!]))) + }, [props.data, xaxis, yaxis]) + + const values = useMemo(() => { + if (xaxis === undefined || yaxis === undefined) { + return {} + } + let series_count = 0 + const initialValues = props.data.reduce( + (accumulator, val) => { + const seriesName = + series_col && series_col in val ? val[series_col] : 'all' + if (!(seriesName in accumulator)) { + if (series_count < MAX_SERIES) { + accumulator[seriesName] = { + name: seriesName, + data: new Array(xAxis.length).fill(0) + } + } else { + accumulator['_other_'] = { + name: '_other_', + data: new Array(xAxis.length).fill(0) + } + } + series_count++ + } + return accumulator + }, + {} as Record + ) + + props.data.forEach((p) => { + const seriesName = series_col && series_col in p ? p[series_col] : 'all' + if (seriesName in initialValues) { + initialValues[seriesName].data[xAxis.indexOf(p[xaxis!])] = p[yaxis!] + } else { + initialValues['_other_'].data[xAxis.indexOf(p[xaxis!])] = p[yaxis!] + } + }) + return initialValues + }, [props.data, props.config]) + + const colors = useMemo( + () => [ + '#faff69', + '#FC74FF', + '#66ff73', + '#6df8e1', + '#33e4ff', + '#6d9bf3', + '#cc66ff', + '#fb63d6', + '#fdcf33', + '#fd9050', + '#fd7575', + '#b3b6bd' + ], + [] + ) + + const series = useMemo(() => { + const mappedColors: { [key: string]: string } = {} + + return Object.values(values).map((series, i) => { + let color = colors[i % colors.length] + if (series.name in mappedColors) { + color = mappedColors[series.name] + } else { + mappedColors[series.name] = color + } + return { + name: series.name, + data: series.data, + type: props.scatter ? 'scatter' : 'line', + smooth: true, + showSymbol: props.scatter ? true : false, + symbolSize: 6, + areaStyle: props.fill_area ? {} : null, + lineStyle: { + color: color, + width: 1.5 + }, + itemStyle: { + color: color + } + } + }) + }, [values, props.config, colors, props.fill_area, props.scatter]) + + if (xaxis === undefined || yaxis === undefined) { + return <> + } + + const onMouseOver = () => { + const echartsInstance = chartRef.current?.getEchartsInstance() + if ( + echartsInstance && + !props.fill_area && + !props.scatter && + series.length === 1 + ) { + const newOptions = { + series: [ + { + lineStyle: { + opacity: 1, + shadowColor: '#FAFF69', + shadowOffsetX: 0, + shadowOffsetY: 0, + shadowBlur: 0 + }, + areaStyle: { + color: { + type: 'linear', + x: 0, + y: 0, + x2: 0, + y2: 0.65, + colorStops: [ + { + offset: 0, + color: '#FAFF69' + }, + { + offset: 1, + color: '#343431' + } + ] + }, + opacity: 0.1 + } + } + ] + } + echartsInstance.setOption(newOptions) + echartsInstance.dispatchAction({ + type: 'takeGlobalCursor', + key: 'brush', + brushOption: { + brushType: 'lineX' + } + }) + } + } + + const bottomPadding = windowWidth >= 1536 && series.length > 1 ? '48px' : '12px' + + const options: any = { + animation: false, + title: { + text: props.config.title, + textStyle: { + width: '100%', + fontSize: 16, + color: '#808691', + fontWeight: 'normal' + }, + left: 'center' + }, + grid: { + left: '8px', + right: '8px', + bottom: bottomPadding, + top: '36px', + containLabel: true + }, + xAxis: { + show: true, + type: 'category', + boundaryGap: false, + data: xAxis, + nameLocation: 'middle', + min: 0, + max: xAxis.length - 1, + axisLabel: { + hideOverlap: true + } + }, + yAxis: { + type: 'value', + splitLine: { + show: true, + lineStyle: { + color: '#808691', + opacity: 0.3 + } + }, + min: (value: { min: number; max: number }) => { + return props.config.yaxis_min !== undefined + ? props.config.yaxis_min + : roundByScale(value.min * 0.9) + }, + max: props.config.yaxis_max ? props.config.yaxis_max : undefined + }, + series: series, + legend: + windowWidth >= 1536 && series_col + ? { + bottom: '0%', + right: '0px', + orient: 'horizontal', + textStyle: { + color: '#FFFFFFF', + fontSize: 14 + }, + icon: 'circle', + borderRadius: 5, + borderWidth: 1, + borderColor: '#626262', + padding: 10 + } + : null, + tooltip: { + trigger: 'axis', + textStyle: { + color: '#FAFF69', + fontWeight: 'bold', + fontSize: 16, + lineHeight: 16 + }, + backgroundColor: '#302e32', + borderWidth: 0, + valueFormatter: (value: number) => roundToDynamicPrecision(value), + ...(series.length === 1 && { + // Only include these properties if series length is equal to 1 + formatter: (params: any) => { + return `
+ ${params[0].axisValue}: ${roundToDynamicPrecision( + params[0].value + ).toLocaleString('en-US')} +
` + }, + extraCssText: 'visibility: hidden;padding:0px;', + position: (point: any, params: any, dom: any, rect: any, size: any) => { + const echartsInstance = chartRef.current?.getEchartsInstance() + if (echartsInstance) { + const pos = echartsInstance.convertToPixel({ seriesIndex: 0 }, [ + params[0].axisValue, + params[0].value + ]) + return [pos[0], pos[1] - size.contentSize[1] * 2] + } + } + }) + } + // brush: { + // toolbox: ["lineX", "clear"], + // brushType: "lineX", + // brushMode: "single", + // transformable: false + // } + } + + const onMouseOut = () => { + const echartsInstance = chartRef.current?.getEchartsInstance() + if (echartsInstance) { + echartsInstance.setOption(options) + } + } + + return ( +
+ { + return !isEqual(prevProps, currentProps) + }} + /> +
+ ) +} + +export default LineChart diff --git a/src/components/CodeViewer/charts/line/styles.module.css b/src/components/CodeViewer/charts/line/styles.module.css new file mode 100644 index 00000000000..5fdc3f546fa --- /dev/null +++ b/src/components/CodeViewer/charts/line/styles.module.css @@ -0,0 +1,37 @@ +.tooltip { + position: relative; + visibility: visible; + display: inline-block; +} + +.tooltip .tooltiptext { + visibility: visible; + background-color: #302e32; + text-align: center; + border-radius: 6px; + padding: 5px; + position: absolute; + z-index: 1; + margin-left: -64px; + margin-top: -20px; +} + +.tooltip .tooltiptext::after { + content: ''; + visibility: visible; + position: absolute; + background-color: transparent; + top: 100%; + left: 50%; + margin-left: -5px; + border-width: 10px; + border-style: solid; + border-color: #302e32 transparent transparent transparent; +} + +.line { + height: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; +} \ No newline at end of file diff --git a/src/components/CodeViewer/charts/pie/index.tsx b/src/components/CodeViewer/charts/pie/index.tsx new file mode 100644 index 00000000000..b76440d9958 --- /dev/null +++ b/src/components/CodeViewer/charts/pie/index.tsx @@ -0,0 +1,183 @@ +'use client' +import ReactECharts from 'echarts-for-react' +import { useEffect, useMemo, useState } from 'react' +import { ChartConfig, Column } from '../../types' +import { nonNullType, roundToDynamicPrecision } from '../../utils' + +const MAX_SERIES = 9 + +function getSupportedColumns(columns: Column[]): { + xaxis: string[] + yaxis: string[] +} { + return { + xaxis: columns + .filter((col) => nonNullType(col.type).includes("String") || + nonNullType(col.type).startsWith("Enum") || + nonNullType(col.type).startsWith("LowCardinality")) + .map((col) => col.name), + yaxis: columns + .filter( + (col) => + nonNullType(col.type).startsWith('UInt') || + nonNullType(col.type).startsWith('Int') || + nonNullType(col.type).startsWith('Decimal') || + nonNullType(col.type).startsWith('Float') + ) + .map((col) => col.name) + } +} + +export default function Pie(props: { + data: Record[] + config: ChartConfig + columns: Column[] +}) { + const columns = getSupportedColumns(props.columns) + // unset columns which aren't valid + const xaxis = + props.config.xaxis && columns.xaxis.includes(props.config.xaxis) + ? props.config.xaxis + : undefined + const yaxis = + props.config.yaxis && columns.yaxis.includes(props.config.yaxis) + ? props.config.yaxis + : undefined + // Declare hooks at the top level unconditionally + const [windowWidth, setWindowWidth] = useState(window.innerWidth) + useEffect(() => { + const handleResize = () => setWindowWidth(window.innerWidth) + window.addEventListener('resize', handleResize) + return () => window.removeEventListener('resize', handleResize) + }, []) + + const values = useMemo(() => { + if (xaxis === undefined || yaxis === undefined) { + return {} + } + let series_count = 0 + return props.data.reduce((accumulator, val) => { + const seriesName = xaxis! in val ? val[xaxis!] : 'all' + if (!(seriesName in accumulator)) { + if (series_count < MAX_SERIES) { + accumulator[seriesName] = Number(val[yaxis!]) + } else if ('_other_' in accumulator) { + accumulator['_other_'] = accumulator['_other_'] + Number(val[yaxis!]) + } else { + accumulator['_other_'] = Number(val[yaxis!]) + } + series_count++ + } else { + accumulator[seriesName] = accumulator[seriesName] + Number(val[yaxis!]) + } + return accumulator + }, {}) + }, [props.data, xaxis, yaxis]) + + const data = useMemo(() => { + return Object.entries(values).map(([seriesName, value]) => { + return { value: value, name: seriesName } + }) + }, [values]) + + if (xaxis === undefined || yaxis === undefined) { + return <> + } + + const options:any = { + title: { + text: props.config.title, + textStyle: { + width: '100%', + fontSize: 16, + color: '#808691', + fontWeight: 'normal' + }, + left: 'center' + }, + animation: false, + grid: { + left: '80px', + right: '24px', + bottom: '24px', + top: '24px' + }, + tooltip: { + trigger: 'item', + textStyle: { + color: '#FAFF69', + fontWeight: 'bold', + fontSize: 16, + lineHeight: 24 + }, + backgroundColor: '#181818', + borderWidth: 0, + valueFormatter: (value: number) => roundToDynamicPrecision(value) + }, + legend: + windowWidth >= 1536 + ? { + top: '0%', + right: '0px', + orient: 'vertical', + textStyle: { + color: '#FFFFFFF', + fontSize: 14 + }, + icon: 'circle', + borderRadius: 5, + borderWidth: 1, + borderColor: '#626262', + padding: 10 + } + : null, + series: [ + { + name: xaxis, + type: 'pie', + radius: ['50%', '90%'], + avoidLabelOverlap: true, + center: ['50%', '55%'], + label: { + show: false + }, + emphasis: { + label: { + show: false + } + }, + labelLine: { + show: true + }, + z: 2, + itemStyle: {}, + color: [ + '#faff69', + '#FC74FF', + '#66ff73', + '#6df8e1', + '#33e4ff', + '#6d9bf3', + '#cc66ff', + '#fb63d6', + '#fdcf33', + '#fd9050', + '#fd7575', + '#b3b6bd' + ], + data: data + } + ] + } + + return ( +
+ +
+ ) +} diff --git a/src/components/CodeViewer/copy/copyGridElements.tsx b/src/components/CodeViewer/copy/copyGridElements.tsx new file mode 100644 index 00000000000..1c366f27df0 --- /dev/null +++ b/src/components/CodeViewer/copy/copyGridElements.tsx @@ -0,0 +1,179 @@ +import { CellProps, SelectedRegion, SelectionFocus } from "@clickhouse/click-ui/bundled"; +import { RefObject, createElement } from "react"; +import { renderToStaticMarkup } from "react-dom/server"; +import { Column } from "../types"; + +interface CopyGridElementsProps { + cell: CellProps; + selection: SelectedRegion; + rowCount: number; + columnCount: number; + pageStart?: number; + focus: SelectionFocus; + outerRef: RefObject; + columnNames: Column[]; + type: String; +} + +function copyTableAsMarkdown(table: HTMLTableElement) { + // Extract header cells from the section if present + const headerCells = table.querySelector("thead") + ? Array.from(table.querySelectorAll("thead th")).map(cell => cell.textContent?.trim() ?? "") + : []; + + let markdownRows: string[] = []; + if (headerCells.length > 0) { + // Create the Markdown header row and separator + const headerRow = `| ${headerCells.join(" | ")} |`; + const separatorRow = `| ${headerCells.map(() => "---").join(" | ")} |`; + markdownRows.push(headerRow) + markdownRows.push(separatorRow) + } + + // Extract body rows, excluding the header row if no is used + const bodyRows = Array.from(table.querySelectorAll("tbody tr")).length + ? Array.from(table.querySelectorAll("tbody tr")) + : [] + + // Map each row to a Markdown formatted row + bodyRows.forEach(row => { + const rowCells: string[] = Array.from(row.querySelectorAll("td, th")).map(cell => cell.textContent?.trim() ?? ""); + markdownRows.push(`| ${rowCells.join(" | ")} |`); + }); + + // Combine the header, separator, and body rows into the final Markdown table + const markdownTable = [...markdownRows].join("\n"); + + // Copy to clipboard + navigator.clipboard.writeText(markdownTable); + +} + +const addCellToRow = ( + row: HTMLTableRowElement, + cell: CellProps, + rowIndex: number, + columnIndex: number +) => { + const td = document.createElement("td"); + // const root = createRoot(td); + const html = renderToStaticMarkup( + createElement(cell, { rowIndex, columnIndex, width: 1000, type: "row-cell" }) + ); + td.innerHTML = html; + + row.appendChild(td); + // root.unmount(); +}; + +const headerListLoop = ( + thead: HTMLTableSectionElement, + columnList: Array, + columnNames: Column[] +) => { + const row = document.createElement("tr"); + columnList.forEach(columnIndex => { + const th = document.createElement("th"); + th.innerHTML = columnNames?.[columnIndex].name; + row.appendChild(th); + }); + thead.appendChild(row); +}; + +const columnListLoop = ( + tbody: HTMLTableSectionElement, + columnList: Array, + cell: CellProps, + rowIndex: number +) => { + const row = document.createElement("tr"); + columnList.forEach(columnIndex => { + addCellToRow(row, cell, rowIndex, columnIndex); + }); + tbody.appendChild(row); +}; + +const copyGridElements = async ({ + cell, + selection, + rowCount, + columnCount, + pageStart = 0, + focus, + outerRef, + columnNames, + type +}: CopyGridElementsProps): Promise => { + if (!outerRef.current) { + throw "Could not fetch selection"; + } + + const table = document.createElement("table"); + table.style.position = "absolute"; + table.style.top = "-200px"; + table.style.left = "-200px"; + table.style.width = "0px"; + table.style.height = "0px"; + table.style.overflow = "hidden"; + const thead = document.createElement("thead"); + const tbody = document.createElement("tbody"); + + switch (selection.type) { + case "rectangle": + const columnListRectangle = Array.from( + { length: selection.bounds.right + 1 - selection.bounds.left }, + (_, index) => selection.bounds.left + index + ); + headerListLoop(thead, columnListRectangle, columnNames); + Array.from( + { length: selection.bounds.bottom + 1 - selection.bounds.top }, + (_, index) => selection.bounds.top + index + ).forEach(rowIndex => { + + columnListLoop(tbody, columnListRectangle, cell, rowIndex); + }); + break; + case "columns": + const columnList = Array.from(selection.columns).sort(); + headerListLoop(thead, columnList, columnNames); + Array.from({ length: rowCount }, (_, index) => pageStart + 1 + index).forEach( + rowIndex => { + columnListLoop(tbody, columnList, cell, rowIndex); + } + ); + break; + case "rows": + const columnListRows = Array.from( + { length: columnCount }, + (_, index) => pageStart + index + ); + headerListLoop(thead, columnListRows, columnNames); + Array.from(selection.rows).sort().forEach(rowIndex => { + columnListLoop(tbody, columnListRows, cell, rowIndex); + }); + break; + case "empty": + columnListLoop(tbody, [focus.column], cell, focus.row); + break; + default: + throw new Error("incorrect selection provided"); + } + + table.appendChild(thead); + table.appendChild(tbody); + + outerRef.current.appendChild(table); + + const windowSelection = window.getSelection(); + if (windowSelection) { + if (type === 'tsv') + await navigator.clipboard.writeText(table.innerText); + else + await copyTableAsMarkdown(table); + outerRef.current.removeChild(table); + } else { + throw "Could not fetch selection"; + } +}; + +export default copyGridElements; diff --git a/src/components/CodeViewer/index.tsx b/src/components/CodeViewer/index.tsx new file mode 100644 index 00000000000..04d4a88ec9f --- /dev/null +++ b/src/components/CodeViewer/index.tsx @@ -0,0 +1,88 @@ +import { CodeBlock, ClickUIProvider } from '@clickhouse/click-ui/bundled' +import CodeInterpreter from './CodeInterpreter' +import { DefaultView } from './CodeResults' +import { ChartConfig, ChartType } from './types' +import { base64Decode } from './utils' +import { useColorMode } from '@docusaurus/theme-common' +import { isValidElement } from 'react' + +function getCodeContent(children: any): string { + if (typeof children === 'string') return children + + if (isValidElement(children) && children.props?.children) { + return getCodeContent(children.props.children) + } + + if (Array.isArray(children)) { + return children.map(getCodeContent).join('') + } + + return '' +} + +function CodeViewer({ + node, + inline, + className, + language = 'sql', + show_line_numbers = 'false', + runnable = false, + run = false, + link, + view = 'table', + chart_config = '', + clickhouse_settings = '{}', + show_statistics = true, + children, + ...props +}: any) { + const showLineNumbers = show_line_numbers === 'true' + const runBoolean = run === 'true' + const runnableBoolean = runnable === 'true' + let chart: { type: ChartType; config?: ChartConfig } | undefined + try { + const parsedChart = JSON.parse(base64Decode(chart_config)) + if (parsedChart && parsedChart.type && parsedChart.config) { + chart = { + type: parsedChart.type as ChartType, + config: parsedChart.config + } + } + } catch { + console.log('chart config is not valid') + } + const { colorMode } = useColorMode(); // returns 'light' or 'dark' + console.log(children.props.children) + return ( +
+ + + + {typeof children === 'string' ? children : getCodeContent(children)} + + + + +
+ + + ) +} + +export default CodeViewer diff --git a/src/components/CodeViewer/types.tsx b/src/components/CodeViewer/types.tsx new file mode 100644 index 00000000000..af86dda1904 --- /dev/null +++ b/src/components/CodeViewer/types.tsx @@ -0,0 +1,87 @@ +export interface QueryResponse { + query?: string + status: number + query_id?: string + error?: any + response?: QueryResults + warning?: string | undefined +} + +export interface QueryResults { + meta: Column[] + data: Record[] + rows: number + exception?: string + statistics: QueryStatistics +} + +export interface QueryStatistics { + elapsed: number + rows_read: number + bytes_read: number +} + +export interface Column { + database?: string + table?: string + name: string + type: string +} + +export interface QueryParameter { + name: string + type?: string + textStartPos?: number + textEndPos?: number + value: string +} + +export enum ChartType { + Line = 'line', + Bar = 'bar', + HorizontalBar = 'horizontal bar', + Area = 'area', + Pie = 'pie', + Scatter = 'scatter', + HeatMap = 'heatmap', + CandleStick = 'candlestick' +} + +export interface YAxisConfig { + yaxis?: string + yaxis_min?: number + yaxis_max?: number +} + +export interface XAxisConfig { + xaxis?: string +} + +export interface SeriesConfig { + series?: string +} + +export interface StackableConfig { + stack?: boolean +} + +export type ChartConfig = StackableConfig & + SeriesConfig & + YAxisConfig & + XAxisConfig & { + title?: string + } + +export interface QueryResults { + meta: Column[] + data: Record[] + rows: number + exception?: string + statistics: QueryStatistics +} + +export interface QueryStatistics { + elapsed: number + rows_read: number + bytes_read: number +} diff --git a/src/components/CodeViewer/utils.ts b/src/components/CodeViewer/utils.ts new file mode 100644 index 00000000000..f8b72b2258b --- /dev/null +++ b/src/components/CodeViewer/utils.ts @@ -0,0 +1,58 @@ +import { filesize } from 'filesize' +import numeral from 'numeral' // @ts-ignore + +export function roundToDynamicPrecision(num: number) { + const validNum = Number(num) + if (isNaN(validNum)) return 0 + if (validNum === 0) return 0 + + const absNum = Math.abs(validNum) + const scale = Math.floor(Math.log10(absNum)) + + const numDecimals = (validNum.toString().split('.')[1] || '').length + + const basePrecision = scale >= 1 ? 0 : Math.max(0, -scale + 1) + const finalPrecision = Math.min( + 3, + Math.round((basePrecision + numDecimals) / 2) + ) + return Number(validNum.toFixed(finalPrecision)) +} + +export function nonNullType(type: string) { + type = type.trim() + if (type.startsWith('Nullable(')) { + return type.slice(9, -1) + } + return type +} + +export function roundByScale(num: number) { + const absNum = Math.abs(num) // incase - + const scale = absNum === 0 ? 0 : Math.floor(Math.log10(absNum)) // ensures we round to a value appropriate for scale + const precision = Math.max(0, -scale) + return Number(num.toFixed(precision)) +} + +export function base64Decode(base64: string): string { + // Convert URL-safe base64 back to regular base64 + const base64String = base64.replace(/-/g, '+').replace(/_/g, '/') + // Add padding if necessary + const paddedBase64String = base64String.padEnd( + base64String.length + ((4 - (base64String.length % 4)) % 4), + '=' + ) + const binaryString = atob(paddedBase64String) + const utf8Bytes = Uint8Array.from(binaryString, (char) => char.charCodeAt(0)) + const decodedText = new TextDecoder().decode(utf8Bytes) + return decodedText +} + +export function formatReadableRows(rows: number): string { + if (rows < 1000) return rows.toString() // Return as is if less than 1,000 + return numeral(rows).format('0.[0]a') // Converts to K, M, B with one decimal if needed +} + +export function formatBytes(bytes: number): string { + return filesize(bytes, { base: 2, standard: 'jedec', spacer: '' }) +} diff --git a/src/css/custom.scss b/src/css/custom.scss index 8990e7f408c..f0ea947426d 100644 --- a/src/css/custom.scss +++ b/src/css/custom.scss @@ -2,6 +2,10 @@ @use "default"; @use "home"; +@tailwind base; +@tailwind components; +@tailwind utilities; + /* KaTeX renders the input twice by default, once in HTML and one in MathML */ .katex-html { display: none; @@ -225,8 +229,7 @@ html { } code { - font-weight: bold; - background-color: var(--ifm-code-background) !important; + background-color: var(--ifm-code-background); scrollbar-width: thin; scrollbar-color: rgb(99, 99, 99) rgb(41, 45, 62); span { diff --git a/src/theme/CodeBlock/index.js b/src/theme/CodeBlock/index.js index 69ec342e731..dcfed629d68 100644 --- a/src/theme/CodeBlock/index.js +++ b/src/theme/CodeBlock/index.js @@ -46,10 +46,10 @@ export default function CodeBlockWrapper(props) { ); } - + console.log(props) return ( - <> - - + <> + + ); } diff --git a/static/images/loading.svg b/static/images/loading.svg new file mode 100644 index 00000000000..13f6cad7bac --- /dev/null +++ b/static/images/loading.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 00000000000..3621c02815d --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,406 @@ +module.exports = { + darkMode: 'class', + plugins: [ + require('@tailwindcss/typography') + ], + content: [ + './src/**/*.{js,ts,jsx,tsx}', + ], + safelist: ['py-[6px]', 'py-[1px]'], + theme: { + screens: { + print: { + raw: 'print' + }, + sm: '640px', + 'sm-mid': '704px', + md: '768px', + 'md-mid': '896px', + lg: '1024px', + 'lg-mid': '1152px', + xl: '1280px', + 'xl-mid': '1408px', + '2xl': '1536px', + '3xl': '2200px' + }, + extend: { + typography: ({ theme }) => ({ + neutral: { + css: { + '--tw-prose-body': theme('colors.neutral[200]'), + '--tw-prose-headings': theme('colors.neutral[100]'), + '--tw-prose-lead': theme('colors.neutral[700]'), + '--tw-prose-links': theme('colors.primary[300]'), + '--tw-prose-bold': theme('colors.neutral[200]'), + '--tw-prose-counters': theme('colors.neutral[200]'), + '--tw-prose-bullets': theme('colors.neutral[200]'), + '--tw-prose-hr': theme('colors.neutral[300]'), + '--tw-prose-quotes': theme('colors.neutral[900]'), + '--tw-prose-quote-borders': theme('colors.neutral[300]'), + '--tw-prose-captions': theme('colors.neutral[700]'), + '--tw-prose-code': theme('colors.neutral[900]'), + '--tw-prose-pre-code': theme('colors.neutral[100]'), + '--tw-prose-pre-bg': theme('colors.neutral[900]'), + '--tw-prose-th-borders': theme('colors.neutral[300]'), + '--tw-prose-td-borders': theme('colors.neutral[200]'), + '--tw-prose-invert-body': theme('colors.neutral[200]'), + '--tw-prose-invert-headings': theme('colors.white'), + '--tw-prose-invert-lead': theme('colors.neutral[300]'), + '--tw-prose-invert-links': theme('colors.white'), + '--tw-prose-invert-bold': theme('colors.white'), + '--tw-prose-invert-counters': theme('colors.neutral[400]'), + '--tw-prose-invert-bullets': theme('colors.neutral[600]'), + '--tw-prose-invert-hr': theme('colors.neutral[700]'), + '--tw-prose-invert-quotes': theme('colors.neutral[100]'), + '--tw-prose-invert-quote-borders': theme('colors.neutral[700]'), + '--tw-prose-invert-captions': theme('colors.neutral[400]'), + '--tw-prose-invert-code': theme('colors.white'), + '--tw-prose-invert-pre-code': theme('colors.neutral[300]'), + '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)', + '--tw-prose-invert-th-borders': theme('colors.neutral[600]'), + '--tw-prose-invert-td-borders': theme('colors.neutral[700]') + } + } + }), + fontSize: { + '2.75xl': '1.75rem', + '5.5xl': '3.5rem', + '5.5xl': '3.5rem', + '6.5xl': '4rem', + '7.5xl': '5.25rem' + }, + fontFamily: { + inter: 'var(--font-inter), sans-serif', + inconsolata: 'var(--font-inconsolata)', + basier: 'Basier Square, Arial, Helvetica, sans-serif' + }, + colors: { + rangitoto: '#28281D', + 'base-color': '#FBFF46', + 'eerie-black': '#1A1918', + jet: '#343434', + + // Generated from: + // @link https://www.tailwindshades.com/#color=64.70588235294119%2C100%2C50&step-up=8&step-down=11&hue-shift=0&name=ch-yellow&base-stop=5&v=1&overrides=e30%3D + 'ch-yellow': { + DEFAULT: '#EBFF00', + 50: '#F9FFB8', + 100: '#F8FFA3', + 200: '#F5FF7A', + 300: '#F1FF52', + 400: '#EEFF29', + 500: '#EBFF00', + 600: '#B7C700', + 700: '#848F00', + 800: '#505700', + 900: '#1C1F00', + 950: '#020300' + }, + + // Generated from: + // @link https://www.tailwindshades.com/#color=167.21311475409837%2C100%2C11.96078431372549&step-up=7&step-down=3&hue-shift=0&name=ch-teal&base-stop=6&v=1&overrides=e30%3D + 'ch-teal': { + DEFAULT: '#003D30', + 50: '#02FFC9', + 100: '#00F0BC', + 200: '#00CCA0', + 300: '#00A884', + 400: '#008468', + 500: '#00614C', + 600: '#003D30', + 700: '#002E24', + 800: '#001E18', + 900: '#000F0C', + 950: '#000706' + }, + primary: { + DEFAULT: '#FBFF46', + 50: '#FFFFE8', + 100: '#FEFFBA', + 200: '#FDFFA3', + 300: '#FAFF69', + 400: '#EEF400', + 500: '#9FA300', + 600: '#4F5100', + 700: '#282900', + 800: '#1F2014', + 900: '#161600' + }, + neutral: { + DEFAULT: '#212121', + 0: '#FFFFFF', + 100: '#F9F9F9', + 200: '#dfdfdf', + 300: '#c0c0c0', + 400: '#a0a0a0', + 500: '#808080', + 600: '#606060', + 700: '#414141', + 725: '#282828', + 750: '#1F1F1C', + 800: '#1d1d1d', + 900: '#151515' + }, + slate: { + DEFAULT: '#373439', + 50: '#F6F7FA', + 100: '#e6e7e9', + 200: '#cccfd3', + 300: '#b3b6bd', + 400: '#9a9ea7', + 500: '#808691', + 600: '#696e79', + 700: '#53575f', + 800: '#302e32', + 900: '#161517' + }, + indigo: { + DEFAULT: '#2F2C3A', + 50: '#F4F1FC', + 100: '#e4e2e9', + 200: '#c8c5d3', + 300: '#ada8bd', + 400: '#918ba7', + 500: '#766e91', + 600: '#5e5874', + 700: '#474257', + 800: '#23212c', + 900: '#18161d' + }, + info: { + DEFAULT: '#2F2C3A', + 50: '#dae6fc', + 100: '#b5cdf9', + 200: '#91b3f6', + 300: '#6c9af3', + 400: '#135be6', + 500: '#0e44ad', + 600: '#092e73', + 700: '#061d48', + 800: '#05173a', + 900: '#041330' + }, + success: { + DEFAULT: '#62DE85', + 50: '#e0f8e7', + 100: '#c0f2ce', + 200: '#a1ebb6', + 300: '#81e59d', + 400: '#41d76b', + 500: '#2ac656', + 600: '#1c8439', + 700: '#15632b', + 800: '#0e421d', + 900: '#07210e' + }, + warning: { + DEFAULT: '#FFA63D', + 50: '#ffedd8', + 100: '#ffdbb1', + 200: '#ffca8b', + 300: '#ffb864', + 400: '#ff9416', + 500: '#ed8000', + 600: '#c66b00', + 700: '#9e5600', + 800: '#4f2b00', + 900: '#271500' + }, + danger: { + DEFAULT: '#FF5353', + 50: '#ffdddd', + 100: '#ffbaba', + 200: '#ff9898', + 300: '#ff7575', + 400: '#ff2323', + 500: '#f10000', + 600: '#c10000', + 700: '#910000', + 800: '#610000', + 900: '#300000' + }, + + // + navigation: { + background: '#212121' + }, + + c1: { + light: '#FFFFFF', + DEFAULT: 'rgba(var(--clickhouse-color-1), )', + dark: '#2F2C3A' + }, + c2: { + light: '#F6F7FA', + DEFAULT: 'rgba(var(--clickhouse-color-2), )', + dark: '#373343' + }, + c3: '#443F51', + c4: { + light: '#6D7386', + DEFAULT: 'rgba(var(--clickhouse-color-4), )', + dark: '#B0B4BC' + }, + c5: { + light: '#2F2C3A', + DEFAULT: 'rgba(var(--clickhouse-color-5), )', + dark: '#FFFFFF' + }, + c6: { + DEFAULT: '#FAFF69', + text: '#FAFF69', + link: '#C78F0F' + }, + c7: { + light: '#A6770D', + DEFAULT: 'rgba(var(--clickhouse-color-7), )', + dark: '#FFC133' + }, + gradientTop: '#FAFF69', + gradientBottom: '#EEF400', + alerts: { + danger: { + text: '#C70F0F', + background: '#FAE7E7' + }, + info: { + text: '#3B73DE', + background: '#E6F1FA' + }, + success: { + text: '#00664B', + background: '#E6F9F4' + }, + warning: { + text: '#805300', + background: '#FFF8E6' + } + } + }, + boxShadow: { + card: '0px 4px 4px rgba(0, 0, 0, 0.06), inset 0px 4px 25px rgba(0, 0, 0, 0.14)', + 'card-xl': '0px 4px 14px 4px rgba(0, 0, 0, 0.13)', + input: '0px 1px 2px rgba(0, 0, 0, 0.05)', + 'click-card': + '0px 4px 44px rgba(22, 22, 0, 0.4), inset 0px 1px 3px rgba(25, 26, 6, 0.9)', + 'click-pill': '0px -1px 5px rgba(16, 24, 40, 0.07)', + 'click-twitter': '0px 4px 48px rgba(250, 255, 72, 0.2)', + 'footer-line': '0px -1px 1px #000000', + codeblock: + '0px 4px 4px rgba(0, 0, 0, 0.06), inset 0px 4px 25px rgba(0, 0, 0, 0.14)', + header_bottom: 'inset 0px -1px 0px rgba(78, 78, 78, 0.25);', + noOffset: '0 0 100px -12px rgb(0 0 0 / 0.25)', + 'noOffset-sm': '0 0 48px rgb(0 0 0 / 0.25)', + stackIntegrationGraphic: '0 4px 60px rgb(251, 255, 70)', + stackIntegrationGraphicSmall: '0 2px 30px rgb(251, 255, 70)' + }, + backgroundSize: { + default_size: '0%, 100%', + focus_size: '100%, 100%' + }, + backgroundImage: { + 'air-gapped': 'url("/images/air-gapped.svg")', + 'half-highlight': + 'linear-gradient(to bottom, rgba(65,65,65,1) 56%, transparent 56%)', + snowflakeGradient: + 'linear-gradient(0deg, #FAFF69 30%, rgba(252, 255, 116, 0) 99.99%)', + homepageFadeLeftLogos: + 'linear-gradient(90deg, #FAFF69 30%, rgba(252, 255, 116, 0) 99.99%)', + homepageFadeRightLogos: + 'linear-gradient(270deg, #FAFF69 30%, rgba(252, 255, 116, 0) 99.99%)', + cloudFadeLeftLogos: + 'linear-gradient(90deg, #1D1D1D 30%, rgba(29, 29, 29, 0.1) 99.99%)', + cloudFadeRightLogos: + 'linear-gradient(270deg, #1D1D1D 30%, rgba(29, 29, 29, 0.09) 99.99%)', + field_focus: + 'linear-gradient(0deg, #fbff46, #fbff46 2px, transparent 0, transparent)', + navDropdown: + 'linear-gradient(to bottom, rgba(65, 65, 65, 0.3) 0px, rgba(65, 65, 65, 0.3) 1px, #282828 1px, #282828 44px, rgba(65, 65, 65, 0.3) 44px, rgba(65, 65, 65, 0.3)45px, #1F1F1C 45px, #1F1F1C 100%)', + grid: 'url("/dot_grid.svg")', + 'click-grid': 'url("/bg-grid.svg")', + 'home-grid': + 'linear-gradient(117.08deg, rgba(0, 0, 0, 0) 14.55%, rgba(22, 22, 0, 0.167461) 34.15%, rgba(47, 47, 47, 0.22751) 40.54%, rgba(22, 22, 0, 0.611327) 46.65%, #161600 95.98%), url("/bg-grid.png");', + 'speed-lines': 'url("/speed-lines.svg")', + 'speed-lines-ml': 'url("/speed-lines-ml.svg")', + calendar: 'url("/calendar.svg")', + 'body-image': 'linear-gradient(272.48deg, #292924 1.95%, #0F0F0F 100%)', + 'menu-options': + 'linear-gradient(255.48deg, rgba(41, 41, 36, 0.95) 1.95%, rgba(15, 15, 15, 0.95) 100%)' + }, + spacing: { + '30': '7.5rem' + }, + keyframes: { + enterFromRight: { + from: { opacity: 0, transform: 'translateX(200px)' }, + to: { opacity: 1, transform: 'translateX(0)' } + }, + enterFromLeft: { + from: { opacity: 0, transform: 'translateX(-200px)' }, + to: { opacity: 1, transform: 'translateX(0)' } + }, + exitToRight: { + from: { opacity: 1, transform: 'translateX(0)' }, + to: { opacity: 0, transform: 'translateX(200px)' } + }, + exitToLeft: { + from: { opacity: 1, transform: 'translateX(0)' }, + to: { opacity: 0, transform: 'translateX(-200px)' } + }, + scaleIn: { + from: { opacity: 0, transform: 'rotateX(-10deg) scale(0.9)' }, + to: { opacity: 1, transform: 'rotateX(0deg) scale(1)' } + }, + scaleOut: { + from: { opacity: 1, transform: 'rotateX(0deg) scale(1)' }, + to: { opacity: 0, transform: 'rotateX(-10deg) scale(0.95)' } + }, + fadeIn: { + from: { opacity: 0 }, + to: { opacity: 1 } + }, + fadeOut: { + from: { opacity: 1 }, + to: { opacity: 0 } + }, + marqueeLeftTransform: { + '0%': { transform: 'translateX(0%)' }, + '100%': { transform: 'translateX(-100%)' } + }, + marqueeLeftTransform2: { + '0%': { transform: 'translateX(100%)' }, + '100%': { transform: 'translateX(0%)' } + }, + loggingFadeSection1: { + '0%': { opacity: '0.05', transform: 'scale(0.9)' }, + '50%': { opacity: '0.15', transform: 'scale(1.1)' }, + '100%': { opacity: '0.05', transform: 'scale(0.9)' } + }, + loggingFadeSection2: { + '0%': { opacity: '0.05', transform: 'scale(0.9)' }, + '50%': { opacity: '0.25', transform: 'scale(1.1)' }, + '100%': { opacity: '0.05', transform: 'scale(0.9)' } + } + }, + animation: { + scaleIn: 'scaleIn 200ms ease', + scaleOut: 'scaleOut 200ms ease', + fadeIn: 'fadeIn 200ms ease', + fadeOut: 'fadeOut 200ms ease', + enterFromLeft: 'enterFromLeft 250ms ease', + enterFromRight: 'enterFromRight 250ms ease', + exitToLeft: 'exitToLeft 250ms ease', + exitToRight: 'exitToRight 250ms ease', + marqueeLeft: 'marqueeLeftTransform 75s linear infinite', + marqueeLeft2: 'marqueeLeftTransform2 75s linear infinite ', + marqueeLeft3: 'marqueeLeftTransform 90s linear infinite', + marqueeLeft4: 'marqueeLeftTransform2 90s linear infinite ', + marqueeLeft5: 'marqueeLeftTransform 190s linear infinite', + marqueeLeft6: 'marqueeLeftTransform2 190s linear infinite ', + loggingFadeSection1: 'loggingFadeSection1 5s ease-in-out infinite', + loggingFadeSection2: 'loggingFadeSection2 5s ease-in-out infinite' + } + } + } + } + \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 9ba1930a79d..8d51acd6a0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -150,6 +150,11 @@ dependencies: "@algolia/client-common" "5.20.1" +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + "@ampproject/remapping@^2.2.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" @@ -1109,6 +1114,13 @@ core-js-pure "^3.30.2" regenerator-runtime "^0.14.0" +"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.1": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.0.tgz#fbee7cf97c709518ecc1f590984481d5460d4762" + integrity sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.25.9", "@babel/runtime@^7.8.4": version "7.26.10" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2" @@ -1200,6 +1212,47 @@ resolved "https://registry.yarnpkg.com/@chevrotain/utils/-/utils-11.0.3.tgz#e39999307b102cff3645ec4f5b3665f5297a2224" integrity sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ== +"@clickhouse/click-ui@^0.0.199": + version "0.0.199" + resolved "https://registry.yarnpkg.com/@clickhouse/click-ui/-/click-ui-0.0.199.tgz#4a9f6ddf38cc5d04c24e0775805425ae1b3e9e36" + integrity sha512-39I8JHibF4/qMZQV0KJvSovDDP5mC9HIapBCqrxB3+KgpnAhtIqZaNtiIA4tM7goFSJti6xwpzc6OL2LE3H9yA== + dependencies: + "@h6s/calendar" "^2.0.1" + "@radix-ui/react-accordion" "^1.1.2" + "@radix-ui/react-avatar" "^1.0.4" + "@radix-ui/react-checkbox" "^1.0.4" + "@radix-ui/react-context-menu" "^2.1.5" + "@radix-ui/react-dialog" "^1.0.5" + "@radix-ui/react-dismissable-layer" "^1.0.5" + "@radix-ui/react-dropdown-menu" "^2.0.6" + "@radix-ui/react-hover-card" "^1.0.7" + "@radix-ui/react-popover" "^1.0.7" + "@radix-ui/react-popper" "^1.1.3" + "@radix-ui/react-radio-group" "^1.1.3" + "@radix-ui/react-scroll-area" "^1.0.5" + "@radix-ui/react-separator" "^1.0.3" + "@radix-ui/react-tabs" "^1.0.4" + "@radix-ui/react-toast" "^1.1.5" + "@radix-ui/react-tooltip" "^1.0.7" + lodash "^4.17.21" + react-sortablejs "^6.1.4" + react-syntax-highlighter "^15.5.0" + react-virtualized-auto-sizer "^1.0.20" + react-window "^1.8.9" + sortablejs "^1.15.0" + +"@clickhouse/client-common@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@clickhouse/client-common/-/client-common-1.11.0.tgz#e66f74040228984dd1b7bda4749bc2d14cfa897d" + integrity sha512-O0xbwv7HiMXayokrf5dYIBpjBnYekcOXWz60T1cXLmiZ8vgrfNRCiOpybJkrMXKnw9D0mWCgPUu/rgMY7U1f4g== + +"@clickhouse/client-web@^1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@clickhouse/client-web/-/client-web-1.11.0.tgz#86601892f6b6a562ec4248f077e2964f2cf2fcb6" + integrity sha512-5N8ll85KRjVsxq2V0Y3gowcApwZA+YyIHIC7M5bFki8gtt3SihijH9cspdZBdBTFFzYPbiKS+zftKq7YQhoGxA== + dependencies: + "@clickhouse/client-common" "1.11.0" + "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -2342,6 +2395,38 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz#c8e119a30a7c8d60b9d2e22d2073722dde3b710b" integrity sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ== +"@floating-ui/core@^1.6.0": + version "1.6.9" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.9.tgz#64d1da251433019dafa091de9b2886ff35ec14e6" + integrity sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw== + dependencies: + "@floating-ui/utils" "^0.2.9" + +"@floating-ui/dom@^1.0.0": + version "1.6.13" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.13.tgz#a8a938532aea27a95121ec16e667a7cbe8c59e34" + integrity sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w== + dependencies: + "@floating-ui/core" "^1.6.0" + "@floating-ui/utils" "^0.2.9" + +"@floating-ui/react-dom@^2.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.2.tgz#a1349bbf6a0e5cb5ded55d023766f20a4d439a31" + integrity sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A== + dependencies: + "@floating-ui/dom" "^1.0.0" + +"@floating-ui/utils@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.9.tgz#50dea3616bc8191fb8e112283b49eaff03e78429" + integrity sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg== + +"@h6s/calendar@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@h6s/calendar/-/calendar-2.0.1.tgz#ce3f0c9311ca2a961b18c74be801891984ae219c" + integrity sha512-9q5ksdnUsLDeuSm5arXzkxHyS22u7yi5TtVr4DZgW514AjdL+76kx7d+ScX9sKusasRQVxrhM2LTVmd8A/u42Q== + "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" @@ -2773,11 +2858,76 @@ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.28.tgz#d45e01c4a56f143ee69c54dd6b12eade9e270a73" integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw== +"@radix-ui/number@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.0.tgz#1e95610461a09cdf8bb05c152e76ca1278d5da46" + integrity sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ== + "@radix-ui/primitive@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.1.tgz#fc169732d755c7fbad33ba8d0cd7fd10c90dc8e3" integrity sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA== +"@radix-ui/react-accordion@^1.1.2": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-accordion/-/react-accordion-1.2.3.tgz#7768a2d2daea18e5c09809f2c4b8097448ee2ff7" + integrity sha512-RIQ15mrcvqIkDARJeERSuXSry2N8uYnxkdDetpfmalT/+0ntOXLkFOsh9iwlAsCv+qcmhZjbdJogIm6WBa6c4A== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-collapsible" "1.1.3" + "@radix-ui/react-collection" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-direction" "1.1.0" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + +"@radix-ui/react-arrow@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz#30c0d574d7bb10eed55cd7007b92d38b03c6b2ab" + integrity sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg== + dependencies: + "@radix-ui/react-primitive" "2.0.2" + +"@radix-ui/react-avatar@^1.0.4": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-avatar/-/react-avatar-1.1.3.tgz#8de2bcebdc38fbe14e952ccacf05ba2cb426bd83" + integrity sha512-Paen00T4P8L8gd9bNsRMw7Cbaz85oxiv+hzomsRZgFm2byltPFDtfcoqlWJ8GyZlIBWgLssJlzLCnKU0G0302g== + dependencies: + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-layout-effect" "1.1.0" + +"@radix-ui/react-checkbox@^1.0.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-1.1.4.tgz#d7f5cb0a82ca6bb4eb717b74e9b2b0cc73ecf7a0" + integrity sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-use-previous" "1.1.0" + "@radix-ui/react-use-size" "1.1.0" + +"@radix-ui/react-collapsible@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-1.1.3.tgz#522a5749646b7a393c9e9049165a9a6dfa924e91" + integrity sha512-jFSerheto1X03MUC0g6R7LedNW9EEGWdg9W1+MlpkMLwGkgkbUXLPBH/KIuWKXUoeYRVY11llqbTBDzuLg7qrw== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-use-layout-effect" "1.1.0" + "@radix-ui/react-collection@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.2.tgz#b45eccca1cb902fd078b237316bd9fa81e621e15" @@ -2793,17 +2943,49 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec" integrity sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw== +"@radix-ui/react-context-menu@^2.1.5": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context-menu/-/react-context-menu-2.2.6.tgz#752fd1d91f92bba287ef2b558770f4ca7d74523e" + integrity sha512-aUP99QZ3VU84NPsHeaFt4cQUNgJqFsLLOt/RbbWXszZ6MP0DpDyjkFZORr4RpAEx3sUBk+Kc8h13yGtC5Qw8dg== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-menu" "2.1.6" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-context@1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.1.tgz#82074aa83a472353bb22e86f11bcbd1c61c4c71a" integrity sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q== +"@radix-ui/react-dialog@^1.0.5": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.6.tgz#65b4465e99ad900f28a98eed9a94bb21ec644bf7" + integrity sha512-/IVhJV5AceX620DUJ4uYVMymzsipdKBzo3edo+omeskCKGm9FRHM0ebIdbPnlQVJqyuHbuBltQUOG2mOTq2IYw== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.5" + "@radix-ui/react-focus-guards" "1.1.1" + "@radix-ui/react-focus-scope" "1.1.2" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-portal" "1.1.4" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-slot" "1.1.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + "@radix-ui/react-direction@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.0.tgz#a7d39855f4d077adc2a1922f9c353c5977a09cdc" integrity sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg== -"@radix-ui/react-dismissable-layer@1.1.5": +"@radix-ui/react-dismissable-layer@1.1.5", "@radix-ui/react-dismissable-layer@^1.0.5": version "1.1.5" resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz#96dde2be078c694a621e55e047406c58cd5fe774" integrity sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg== @@ -2814,6 +2996,48 @@ "@radix-ui/react-use-callback-ref" "1.1.0" "@radix-ui/react-use-escape-keydown" "1.1.0" +"@radix-ui/react-dropdown-menu@^2.0.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.6.tgz#b66b62648b378370aa3c38e5727fd3bc5b8792a3" + integrity sha512-no3X7V5fD487wab/ZYSHXq3H37u4NVeLDKI/Ks724X/eEFSSEFYZxWgsIlr1UBeEyDaM29HM5x9p1Nv8DuTYPA== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-menu" "2.1.6" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + +"@radix-ui/react-focus-guards@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz#8635edd346304f8b42cae86b05912b61aef27afe" + integrity sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg== + +"@radix-ui/react-focus-scope@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz#c0a4519cd95c772606a82fc5b96226cd7fdd2602" + integrity sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA== + dependencies: + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-callback-ref" "1.1.0" + +"@radix-ui/react-hover-card@^1.0.7": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-hover-card/-/react-hover-card-1.1.6.tgz#94fb87c047e1bb3bfd70439cf7ee48165ea4efa5" + integrity sha512-E4ozl35jq0VRlrdc4dhHrNSV0JqBb4Jy73WAhBEK7JoYnQ83ED5r0Rb/XdVKw89ReAJN38N492BAPBZQ57VmqQ== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.5" + "@radix-ui/react-popper" "1.2.2" + "@radix-ui/react-portal" "1.1.4" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-id@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.0.tgz#de47339656594ad722eb87f94a6b25f9cffae0ed" @@ -2821,6 +3045,30 @@ dependencies: "@radix-ui/react-use-layout-effect" "1.1.0" +"@radix-ui/react-menu@2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.1.6.tgz#05fb1ef3fd7545c8abe61178372902970cdec3ce" + integrity sha512-tBBb5CXDJW3t2mo9WlO7r6GTmWV0F0uzHZVFmlRmYpiSK1CDU5IKojP1pm7oknpBOrFZx/YgBRW9oorPO2S/Lg== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-collection" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-direction" "1.1.0" + "@radix-ui/react-dismissable-layer" "1.1.5" + "@radix-ui/react-focus-guards" "1.1.1" + "@radix-ui/react-focus-scope" "1.1.2" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-popper" "1.2.2" + "@radix-ui/react-portal" "1.1.4" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-roving-focus" "1.1.2" + "@radix-ui/react-slot" "1.1.2" + "@radix-ui/react-use-callback-ref" "1.1.0" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + "@radix-ui/react-navigation-menu@^1.2.5": version "1.2.5" resolved "https://registry.yarnpkg.com/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.5.tgz#c882e2067f1101a9a5f18e05b73b68b2e158a272" @@ -2841,6 +3089,51 @@ "@radix-ui/react-use-previous" "1.1.0" "@radix-ui/react-visually-hidden" "1.1.2" +"@radix-ui/react-popover@^1.0.7": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.6.tgz#699634dbc7899429f657bb590d71fb3ca0904087" + integrity sha512-NQouW0x4/GnkFJ/pRqsIS3rM/k97VzKnVb2jB7Gq7VEGPy5g7uNV1ykySFt7eWSp3i2uSGFwaJcvIRJBAHmmFg== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.5" + "@radix-ui/react-focus-guards" "1.1.1" + "@radix-ui/react-focus-scope" "1.1.2" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-popper" "1.2.2" + "@radix-ui/react-portal" "1.1.4" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-slot" "1.1.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + +"@radix-ui/react-popper@1.2.2", "@radix-ui/react-popper@^1.1.3": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.2.2.tgz#d2e1ee5a9b24419c5936a1b7f6f472b7b412b029" + integrity sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA== + dependencies: + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-layout-effect" "1.1.0" + "@radix-ui/react-use-rect" "1.1.0" + "@radix-ui/react-use-size" "1.1.0" + "@radix-ui/rect" "1.1.0" + +"@radix-ui/react-portal@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.4.tgz#ff5401ff63c8a825c46eea96d3aef66074b8c0c8" + integrity sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA== + dependencies: + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-layout-effect" "1.1.0" + "@radix-ui/react-presence@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.2.tgz#bb764ed8a9118b7ec4512da5ece306ded8703cdc" @@ -2856,6 +3149,59 @@ dependencies: "@radix-ui/react-slot" "1.1.2" +"@radix-ui/react-radio-group@^1.1.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-radio-group/-/react-radio-group-1.2.3.tgz#f60f58179cce716ccdb5c3d53a2eca97e4efd520" + integrity sha512-xtCsqt8Rp09FK50ItqEqTJ7Sxanz8EM8dnkVIhJrc/wkMMomSmXHvYbhv3E7Zx4oXh98aaLt9W679SUYXg4IDA== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-direction" "1.1.0" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-roving-focus" "1.1.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-use-previous" "1.1.0" + "@radix-ui/react-use-size" "1.1.0" + +"@radix-ui/react-roving-focus@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.2.tgz#815d051a54299114a68db6eb8d34c41a3c0a646f" + integrity sha512-zgMQWkNO169GtGqRvYrzb0Zf8NhMHS2DuEB/TiEmVnpr5OqPU3i8lfbxaAmC2J/KYuIQxyoQQ6DxepyXp61/xw== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-collection" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-direction" "1.1.0" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-controllable-state" "1.1.0" + +"@radix-ui/react-scroll-area@^1.0.5": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.3.tgz#6a9a7897add739ce84b517796ee345d495893d3f" + integrity sha512-l7+NNBfBYYJa9tNqVcP2AGvxdE3lmE6kFTBXdvHgUaZuy+4wGCL1Cl2AfaR7RKyimj7lZURGLwFO59k4eBnDJQ== + dependencies: + "@radix-ui/number" "1.1.0" + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-direction" "1.1.0" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-layout-effect" "1.1.0" + +"@radix-ui/react-separator@^1.0.3": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.2.tgz#24c5450db20f341f2b743ed4b07b907e18579216" + integrity sha512-oZfHcaAp2Y6KFBX6I5P1u7CQoy4lheCGiYj+pGFrHy8E/VNRb5E39TkTr3JrV520csPBTZjkuKFdEsjS5EUNKQ== + dependencies: + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-slot@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.2.tgz#daffff7b2bfe99ade63b5168407680b93c00e1c6" @@ -2863,6 +3209,56 @@ dependencies: "@radix-ui/react-compose-refs" "1.1.1" +"@radix-ui/react-tabs@^1.0.4": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tabs/-/react-tabs-1.1.3.tgz#c47c8202dc676dea47676215863d2ef9b141c17a" + integrity sha512-9mFyI30cuRDImbmFF6O2KUJdgEOsGh9Vmx9x/Dh9tOhL7BngmQPQfwW4aejKm5OHpfWIdmeV6ySyuxoOGjtNng== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-direction" "1.1.0" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-roving-focus" "1.1.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + +"@radix-ui/react-toast@^1.1.5": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-toast/-/react-toast-1.2.6.tgz#f8d4bb2217851d221d700ac48fbe866b35023361" + integrity sha512-gN4dpuIVKEgpLn1z5FhzT9mYRUitbfZq9XqN/7kkBMUgFTzTG8x/KszWJugJXHcwxckY8xcKDZPz7kG3o6DsUA== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-collection" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.5" + "@radix-ui/react-portal" "1.1.4" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-use-layout-effect" "1.1.0" + "@radix-ui/react-visually-hidden" "1.1.2" + +"@radix-ui/react-tooltip@^1.0.7": + version "1.1.8" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.1.8.tgz#1aa2a575630fca2b2845b62f85056bb826bec456" + integrity sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.5" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-popper" "1.2.2" + "@radix-ui/react-portal" "1.1.4" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.2" + "@radix-ui/react-slot" "1.1.2" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-visually-hidden" "1.1.2" + "@radix-ui/react-use-callback-ref@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz#bce938ca413675bc937944b0d01ef6f4a6dc5bf1" @@ -2892,6 +3288,20 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz#d4dd37b05520f1d996a384eb469320c2ada8377c" integrity sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og== +"@radix-ui/react-use-rect@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz#13b25b913bd3e3987cc9b073a1a164bb1cf47b88" + integrity sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ== + dependencies: + "@radix-ui/rect" "1.1.0" + +"@radix-ui/react-use-size@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz#b4dba7fbd3882ee09e8d2a44a3eed3a7e555246b" + integrity sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.0" + "@radix-ui/react-visually-hidden@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz#8f6025507eb5d8b4b3215ebfd2c71a6632323a62" @@ -2899,6 +3309,11 @@ dependencies: "@radix-ui/react-primitive" "2.0.2" +"@radix-ui/rect@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438" + integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg== + "@rspack/binding-darwin-arm64@1.2.0-alpha.0": version "1.2.0-alpha.0" resolved "https://registry.yarnpkg.com/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.2.0-alpha.0.tgz#234a0c42f6e89a2589f53ad8c44b2e85638bc77b" @@ -3287,6 +3702,109 @@ dependencies: defer-to-connect "^2.0.1" +"@tailwindcss/node@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/node/-/node-4.1.3.tgz#f290886582ce8eb1978853d07ca4da45f2d43fdb" + integrity sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA== + dependencies: + enhanced-resolve "^5.18.1" + jiti "^2.4.2" + lightningcss "1.29.2" + tailwindcss "4.1.3" + +"@tailwindcss/oxide-android-arm64@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.3.tgz#6c1834e7de84aa5544f4c8aacb380e00e019a11f" + integrity sha512-cxklKjtNLwFl3mDYw4XpEfBY+G8ssSg9ADL4Wm6//5woi3XGqlxFsnV5Zb6v07dxw1NvEX2uoqsxO/zWQsgR+g== + +"@tailwindcss/oxide-darwin-arm64@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.3.tgz#ed3abd4a59f05a1ac58337b63d6fe82bb9903462" + integrity sha512-mqkf2tLR5VCrjBvuRDwzKNShRu99gCAVMkVsaEOFvv6cCjlEKXRecPu9DEnxp6STk5z+Vlbh1M5zY3nQCXMXhw== + +"@tailwindcss/oxide-darwin-x64@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.3.tgz#d8a0786f4eae8203f8345fcf5b03f3284eee82af" + integrity sha512-7sGraGaWzXvCLyxrc7d+CCpUN3fYnkkcso3rCzwUmo/LteAl2ZGCDlGvDD8Y/1D3ngxT8KgDj1DSwOnNewKhmg== + +"@tailwindcss/oxide-freebsd-x64@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.3.tgz#e76520e5341c3a44959901b8fefee78d4fc2f074" + integrity sha512-E2+PbcbzIReaAYZe997wb9rId246yDkCwAakllAWSGqe6VTg9hHle67hfH6ExjpV2LSK/siRzBUs5wVff3RW9w== + +"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.3.tgz#130c276e590b6ba621c443ac7faa702a709620c7" + integrity sha512-GvfbJ8wjSSjbLFFE3UYz4Eh8i4L6GiEYqCtA8j2Zd2oXriPuom/Ah/64pg/szWycQpzRnbDiJozoxFU2oJZyfg== + +"@tailwindcss/oxide-linux-arm64-gnu@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.3.tgz#55e736a89d8547835026df3c5d6ce50467d71241" + integrity sha512-35UkuCWQTeG9BHcBQXndDOrpsnt3Pj9NVIB4CgNiKmpG8GnCNXeMczkUpOoqcOhO6Cc/mM2W7kaQ/MTEENDDXg== + +"@tailwindcss/oxide-linux-arm64-musl@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.3.tgz#4ff54e4a40fede7a66e209b07f9b5da432d96678" + integrity sha512-dm18aQiML5QCj9DQo7wMbt1Z2tl3Giht54uVR87a84X8qRtuXxUqnKQkRDK5B4bCOmcZ580lF9YcoMkbDYTXHQ== + +"@tailwindcss/oxide-linux-x64-gnu@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.3.tgz#66477a71fbaad552be882e8b7a56bb7519b47838" + integrity sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA== + +"@tailwindcss/oxide-linux-x64-musl@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.3.tgz#403145ce43361e7d63886c878fdb09cd868920da" + integrity sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw== + +"@tailwindcss/oxide-win32-arm64-msvc@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.3.tgz#0cc2bc59c228ce1d64156089af21acc4302081da" + integrity sha512-PEj7XR4OGTGoboTIAdXicKuWl4EQIjKHKuR+bFy9oYN7CFZo0eu74+70O4XuERX4yjqVZGAkCdglBODlgqcCXg== + +"@tailwindcss/oxide-win32-x64-msvc@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.3.tgz#9bd5108b95b03dace8a2e5e738b1b2389f8a6d09" + integrity sha512-T8gfxECWDBENotpw3HR9SmNiHC9AOJdxs+woasRZ8Q/J4VHN0OMs7F+4yVNZ9EVN26Wv6mZbK0jv7eHYuLJLwA== + +"@tailwindcss/oxide@4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide/-/oxide-4.1.3.tgz#d01162137fcefe7d4c2a34500b9ed5c142388352" + integrity sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ== + optionalDependencies: + "@tailwindcss/oxide-android-arm64" "4.1.3" + "@tailwindcss/oxide-darwin-arm64" "4.1.3" + "@tailwindcss/oxide-darwin-x64" "4.1.3" + "@tailwindcss/oxide-freebsd-x64" "4.1.3" + "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.3" + "@tailwindcss/oxide-linux-arm64-gnu" "4.1.3" + "@tailwindcss/oxide-linux-arm64-musl" "4.1.3" + "@tailwindcss/oxide-linux-x64-gnu" "4.1.3" + "@tailwindcss/oxide-linux-x64-musl" "4.1.3" + "@tailwindcss/oxide-win32-arm64-msvc" "4.1.3" + "@tailwindcss/oxide-win32-x64-msvc" "4.1.3" + +"@tailwindcss/postcss@^4.1.3": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@tailwindcss/postcss/-/postcss-4.1.3.tgz#82bf8b90c134f89f70d8d0293b5b14f234918faf" + integrity sha512-6s5nJODm98F++QT49qn8xJKHQRamhYHfMi3X7/ltxiSQ9dyRsaFSfFkfaMsanWzf+TMYQtbk8mt5f6cCVXJwfg== + dependencies: + "@alloc/quick-lru" "^5.2.0" + "@tailwindcss/node" "4.1.3" + "@tailwindcss/oxide" "4.1.3" + postcss "^8.4.41" + tailwindcss "4.1.3" + +"@tailwindcss/typography@^0.5.16": + version "0.5.16" + resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.16.tgz#a926c8f44d5c439b2915e231cad80058850047c6" + integrity sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA== + dependencies: + lodash.castarray "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.merge "^4.6.2" + postcss-selector-parser "6.0.10" + "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" @@ -3624,6 +4142,13 @@ resolved "https://registry.yarnpkg.com/@types/gtag.js/-/gtag.js-0.0.12.tgz#095122edca896689bdfcdd73b057e23064d23572" integrity sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg== +"@types/hast@^2.0.0": + version "2.3.10" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.10.tgz#5c9d9e0b304bbb8879b857225c5ebab2d81d7643" + integrity sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw== + dependencies: + "@types/unist" "^2" + "@types/hast@^3.0.0": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.4.tgz#1d6b39993b82cea6ad783945b0508c25903e15aa" @@ -3841,7 +4366,7 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.3.tgz#acaab0f919ce69cce629c2d4ed2eb4adc1b6c20c" integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q== -"@types/unist@^2.0.0": +"@types/unist@^2", "@types/unist@^2.0.0": version "2.0.11" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.11.tgz#11af57b127e32487774841f7a4e54eab166d03c4" integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA== @@ -4150,6 +4675,11 @@ ansi-styles@^6.1.0, ansi-styles@^6.2.1: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== +any-base@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" + integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== + anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -4175,6 +4705,13 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +aria-hidden@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.4.tgz#b78e383fdbc04d05762c78b4a25a501e736c4522" + integrity sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A== + dependencies: + tslib "^2.0.0" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -4586,16 +5123,31 @@ character-entities-html4@^2.0.0: resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz#1f1adb940c971a4b22ba39ddca6b618dc6e56b2b" integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + character-entities-legacy@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + character-entities@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + character-reference-invalid@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" @@ -4699,6 +5251,11 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== +classnames@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + clean-css@^5.2.2, clean-css@^5.3.2, clean-css@~5.3.2: version "5.3.3" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd" @@ -4811,6 +5368,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +comma-separated-tokens@^1.0.0: + version "1.0.8" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" + integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== + comma-separated-tokens@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz#4e89c9458acb61bc8fef19f4529973b2392839ee" @@ -5676,6 +6238,11 @@ detect-libc@^2.0.0, detect-libc@^2.0.2, detect-libc@^2.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + detect-node@^2.0.4: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" @@ -5835,6 +6402,22 @@ eastasianwidth@^0.2.0: resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== +echarts-for-react@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/echarts-for-react/-/echarts-for-react-3.0.2.tgz#ac5859157048a1066d4553e34b328abb24f2b7c1" + integrity sha512-DRwIiTzx8JfwPOVgGttDytBqdp5VzCSyMRIxubgU/g2n9y3VLUmF2FK7Icmg/sNVkv4+rktmrLN9w22U2yy3fA== + dependencies: + fast-deep-equal "^3.1.3" + size-sensor "^1.0.1" + +echarts@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.6.0.tgz#2377874dca9fb50f104051c3553544752da3c9d6" + integrity sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA== + dependencies: + tslib "2.3.0" + zrender "5.6.1" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -5900,7 +6483,7 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -enhanced-resolve@^5.17.1: +enhanced-resolve@^5.17.1, enhanced-resolve@^5.18.1: version "5.18.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz#728ab082f8b7b6836de51f1637aab5d3b9568faf" integrity sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg== @@ -6298,6 +6881,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fault@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fault/-/fault-1.0.4.tgz#eafcfc0a6d214fc94601e170df29954a4f842f13" + integrity sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA== + dependencies: + format "^0.2.0" + fault@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fault/-/fault-2.0.1.tgz#d47ca9f37ca26e4bd38374a7c500b5a384755b6c" @@ -6342,6 +6932,11 @@ file-loader@^6.2.0: loader-utils "^2.0.0" schema-utils "^3.0.0" +filesize@^10.1.6: + version "10.1.6" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-10.1.6.tgz#31194da825ac58689c0bce3948f33ce83aabd361" + integrity sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w== + filesize@^8.0.6: version "8.0.7" resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8" @@ -6548,6 +7143,11 @@ get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6: hasown "^2.0.2" math-intrinsics "^1.1.0" +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + get-own-enumerable-property-symbols@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" @@ -6834,6 +7434,11 @@ hast-util-is-element@^3.0.0: dependencies: "@types/hast" "^3.0.0" +hast-util-parse-selector@^2.0.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a" + integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ== + hast-util-parse-selector@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz#352879fa86e25616036037dd8931fb5f34cb4a27" @@ -6933,6 +7538,17 @@ hast-util-whitespace@^3.0.0: dependencies: "@types/hast" "^3.0.0" +hastscript@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640" + integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w== + dependencies: + "@types/hast" "^2.0.0" + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^5.0.0" + space-separated-tokens "^1.0.0" + hastscript@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-9.0.0.tgz#2b76b9aa3cba8bf6d5280869f6f6f7165c230763" @@ -6949,6 +7565,16 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +highlight.js@^10.4.1, highlight.js@~10.7.0: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +highlightjs-vue@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz#fdfe97fbea6354e70ee44e3a955875e114db086d" + integrity sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA== + history@^4.9.0: version "4.10.1" resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" @@ -7290,11 +7916,24 @@ ipaddr.js@^2.0.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + is-alphabetical@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-alphanumerical@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" @@ -7334,6 +7973,11 @@ is-core-module@^2.16.0: dependencies: hasown "^2.0.2" +is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + is-decimal@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" @@ -7366,6 +8010,11 @@ is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + is-hexadecimal@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" @@ -7557,6 +8206,11 @@ jiti@^1.20.0: resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.7.tgz#9dd81043424a3d28458b193d965f0d18a2300ba9" integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A== +jiti@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + joi@^17.9.2: version "17.13.3" resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.3.tgz#0f5cc1169c999b30d344366d384b12d92558bcec" @@ -7774,7 +8428,7 @@ lightningcss-win32-x64-msvc@1.29.2: resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz#ddefaa099a39b725b2f5bbdcb9fc718435cc9797" integrity sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA== -lightningcss@^1.27.0: +lightningcss@1.29.2, lightningcss@^1.27.0: version "1.29.2" resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.29.2.tgz#f5f0fd6e63292a232697e6fe709da5b47624def3" integrity sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA== @@ -7863,6 +8517,11 @@ lodash-es@4.17.21, lodash-es@^4.17.21: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash.castarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + integrity sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q== + lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -7873,11 +8532,21 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -7920,6 +8589,14 @@ lowercase-keys@^3.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== +lowlight@^1.17.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888" + integrity sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw== + dependencies: + fault "^1.0.0" + highlight.js "~10.7.0" + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -8266,6 +8943,11 @@ memfs@^3.1.2, memfs@^3.4.3: dependencies: fs-monkey "^1.0.4" +"memoize-one@>=3.1.1 <6": + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + merge-descriptors@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" @@ -9005,6 +9687,11 @@ null-loader@^4.0.1: loader-utils "^2.0.0" schema-utils "^3.0.0" +numeral@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506" + integrity sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA== + object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -9218,6 +9905,18 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + parse-entities@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.2.tgz#61d46f5ed28e4ee62e9ddc43d6b010188443f159" @@ -9912,6 +10611,14 @@ postcss-selector-not@^8.0.1: dependencies: postcss-selector-parser "^7.0.0" +postcss-selector-parser@6.0.10: + version "6.0.10" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" + integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + postcss-selector-parser@^6.0.11, postcss-selector-parser@^6.0.16: version "6.1.2" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" @@ -9969,6 +10676,15 @@ postcss@^8.4.21, postcss@^8.4.24, postcss@^8.4.26, postcss@^8.4.33, postcss@^8.4 picocolors "^1.1.1" source-map-js "^1.2.1" +postcss@^8.4.41, postcss@^8.5.3: + version "8.5.3" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" + integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== + dependencies: + nanoid "^3.3.8" + picocolors "^1.1.1" + source-map-js "^1.2.1" + prebuild-install@^7.1.1: version "7.1.3" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.3.tgz#d630abad2b147443f20a212917beae68b8092eec" @@ -10008,11 +10724,16 @@ prism-react-renderer@^2.3.0, prism-react-renderer@^2.4.1: "@types/prismjs" "^1.26.0" clsx "^2.0.0" -prismjs@^1.29.0: +prismjs@^1.27.0, prismjs@^1.29.0: version "1.30.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.30.0.tgz#d9709969d9d4e16403f6f348c63553b19f0975a9" integrity sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw== +prismjs@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" + integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -10035,6 +10756,13 @@ prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.13.1" +property-information@^5.0.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-5.6.0.tgz#61675545fb23002f245c6540ec46077d4da3ed69" + integrity sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA== + dependencies: + xtend "^4.0.0" + property-information@^6.0.0: version "6.5.0" resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.5.0.tgz#6212fbb52ba757e92ef4fb9d657563b933b7ffec" @@ -10237,6 +10965,25 @@ react-medium-image-zoom@^5.2.14: resolved "https://registry.yarnpkg.com/react-medium-image-zoom/-/react-medium-image-zoom-5.2.14.tgz#87032d079fce4a21a17770d6709f739872580906" integrity sha512-nfTVYcAUnBzXQpPDcZL+cG/e6UceYUIG+zDcnemL7jtAqbJjVVkA85RgneGtJeni12dTyiRPZVM6Szkmwd/o8w== +react-remove-scroll-bar@^2.3.7: + version "2.3.8" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz#99c20f908ee467b385b68a3469b4a3e750012223" + integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q== + dependencies: + react-style-singleton "^2.2.2" + tslib "^2.0.0" + +react-remove-scroll@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz#df02cde56d5f2731e058531f8ffd7f9adec91ac2" + integrity sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ== + dependencies: + react-remove-scroll-bar "^2.3.7" + react-style-singleton "^2.2.3" + tslib "^2.1.0" + use-callback-ref "^1.3.3" + use-sidecar "^1.1.3" + react-router-config@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/react-router-config/-/react-router-config-5.1.1.tgz#0f4263d1a80c6b2dc7b9c1902c9526478194a988" @@ -10272,6 +11019,39 @@ react-router@5.3.4, react-router@^5.3.4: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" +react-sortablejs@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/react-sortablejs/-/react-sortablejs-6.1.4.tgz#420ebfab602bbd935035dec24a04c8b3b836dbbf" + integrity sha512-fc7cBosfhnbh53Mbm6a45W+F735jwZ1UFIYSrIqcO/gRIFoDyZeMtgKlpV4DdyQfbCzdh5LoALLTDRxhMpTyXQ== + dependencies: + classnames "2.3.1" + tiny-invariant "1.2.0" + +react-style-singleton@^2.2.2, react-style-singleton@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388" + integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ== + dependencies: + get-nonce "^1.0.0" + tslib "^2.0.0" + +react-syntax-highlighter@^15.5.0: + version "15.6.1" + resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz#fa567cb0a9f96be7bbccf2c13a3c4b5657d9543e" + integrity sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg== + dependencies: + "@babel/runtime" "^7.3.1" + highlight.js "^10.4.1" + highlightjs-vue "^1.0.0" + lowlight "^1.17.0" + prismjs "^1.27.0" + refractor "^3.6.0" + +react-virtualized-auto-sizer@^1.0.20: + version "1.0.26" + resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz#e9470ef6a778dc4f1d5fd76305fa2d8b610c357a" + integrity sha512-CblNyiNVw2o+hsa5/49NH2ogGxZ+t+3aweRvNSq7TVjDIlwk7ir4lencEg5HxHeSzwNarSkNkiu0qJSOXtxm5A== + react-waypoint@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/react-waypoint/-/react-waypoint-10.3.0.tgz#fcc60e86c6c9ad2174fa58d066dc6ae54e3df71d" @@ -10282,6 +11062,14 @@ react-waypoint@^10.3.0: prop-types "^15.0.0" react-is "^17.0.1 || ^18.0.0" +react-window@^1.8.9: + version "1.8.11" + resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.11.tgz#a857b48fa85bd77042d59cc460964ff2e0648525" + integrity sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ== + dependencies: + "@babel/runtime" "^7.0.0" + memoize-one ">=3.1.1 <6" + react@^18.2.0: version "18.3.1" resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" @@ -10382,6 +11170,15 @@ recursive-readdir@^2.2.2: dependencies: minimatch "^3.0.5" +refractor@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" + integrity sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA== + dependencies: + hastscript "^6.0.0" + parse-entities "^2.0.0" + prismjs "~1.27.0" + regenerate-unicode-properties@^10.2.0: version "10.2.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0" @@ -11001,6 +11798,14 @@ shelljs@^0.8.5: interpret "^1.0.0" rechoir "^0.6.2" +short-uuid@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/short-uuid/-/short-uuid-5.2.0.tgz#49378f8c5335a603bc801c279ae521c5d22532dc" + integrity sha512-296/Nzi4DmANh93iYBwT4NoYRJuHnKEzefrkSagQbTH/A6NTaB68hSPDjm5IlbI5dx9FXdmtqPcj6N5H+CPm6w== + dependencies: + any-base "^1.1.0" + uuid "^9.0.1" + side-channel-list@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" @@ -11096,6 +11901,11 @@ sitemap@^7.1.1: arg "^5.0.0" sax "^1.2.4" +size-sensor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/size-sensor/-/size-sensor-1.0.2.tgz#b8f8da029683cf2b4e22f12bf8b8f0a1145e8471" + integrity sha512-2NCmWxY7A9pYKGXNBfteo4hy14gWu47rg5692peVMst6lQLPKrVjhY+UTEsPI5ceFRJSl3gVgMYaUi/hKuaiKw== + skin-tone@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/skin-tone/-/skin-tone-2.0.0.tgz#4e3933ab45c0d4f4f781745d64b9f4c208e41237" @@ -11140,6 +11950,11 @@ sort-css-media-queries@2.2.0: resolved "https://registry.yarnpkg.com/sort-css-media-queries/-/sort-css-media-queries-2.2.0.tgz#aa33cf4a08e0225059448b6c40eddbf9f1c8334c" integrity sha512-0xtkGhWCC9MGt/EzgnvbbbKhqWjl1+/rncmhTh5qCpbYguXh6S/qwePfv/JQ8jePXXmqingylxoC49pCkSPIbA== +sortablejs@^1.15.0: + version "1.15.6" + resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.15.6.tgz#ff93699493f5b8ab8d828f933227b4988df1d393" + integrity sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A== + source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" @@ -11168,6 +11983,11 @@ source-map@^0.7.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== +space-separated-tokens@^1.0.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" + integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== + space-separated-tokens@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz#1ecd9d2350a3844572c3f4a312bceb018348859f" @@ -11404,6 +12224,11 @@ swc-loader@^0.2.6: dependencies: "@swc/counter" "^0.1.3" +tailwindcss@4.1.3, tailwindcss@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-4.1.3.tgz#f5a6b4451295c06e213013697f7193be1630fa46" + integrity sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g== + tapable@^1.0.0: version "1.1.3" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" @@ -11493,6 +12318,11 @@ thunky@^1.0.2: resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== +tiny-invariant@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" + integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== + tiny-invariant@^1.0.2: version "1.3.3" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" @@ -11545,7 +12375,12 @@ ts-dedent@^2.2.0: resolved "https://registry.yarnpkg.com/ts-dedent/-/ts-dedent-2.2.0.tgz#39e4bd297cd036292ae2394eb3412be63f563bb5" integrity sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ== -tslib@^2.0.3, tslib@^2.4.0, tslib@^2.6.0: +tslib@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -11847,6 +12682,21 @@ url-loader@^4.1.1: mime-types "^2.1.27" schema-utils "^3.0.0" +use-callback-ref@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf" + integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg== + dependencies: + tslib "^2.0.0" + +use-sidecar@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb" + integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -12238,6 +13088,11 @@ xml-js@^1.6.11: dependencies: sax "^1.2.4" +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + yallist@^3.0.2: version "3.1.1" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" @@ -12263,6 +13118,13 @@ yocto-queue@^1.0.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.1.1.tgz#fef65ce3ac9f8a32ceac5a634f74e17e5b232110" integrity sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g== +zrender@5.6.1: + version "5.6.1" + resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.6.1.tgz#e08d57ecf4acac708c4fcb7481eb201df7f10a6b" + integrity sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag== + dependencies: + tslib "2.3.0" + zwitch@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.4.tgz#c827d4b0acb76fc3e685a4c6ec2902d51070e9d7" From 284990d095d01783077910a4aef6083b5ec23a2c Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Tue, 8 Apr 2025 19:45:25 +0100 Subject: [PATCH 2/5] code widget --- docs/cloud/manage/dashboards.md | 2 +- .../managing-data/core-concepts/partitions.md | 75 ++++--------------- src/components/CodeViewer/CodeResults.tsx | 24 +++++- src/components/CodeViewer/index.tsx | 54 ++++++++++--- src/css/custom.scss | 44 +---------- src/theme/CodeBlock/index.js | 42 +++++++++-- static/images/loading.svg | 6 +- 7 files changed, 121 insertions(+), 126 deletions(-) diff --git a/docs/cloud/manage/dashboards.md b/docs/cloud/manage/dashboards.md index ff2783f260c..8c38059d81e 100644 --- a/docs/cloud/manage/dashboards.md +++ b/docs/cloud/manage/dashboards.md @@ -2,7 +2,7 @@ sidebar_label: 'Dashboards' slug: /cloud/manage/dashboards title: 'Dashboards' -description: 'The SQL Console's dashboards feature allows you to collect and share visualizations from saved queries.' +description: 'The SQL Console dashboards feature allows you to collect and share visualizations from saved queries.' --- import BetaBadge from '@theme/badges/BetaBadge'; diff --git a/docs/managing-data/core-concepts/partitions.md b/docs/managing-data/core-concepts/partitions.md index d43499970ff..38dc6cdb91c 100644 --- a/docs/managing-data/core-concepts/partitions.md +++ b/docs/managing-data/core-concepts/partitions.md @@ -24,8 +24,7 @@ Partitioning can be enabled when a table is initially defined via the [PARTITION To illustrate this, we [enhance](https://sql.clickhouse.com/?query=U0hPVyBDUkVBVEUgVEFCTEUgdWsudWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQ&run_query=true&tab=results) the [What are table parts](/parts) example table by adding a `PARTITION BY toStartOfMonth(date)` clause, which organizes the table`s data parts based on the months of property sales: - -```sql runnable=true view=chart show_statistics=false +```sql CREATE TABLE uk.uk_price_paid_simple_partitioned ( date Date, @@ -67,26 +66,15 @@ As sketched in the diagram above, parts belonging to different partitions are ne You can [query](https://sql.clickhouse.com/?query=U0VMRUNUIERJU1RJTkNUIF9wYXJ0aXRpb25fdmFsdWUgQVMgcGFydGl0aW9uCkZST00gdWsudWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQKT1JERVIgQlkgcGFydGl0aW9uIEFTQw&run_query=true&tab=results) the list of all existing unique partitions of our example table by using the [virtual column](/engines/table-engines#table_engines-virtual_columns) `_partition_value`: -```sql +```sql runnable SELECT DISTINCT _partition_value AS partition FROM uk.uk_price_paid_simple_partitioned ORDER BY partition ASC; - - - ┌─partition──────┐ - 1. │ ('1995-01-01') │ - 2. │ ('1995-02-01') │ - 3. │ ('1995-03-01') │ - ... -304. │ ('2021-04-01') │ -305. │ ('2021-05-01') │ -306. │ ('2021-06-01') │ - └────────────────┘ ``` Alternatively, ClickHouse tracks all parts and partitions of all tables in the [system.parts](/operations/system-tables/parts) system table, and the following query [returns](https://sql.clickhouse.com/?query=U0VMRUNUCiAgICBwYXJ0aXRpb24sCiAgICBjb3VudCgpIEFTIHBhcnRzLAogICAgc3VtKHJvd3MpIEFTIHJvd3MKRlJPTSBzeXN0ZW0ucGFydHMKV0hFUkUgKGRhdGFiYXNlID0gJ3VrJykgQU5EIChgdGFibGVgID0gJ3VrX3ByaWNlX3BhaWRfc2ltcGxlX3BhcnRpdGlvbmVkJykgQU5EIGFjdGl2ZQpHUk9VUCBCWSBwYXJ0aXRpb24KT1JERVIgQlkgcGFydGl0aW9uIEFTQzs&run_query=true&tab=results) for our example table above the list of all partitions, plus the current number of active parts and the sum of rows in these parts per partition: -```sql +```sql runnable SELECT partition, count() AS parts, @@ -95,17 +83,6 @@ FROM system.parts WHERE (database = 'uk') AND (`table` = 'uk_price_paid_simple_partitioned') AND active GROUP BY partition ORDER BY partition ASC; - - - ┌─partition──┬─parts─┬───rows─┐ - 1. │ 1995-01-01 │ 1 │ 50473 │ - 2. │ 1995-02-01 │ 1 │ 50840 │ - 3. │ 1995-03-01 │ 1 │ 71276 │ - ... -304. │ 2021-04-01 │ 3 │ 23160 │ -305. │ 2021-05-01 │ 3 │ 17607 │ -306. │ 2021-06-01 │ 3 │ 5652 │ - └─partition──┴─parts─┴───rows─┘ ``` @@ -152,20 +129,12 @@ TTL date + INTERVAL 12 MONTH TO VOLUME 'slow_but_cheap'; Partitions can assist with query performance, but this depends heavily on the access patterns. If queries target only a few partitions (ideally one), performance can potentially improve. This is only typically useful if the partitioning key is not in the primary key and you are filtering by it, as shown in the example query below. -```sql +```sql runnable SELECT MAX(price) AS highest_price -FROM uk_price_paid_simple_partitioned +FROM uk.uk_price_paid_simple_partitioned WHERE date >= '2020-12-01' AND date <= '2020-12-31' AND town = 'LONDON'; - - - ┌─highest_price─┐ -1. │ 296280000 │ -- 296.28 million - └───────────────┘ - -1 row in set. Elapsed: 0.006 sec. Processed 8.19 thousand rows, 57.34 KB (1.36 million rows/s., 9.49 MB/s.) -Peak memory usage: 2.73 MiB. ``` The query runs over our example table from above and [calculates](https://sql.clickhouse.com/?query=U0VMRUNUIE1BWChwcmljZSkgQVMgaGlnaGVzdF9wcmljZQpGUk9NIHVrLnVrX3ByaWNlX3BhaWRfc2ltcGxlX3BhcnRpdGlvbmVkCldIRVJFIGRhdGUgPj0gJzIwMjAtMTItMDEnCiAgQU5EIGRhdGUgPD0gJzIwMjAtMTItMzEnCiAgQU5EIHRvd24gPSAnTE9ORE9OJzs&run_query=true&tab=results) the highest price of all sold properties in London in December 2020 by filtering on both a column (`date`) used in the table's partition key and on a column (`town`) used in the table's primary key (and `date` is not part of the primary key). @@ -182,10 +151,10 @@ ClickHouse processes that query by applying a sequence of pruning techniques to We can observe these data pruning steps by [inspecting](https://sql.clickhouse.com/?query=RVhQTEFJTiBpbmRleGVzID0gMQpTRUxFQ1QgTUFYKHByaWNlKSBBUyBoaWdoZXN0X3ByaWNlCkZST00gdWsudWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQKV0hFUkUgZGF0ZSA-PSAnMjAyMC0xMi0wMScKICBBTkQgZGF0ZSA8PSAnMjAyMC0xMi0zMScKICBBTkQgdG93biA9ICdMT05ET04nOw&run_query=true&tab=results) the physical query execution plan for our example query from above via an [EXPLAIN](/sql-reference/statements/explain) clause : -```sql +```sql style="fontSize:13px" EXPLAIN indexes = 1 SELECT MAX(price) AS highest_price -FROM uk_price_paid_simple_partitioned +FROM uk.uk_price_paid_simple_partitioned WHERE date >= '2020-12-01' AND date <= '2020-12-31' AND town = 'LONDON'; @@ -240,23 +209,18 @@ With partitioning, the data is usually distributed across more data parts, which We can demonstrate this by running the same query over both the [What are table parts](/parts) example table (without partitioning enabled), and our current example table from above (with partitioning enabled). Both tables [contain](https://sql.clickhouse.com/?query=U0VMRUNUCiAgICB0YWJsZSwKICAgIHN1bShyb3dzKSBBUyByb3dzCkZST00gc3lzdGVtLnBhcnRzCldIRVJFIChkYXRhYmFzZSA9ICd1aycpIEFORCAoYHRhYmxlYCBJTiBbJ3VrX3ByaWNlX3BhaWRfc2ltcGxlJywgJ3VrX3ByaWNlX3BhaWRfc2ltcGxlX3BhcnRpdGlvbmVkJ10pIEFORCBhY3RpdmUKR1JPVVAgQlkgdGFibGU7&run_query=true&tab=results) the same data and number of rows: -```sql +```sql runnable SELECT table, sum(rows) AS rows FROM system.parts WHERE (database = 'uk') AND (table IN ['uk_price_paid_simple', 'uk_price_paid_simple_partitioned']) AND active GROUP BY table; - - ┌─table────────────────────────────┬─────rows─┐ -1. │ uk_price_paid_simple │ 25248433 │ -2. │ uk_price_paid_simple_partitioned │ 25248433 │ - └──────────────────────────────────┴──────────┘ ``` However, the table with partitions enabled, [has](https://sql.clickhouse.com/?query=U0VMRUNUCiAgICB0YWJsZSwKICAgIGNvdW50KCkgQVMgcGFydHMKRlJPTSBzeXN0ZW0ucGFydHMKV0hFUkUgKGRhdGFiYXNlID0gJ3VrJykgQU5EIChgdGFibGVgIElOIFsndWtfcHJpY2VfcGFpZF9zaW1wbGUnLCAndWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQnXSkgQU5EIGFjdGl2ZQpHUk9VUCBCWSB0YWJsZTs&run_query=true&tab=results) more active [data parts](/parts), because, as mentioned above, ClickHouse only [merges](/parts) data parts within, but not across partitions: -```sql +```sql runnable SELECT table, count() AS parts @@ -264,13 +228,8 @@ FROM system.parts WHERE (database = 'uk') AND (table IN ['uk_price_paid_simple', 'uk_price_paid_simple_partitioned']) AND active GROUP BY table; - - ┌─table────────────────────────────┬─parts─┐ -1. │ uk_price_paid_simple │ 1 │ -2. │ uk_price_paid_simple_partitioned │ 436 │ - └──────────────────────────────────┴───────┘ ``` -As shown further above, the partitioned table `uk_price_paid_simple_partitioned` has 306 partitions, and therefore at least 306 active data parts. Whereas for our non-partitioned table `uk_price_paid_simple` all [initial](/parts) data parts could be merged into a single active part by background merges. +As shown further above, the partitioned table `uk_price_paid_simple_partitioned` has over 600 partitions, and therefore at 600 306 active data parts. Whereas for our non-partitioned table `uk_price_paid_simple` all [initial](/parts) data parts could be merged into a single active part by background merges. When we [check](https://sql.clickhouse.com/?query=RVhQTEFJTiBpbmRleGVzID0gMQpTRUxFQ1QgTUFYKHByaWNlKSBBUyBoaWdoZXN0X3ByaWNlCkZST00gdWsudWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQKV0hFUkUgdG93biA9ICdMT05ET04nOw&run_query=true&tab=results) the physical query execution plan with an [EXPLAIN](/sql-reference/statements/explain) clause for our example query from above without the partition filter running over the partitioned table, we can see in row 19 and 20 of the output below that ClickHouse identified 671 out of 3257 existing [granules](/guides/best-practices/sparse-primary-indexes#data-is-organized-into-granules-for-parallel-data-processing) (blocks of rows) spread over 431 out of 436 existing active data parts that potentially contain rows matching the query's filter, and therefore will be scanned and processed by the query engine: @@ -338,10 +297,9 @@ SELECT MAX(price) AS highest_price FROM uk.uk_price_paid_simple_partitioned WHERE town = 'LONDON'; - - ┌─highest_price─┐ -1. │ 594300000 │ -- 594.30 million - └───────────────┘ +┌─highest_price─┐ +│ 594300000 │ -- 594.30 million +└───────────────┘ 1 row in set. Elapsed: 0.090 sec. Processed 5.48 million rows, 27.95 MB (60.66 million rows/s., 309.51 MB/s.) Peak memory usage: 163.44 MiB. @@ -355,10 +313,9 @@ SELECT MAX(price) AS highest_price FROM uk.uk_price_paid_simple WHERE town = 'LONDON'; - - ┌─highest_price─┐ -1. │ 594300000 │ -- 594.30 million - └───────────────┘ +┌─highest_price─┐ +│ 594300000 │ -- 594.30 million +└───────────────┘ 1 row in set. Elapsed: 0.012 sec. Processed 1.97 million rows, 9.87 MB (162.23 million rows/s., 811.17 MB/s.) Peak memory usage: 62.02 MiB. diff --git a/src/components/CodeViewer/CodeResults.tsx b/src/components/CodeViewer/CodeResults.tsx index a57a3264228..9765c04666f 100644 --- a/src/components/CodeViewer/CodeResults.tsx +++ b/src/components/CodeViewer/CodeResults.tsx @@ -13,6 +13,7 @@ import Chart from './charts' import copyGridElements from './copy/copyGridElements' import { ChartConfig, ChartType, QueryResults } from './types' import LoadingSVG from '@site/static/images/loading.svg' +import { useColorMode } from '@docusaurus/theme-common' export enum DefaultView { Chart = 'chart', @@ -41,11 +42,14 @@ const Loading: React.FC = ({ position = Position.Start, className = '' }) => { + const { colorMode } = useColorMode() + const strokeColor = colorMode === 'light' ? '#000000' : '#FAFF69' + return (
- - Loading + +   Loading
) @@ -87,6 +91,7 @@ function CodeResults(props: ResultsProps) { const response = props.results?.response const error = props.results?.error const gridRef = useRef(null) + const { colorMode } = useColorMode(); // 'light' or 'dark' const isNumeric = (columnType: string) => { return columnType.startsWith('UInt') || columnType.startsWith('Int') || columnType.startsWith('Float') || columnType.startsWith('Decimal'); @@ -178,8 +183,19 @@ function CodeResults(props: ResultsProps) { if (isNumeric(columnType) && response && response.data.length > 1) { const ratio = value ? 100 * Number(value) / Number(extreme[columnName].max) : 100; - const bgColor = rowIndex === selectedCell.row? "lch(15.8 0 0)" : "#1f201b"; - const background = `linear-gradient(to right, #35372f 0%, #35372f ${ratio}%, ${bgColor} ${ratio}%, ${bgColor} 100%)` + const bgColor = + colorMode === 'light' + ? rowIndex === selectedCell.row + ? '#f0f0f0' + : '#ffffff' + : rowIndex === selectedCell.row + ? 'lch(15.8 0 0)' + : '#1f201b' + + const barColor = colorMode === 'light' ? '#d2d2d2' : '#35372f' + + const background = `linear-gradient(to right, ${barColor} 0%, ${barColor} ${ratio}%, ${bgColor} ${ratio}%, ${bgColor} 100%)` + return ( { + const [key, value] = item.split(':').map(str => str.trim()) + if (key && value) { + const camelKey = key.replace(/-([a-z])/g, (_, char) => char.toUpperCase()) + acc[camelKey] = value + } + return acc + }, {} as React.CSSProperties) + } + return {} +} + function CodeViewer({ node, inline, className, language = 'sql', - show_line_numbers = 'false', - runnable = false, - run = false, + show_line_numbers = false, + runnable = 'false', + run = 'false', link, view = 'table', chart_config = '', clickhouse_settings = '{}', - show_statistics = true, + show_statistics = 'true', + style = '', + title='', children, ...props }: any) { const showLineNumbers = show_line_numbers === 'true' const runBoolean = run === 'true' const runnableBoolean = runnable === 'true' + const showStatistics = show_statistics === 'true' + let chart: { type: ChartType; config?: ChartConfig } | undefined try { - const parsedChart = JSON.parse(base64Decode(chart_config)) + const parsedChart = JSON.parse(chart_config !== '' ? base64Decode(chart_config) : '{}') if (parsedChart && parsedChart.type && parsedChart.config) { chart = { type: parsedChart.type as ChartType, @@ -52,18 +70,30 @@ function CodeViewer({ console.log('chart config is not valid') } const { colorMode } = useColorMode(); // returns 'light' or 'dark' - console.log(children.props.children) + const extraStyle = parseInlineStyle(style) + const combinedStyle:React.CSSProperties = { + wordBreak: 'break-word', + ...extraStyle + } + const header = title ? ( + <> + {title} + + + ): null return ( -
+
- + { header } {typeof children === 'string' ? children : getCodeContent(children)} @@ -76,7 +106,7 @@ function CodeViewer({ view={chart ? view : DefaultView.Table} chart={chart} settings={clickhouse_settings} - show_statistics={show_statistics} + show_statistics={showStatistics} />
diff --git a/src/css/custom.scss b/src/css/custom.scss index f0ea947426d..66d222f4532 100644 --- a/src/css/custom.scss +++ b/src/css/custom.scss @@ -228,48 +228,12 @@ html { font-size: 16px; } -code { - background-color: var(--ifm-code-background); - scrollbar-width: thin; - scrollbar-color: rgb(99, 99, 99) rgb(41, 45, 62); - span { - font-style: normal !important; - } -} - -/* Style individual tokens */ -code .token.keyword { - font-style: italic !important; /* Italicize keywords */ - color: rgb(86, 156, 214) !important; /* Blue for keywords */ -} - -code .token.plain { - color: rgb(156, 220, 254) !important; -} - -code .token.punctuation { - color: rgb(199, 146, 234) !important; /* Match punctuation color */ -} - -code .token.operator { - color: rgb(137, 221, 255) !important; /* Light blue for operators */ -} - -code .token.string { - color: rgb(206, 145, 120) !important; /* Orange for strings */ -} - -code .token.number { - color: rgb(181, 206, 168) !important; /* Green for numbers */ -} - -code .token.function { - color: rgb(220, 220, 170) !important; /* Bright blue for functions */ +.code-viewer pre { + font-size: inherit !important; } -/* Ensure keywords are not italic */ -code span.token.keyword { - font-style: normal !important; +.code-viewer pre code { + font-size: inherit !important; } .markdown h1:first-child { diff --git a/src/theme/CodeBlock/index.js b/src/theme/CodeBlock/index.js index dcfed629d68..28629d840b5 100644 --- a/src/theme/CodeBlock/index.js +++ b/src/theme/CodeBlock/index.js @@ -1,6 +1,7 @@ import React, {useState, useRef, useCallback, useEffect} from 'react'; -import CodeBlock from '@theme-original/CodeBlock'; import styles from './styles.module.css'; +import CodeViewer from "../../components/CodeViewer"; + function countLines(text) { // Split the string by newline characters @@ -8,6 +9,30 @@ function countLines(text) { // Return the number of lines return lines.length; } + +function parseMetaString(meta = '') { + const result = {} + const implicit_settings = ['runnable', 'run', 'show_statistics'] + + meta.split(' ').forEach((part) => { + if (!part) return + + const [rawKey, ...rawValueParts] = part.split('=') + const key = rawKey?.trim() + const rawValue = rawValueParts.join('=').trim() + + if (key && rawValue) { + // Remove surrounding single or double quotes if present + const cleanedValue = rawValue.replace(/^['"]|['"]$/g, '') + result[key] = cleanedValue + } else if (key && implicit_settings.includes(key)) { + result[key] = 'true' + } + }) + + return result +} + export default function CodeBlockWrapper(props) { const lineHeight = 18.85; const [isLoaded, setIsLoaded] = useState(false); @@ -46,10 +71,15 @@ export default function CodeBlockWrapper(props) {
); } - console.log(props) - return ( - <> - - + + + const settings = parseMetaString(props.metastring); + settings['language'] = props.className ? props.className.replace('language-', ''): 'txt'; + return ( + <> + + {props.children} + + ); } diff --git a/static/images/loading.svg b/static/images/loading.svg index 13f6cad7bac..821632dce66 100644 --- a/static/images/loading.svg +++ b/static/images/loading.svg @@ -1,7 +1,5 @@ - - + From 109c27d5de9b5a6926d5f8e3bc412d2e9b63e55f Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Wed, 9 Apr 2025 10:59:37 +0100 Subject: [PATCH 3/5] use old code --- docs/quick-start.mdx | 2 +- docusaurus.config.en.js | 2 +- src/components/CodeViewer/index.tsx | 60 +-- src/css/custom.scss | 119 +++++- .../CodeBlock/Container/styles.module.css | 8 - src/theme/CodeBlock/index.js | 4 +- tailwind.config.js | 378 ------------------ 7 files changed, 154 insertions(+), 419 deletions(-) diff --git a/docs/quick-start.mdx b/docs/quick-start.mdx index e78b8082f0f..f5da552e1db 100644 --- a/docs/quick-start.mdx +++ b/docs/quick-start.mdx @@ -138,7 +138,7 @@ ORDER BY timestamp ``` Notice the response comes back in a nice table format: -```response +```text ┌─user_id─┬─message────────────────────────────────────────────┬───────────timestamp─┬──metric─┐ │ 102 │ Insert a lot of rows per batch │ 2022-03-21 00:00:00 │ 1.41421 │ │ 102 │ Sort your data based on your commonly-used queries │ 2022-03-22 00:00:00 │ 2.718 │ diff --git a/docusaurus.config.en.js b/docusaurus.config.en.js index 3aa26d0e5e4..2e59baf3afe 100644 --- a/docusaurus.config.en.js +++ b/docusaurus.config.en.js @@ -287,7 +287,7 @@ const config = { prism: { theme: themes.darkTheme, darkTheme: themes.darkTheme, - additionalLanguages: ["java", "cpp", "rust"], + additionalLanguages: ["java", "cpp", "rust", "python"], magicComments: [ // Remember to extend the default highlight class name as well! { diff --git a/src/components/CodeViewer/index.tsx b/src/components/CodeViewer/index.tsx index 7eda5fa371c..1f6651d391e 100644 --- a/src/components/CodeViewer/index.tsx +++ b/src/components/CodeViewer/index.tsx @@ -5,6 +5,7 @@ import { ChartConfig, ChartType } from './types' import { base64Decode } from './utils' import { useColorMode } from '@docusaurus/theme-common' import { isValidElement } from 'react' +import DocusaurusCodeBlock from '@theme-original/CodeBlock'; function getCodeContent(children: any): string { if (typeof children === 'string') return children @@ -49,6 +50,7 @@ function CodeViewer({ show_statistics = 'true', style = '', title='', + click_ui = 'false', children, ...props }: any) { @@ -78,36 +80,44 @@ function CodeViewer({ const header = title ? ( <> {title} - ): null + + const code_block = click_ui === 'true' ? ( + + {typeof children === 'string' ? children : getCodeContent(children)} + + ): ( + + ) + const results = runnable ? ( + + ): null + return ( -
+
{ header } - - {typeof children === 'string' ? children : getCodeContent(children)} - - - + { code_block } + { results }
diff --git a/src/css/custom.scss b/src/css/custom.scss index 66d222f4532..08bb1920800 100644 --- a/src/css/custom.scss +++ b/src/css/custom.scss @@ -228,12 +228,123 @@ html { font-size: 16px; } -.code-viewer pre { - font-size: inherit !important; +/* === Base styles === */ +code { + font-weight: bold; + font-size: 0.95em; + border-radius: 0; + padding: 0.15em 0.35em; + scrollbar-width: thin; + scrollbar-color: rgb(99, 99, 99) rgb(41, 45, 62); +} + +/* Normalize inner span styles */ +code span { + font-style: normal !important; +} + +/* === Theme-specific inline backgrounds === */ +html[data-theme='dark'] pre, +html[data-theme='dark'] pre code, +html[data-theme='dark'] code { + background: none !important; + background-color: #292D3E !important; + box-shadow: none !important; + filter: none !important; + border: none !important; +} + +html[data-theme='light'] code { + background-color: #f5f5f5 !important; + color: #000 !important; +} + +/* === Block code (pre) === */ +pre { + padding: 1rem; + border-radius: 0 !important; +} + +html[data-theme='light'] pre, +html[data-theme='light'] pre code { + background-color: #f5f5f5 !important; + color: #000 !important; +} + +html[data-theme='dark'] pre, +html[data-theme='dark'] pre code { + background-color: #292D3E !important; + color: var(--prism-color); +} + +/* === Prism token styles (Dark Theme) === */ +code .token.keyword { + font-style: italic !important; + color: rgb(86, 156, 214) !important; +} + +code .token.plain { + color: rgb(156, 220, 254) !important; +} + +code .token.punctuation { + color: rgb(199, 146, 234) !important; +} + +code .token.operator { + color: rgb(137, 221, 255) !important; +} + +code .token.string { + color: rgb(206, 145, 120) !important; +} + +code .token.number { + color: rgb(181, 206, 168) !important; +} + +code .token.function { + color: rgb(220, 220, 170) !important; +} + +/* === Prism token styles (Light Theme) === */ +html[data-theme='light'] code .token.keyword { + font-style: italic !important; + color: rgb(0, 92, 154) !important; +} + +html[data-theme='light'] code .token.plain { + color: rgb(36, 41, 46) !important; +} + +html[data-theme='light'] code .token.identifier { + color: rgb(0, 102, 204) !important; +} + +html[data-theme='light'] code .token.punctuation { + color: rgb(125, 86, 148) !important; +} + +html[data-theme='light'] code .token.operator { + color: rgb(0, 112, 138) !important; +} + +html[data-theme='light'] code .token.string { + color: rgb(163, 21, 21) !important; +} + +html[data-theme='light'] code .token.number { + color: rgb(34, 134, 58) !important; +} + +html[data-theme='light'] code .token.function { + color: rgb(88, 92, 63) !important; } -.code-viewer pre code { - font-size: inherit !important; +/* Ensure keywords are not italic if nested */ +html[data-theme='light'] code span.token.keyword, +code span.token.keyword { + font-style: normal !important; } .markdown h1:first-child { diff --git a/src/theme/CodeBlock/Container/styles.module.css b/src/theme/CodeBlock/Container/styles.module.css index 61e40e38ad6..f3b27fb155e 100644 --- a/src/theme/CodeBlock/Container/styles.module.css +++ b/src/theme/CodeBlock/Container/styles.module.css @@ -1,11 +1,3 @@ .codeBlockContainer { - background: var(--prism-background-color); - color: var(--prism-color); - margin-bottom: var(--ifm-leading); - box-shadow: var(--ifm-global-shadow-lw); - border-radius: var(--ifm-code-border-radius); - --ifm-code-background: var(--prism-background-color); - --ifm-pre-color: var(--prism-color); - overflow-x: scroll; } diff --git a/src/theme/CodeBlock/index.js b/src/theme/CodeBlock/index.js index 28629d840b5..b8f76b0c582 100644 --- a/src/theme/CodeBlock/index.js +++ b/src/theme/CodeBlock/index.js @@ -12,7 +12,7 @@ function countLines(text) { function parseMetaString(meta = '') { const result = {} - const implicit_settings = ['runnable', 'run', 'show_statistics'] + const implicit_settings = ['runnable', 'run', 'show_statistics', 'click_ui'] meta.split(' ').forEach((part) => { if (!part) return @@ -72,7 +72,7 @@ export default function CodeBlockWrapper(props) { ); } - + const settings = parseMetaString(props.metastring); settings['language'] = props.className ? props.className.replace('language-', ''): 'txt'; return ( diff --git a/tailwind.config.js b/tailwind.config.js index 3621c02815d..42db927db97 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -23,384 +23,6 @@ module.exports = { '2xl': '1536px', '3xl': '2200px' }, - extend: { - typography: ({ theme }) => ({ - neutral: { - css: { - '--tw-prose-body': theme('colors.neutral[200]'), - '--tw-prose-headings': theme('colors.neutral[100]'), - '--tw-prose-lead': theme('colors.neutral[700]'), - '--tw-prose-links': theme('colors.primary[300]'), - '--tw-prose-bold': theme('colors.neutral[200]'), - '--tw-prose-counters': theme('colors.neutral[200]'), - '--tw-prose-bullets': theme('colors.neutral[200]'), - '--tw-prose-hr': theme('colors.neutral[300]'), - '--tw-prose-quotes': theme('colors.neutral[900]'), - '--tw-prose-quote-borders': theme('colors.neutral[300]'), - '--tw-prose-captions': theme('colors.neutral[700]'), - '--tw-prose-code': theme('colors.neutral[900]'), - '--tw-prose-pre-code': theme('colors.neutral[100]'), - '--tw-prose-pre-bg': theme('colors.neutral[900]'), - '--tw-prose-th-borders': theme('colors.neutral[300]'), - '--tw-prose-td-borders': theme('colors.neutral[200]'), - '--tw-prose-invert-body': theme('colors.neutral[200]'), - '--tw-prose-invert-headings': theme('colors.white'), - '--tw-prose-invert-lead': theme('colors.neutral[300]'), - '--tw-prose-invert-links': theme('colors.white'), - '--tw-prose-invert-bold': theme('colors.white'), - '--tw-prose-invert-counters': theme('colors.neutral[400]'), - '--tw-prose-invert-bullets': theme('colors.neutral[600]'), - '--tw-prose-invert-hr': theme('colors.neutral[700]'), - '--tw-prose-invert-quotes': theme('colors.neutral[100]'), - '--tw-prose-invert-quote-borders': theme('colors.neutral[700]'), - '--tw-prose-invert-captions': theme('colors.neutral[400]'), - '--tw-prose-invert-code': theme('colors.white'), - '--tw-prose-invert-pre-code': theme('colors.neutral[300]'), - '--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 50%)', - '--tw-prose-invert-th-borders': theme('colors.neutral[600]'), - '--tw-prose-invert-td-borders': theme('colors.neutral[700]') - } - } - }), - fontSize: { - '2.75xl': '1.75rem', - '5.5xl': '3.5rem', - '5.5xl': '3.5rem', - '6.5xl': '4rem', - '7.5xl': '5.25rem' - }, - fontFamily: { - inter: 'var(--font-inter), sans-serif', - inconsolata: 'var(--font-inconsolata)', - basier: 'Basier Square, Arial, Helvetica, sans-serif' - }, - colors: { - rangitoto: '#28281D', - 'base-color': '#FBFF46', - 'eerie-black': '#1A1918', - jet: '#343434', - - // Generated from: - // @link https://www.tailwindshades.com/#color=64.70588235294119%2C100%2C50&step-up=8&step-down=11&hue-shift=0&name=ch-yellow&base-stop=5&v=1&overrides=e30%3D - 'ch-yellow': { - DEFAULT: '#EBFF00', - 50: '#F9FFB8', - 100: '#F8FFA3', - 200: '#F5FF7A', - 300: '#F1FF52', - 400: '#EEFF29', - 500: '#EBFF00', - 600: '#B7C700', - 700: '#848F00', - 800: '#505700', - 900: '#1C1F00', - 950: '#020300' - }, - - // Generated from: - // @link https://www.tailwindshades.com/#color=167.21311475409837%2C100%2C11.96078431372549&step-up=7&step-down=3&hue-shift=0&name=ch-teal&base-stop=6&v=1&overrides=e30%3D - 'ch-teal': { - DEFAULT: '#003D30', - 50: '#02FFC9', - 100: '#00F0BC', - 200: '#00CCA0', - 300: '#00A884', - 400: '#008468', - 500: '#00614C', - 600: '#003D30', - 700: '#002E24', - 800: '#001E18', - 900: '#000F0C', - 950: '#000706' - }, - primary: { - DEFAULT: '#FBFF46', - 50: '#FFFFE8', - 100: '#FEFFBA', - 200: '#FDFFA3', - 300: '#FAFF69', - 400: '#EEF400', - 500: '#9FA300', - 600: '#4F5100', - 700: '#282900', - 800: '#1F2014', - 900: '#161600' - }, - neutral: { - DEFAULT: '#212121', - 0: '#FFFFFF', - 100: '#F9F9F9', - 200: '#dfdfdf', - 300: '#c0c0c0', - 400: '#a0a0a0', - 500: '#808080', - 600: '#606060', - 700: '#414141', - 725: '#282828', - 750: '#1F1F1C', - 800: '#1d1d1d', - 900: '#151515' - }, - slate: { - DEFAULT: '#373439', - 50: '#F6F7FA', - 100: '#e6e7e9', - 200: '#cccfd3', - 300: '#b3b6bd', - 400: '#9a9ea7', - 500: '#808691', - 600: '#696e79', - 700: '#53575f', - 800: '#302e32', - 900: '#161517' - }, - indigo: { - DEFAULT: '#2F2C3A', - 50: '#F4F1FC', - 100: '#e4e2e9', - 200: '#c8c5d3', - 300: '#ada8bd', - 400: '#918ba7', - 500: '#766e91', - 600: '#5e5874', - 700: '#474257', - 800: '#23212c', - 900: '#18161d' - }, - info: { - DEFAULT: '#2F2C3A', - 50: '#dae6fc', - 100: '#b5cdf9', - 200: '#91b3f6', - 300: '#6c9af3', - 400: '#135be6', - 500: '#0e44ad', - 600: '#092e73', - 700: '#061d48', - 800: '#05173a', - 900: '#041330' - }, - success: { - DEFAULT: '#62DE85', - 50: '#e0f8e7', - 100: '#c0f2ce', - 200: '#a1ebb6', - 300: '#81e59d', - 400: '#41d76b', - 500: '#2ac656', - 600: '#1c8439', - 700: '#15632b', - 800: '#0e421d', - 900: '#07210e' - }, - warning: { - DEFAULT: '#FFA63D', - 50: '#ffedd8', - 100: '#ffdbb1', - 200: '#ffca8b', - 300: '#ffb864', - 400: '#ff9416', - 500: '#ed8000', - 600: '#c66b00', - 700: '#9e5600', - 800: '#4f2b00', - 900: '#271500' - }, - danger: { - DEFAULT: '#FF5353', - 50: '#ffdddd', - 100: '#ffbaba', - 200: '#ff9898', - 300: '#ff7575', - 400: '#ff2323', - 500: '#f10000', - 600: '#c10000', - 700: '#910000', - 800: '#610000', - 900: '#300000' - }, - - // - navigation: { - background: '#212121' - }, - - c1: { - light: '#FFFFFF', - DEFAULT: 'rgba(var(--clickhouse-color-1), )', - dark: '#2F2C3A' - }, - c2: { - light: '#F6F7FA', - DEFAULT: 'rgba(var(--clickhouse-color-2), )', - dark: '#373343' - }, - c3: '#443F51', - c4: { - light: '#6D7386', - DEFAULT: 'rgba(var(--clickhouse-color-4), )', - dark: '#B0B4BC' - }, - c5: { - light: '#2F2C3A', - DEFAULT: 'rgba(var(--clickhouse-color-5), )', - dark: '#FFFFFF' - }, - c6: { - DEFAULT: '#FAFF69', - text: '#FAFF69', - link: '#C78F0F' - }, - c7: { - light: '#A6770D', - DEFAULT: 'rgba(var(--clickhouse-color-7), )', - dark: '#FFC133' - }, - gradientTop: '#FAFF69', - gradientBottom: '#EEF400', - alerts: { - danger: { - text: '#C70F0F', - background: '#FAE7E7' - }, - info: { - text: '#3B73DE', - background: '#E6F1FA' - }, - success: { - text: '#00664B', - background: '#E6F9F4' - }, - warning: { - text: '#805300', - background: '#FFF8E6' - } - } - }, - boxShadow: { - card: '0px 4px 4px rgba(0, 0, 0, 0.06), inset 0px 4px 25px rgba(0, 0, 0, 0.14)', - 'card-xl': '0px 4px 14px 4px rgba(0, 0, 0, 0.13)', - input: '0px 1px 2px rgba(0, 0, 0, 0.05)', - 'click-card': - '0px 4px 44px rgba(22, 22, 0, 0.4), inset 0px 1px 3px rgba(25, 26, 6, 0.9)', - 'click-pill': '0px -1px 5px rgba(16, 24, 40, 0.07)', - 'click-twitter': '0px 4px 48px rgba(250, 255, 72, 0.2)', - 'footer-line': '0px -1px 1px #000000', - codeblock: - '0px 4px 4px rgba(0, 0, 0, 0.06), inset 0px 4px 25px rgba(0, 0, 0, 0.14)', - header_bottom: 'inset 0px -1px 0px rgba(78, 78, 78, 0.25);', - noOffset: '0 0 100px -12px rgb(0 0 0 / 0.25)', - 'noOffset-sm': '0 0 48px rgb(0 0 0 / 0.25)', - stackIntegrationGraphic: '0 4px 60px rgb(251, 255, 70)', - stackIntegrationGraphicSmall: '0 2px 30px rgb(251, 255, 70)' - }, - backgroundSize: { - default_size: '0%, 100%', - focus_size: '100%, 100%' - }, - backgroundImage: { - 'air-gapped': 'url("/images/air-gapped.svg")', - 'half-highlight': - 'linear-gradient(to bottom, rgba(65,65,65,1) 56%, transparent 56%)', - snowflakeGradient: - 'linear-gradient(0deg, #FAFF69 30%, rgba(252, 255, 116, 0) 99.99%)', - homepageFadeLeftLogos: - 'linear-gradient(90deg, #FAFF69 30%, rgba(252, 255, 116, 0) 99.99%)', - homepageFadeRightLogos: - 'linear-gradient(270deg, #FAFF69 30%, rgba(252, 255, 116, 0) 99.99%)', - cloudFadeLeftLogos: - 'linear-gradient(90deg, #1D1D1D 30%, rgba(29, 29, 29, 0.1) 99.99%)', - cloudFadeRightLogos: - 'linear-gradient(270deg, #1D1D1D 30%, rgba(29, 29, 29, 0.09) 99.99%)', - field_focus: - 'linear-gradient(0deg, #fbff46, #fbff46 2px, transparent 0, transparent)', - navDropdown: - 'linear-gradient(to bottom, rgba(65, 65, 65, 0.3) 0px, rgba(65, 65, 65, 0.3) 1px, #282828 1px, #282828 44px, rgba(65, 65, 65, 0.3) 44px, rgba(65, 65, 65, 0.3)45px, #1F1F1C 45px, #1F1F1C 100%)', - grid: 'url("/dot_grid.svg")', - 'click-grid': 'url("/bg-grid.svg")', - 'home-grid': - 'linear-gradient(117.08deg, rgba(0, 0, 0, 0) 14.55%, rgba(22, 22, 0, 0.167461) 34.15%, rgba(47, 47, 47, 0.22751) 40.54%, rgba(22, 22, 0, 0.611327) 46.65%, #161600 95.98%), url("/bg-grid.png");', - 'speed-lines': 'url("/speed-lines.svg")', - 'speed-lines-ml': 'url("/speed-lines-ml.svg")', - calendar: 'url("/calendar.svg")', - 'body-image': 'linear-gradient(272.48deg, #292924 1.95%, #0F0F0F 100%)', - 'menu-options': - 'linear-gradient(255.48deg, rgba(41, 41, 36, 0.95) 1.95%, rgba(15, 15, 15, 0.95) 100%)' - }, - spacing: { - '30': '7.5rem' - }, - keyframes: { - enterFromRight: { - from: { opacity: 0, transform: 'translateX(200px)' }, - to: { opacity: 1, transform: 'translateX(0)' } - }, - enterFromLeft: { - from: { opacity: 0, transform: 'translateX(-200px)' }, - to: { opacity: 1, transform: 'translateX(0)' } - }, - exitToRight: { - from: { opacity: 1, transform: 'translateX(0)' }, - to: { opacity: 0, transform: 'translateX(200px)' } - }, - exitToLeft: { - from: { opacity: 1, transform: 'translateX(0)' }, - to: { opacity: 0, transform: 'translateX(-200px)' } - }, - scaleIn: { - from: { opacity: 0, transform: 'rotateX(-10deg) scale(0.9)' }, - to: { opacity: 1, transform: 'rotateX(0deg) scale(1)' } - }, - scaleOut: { - from: { opacity: 1, transform: 'rotateX(0deg) scale(1)' }, - to: { opacity: 0, transform: 'rotateX(-10deg) scale(0.95)' } - }, - fadeIn: { - from: { opacity: 0 }, - to: { opacity: 1 } - }, - fadeOut: { - from: { opacity: 1 }, - to: { opacity: 0 } - }, - marqueeLeftTransform: { - '0%': { transform: 'translateX(0%)' }, - '100%': { transform: 'translateX(-100%)' } - }, - marqueeLeftTransform2: { - '0%': { transform: 'translateX(100%)' }, - '100%': { transform: 'translateX(0%)' } - }, - loggingFadeSection1: { - '0%': { opacity: '0.05', transform: 'scale(0.9)' }, - '50%': { opacity: '0.15', transform: 'scale(1.1)' }, - '100%': { opacity: '0.05', transform: 'scale(0.9)' } - }, - loggingFadeSection2: { - '0%': { opacity: '0.05', transform: 'scale(0.9)' }, - '50%': { opacity: '0.25', transform: 'scale(1.1)' }, - '100%': { opacity: '0.05', transform: 'scale(0.9)' } - } - }, - animation: { - scaleIn: 'scaleIn 200ms ease', - scaleOut: 'scaleOut 200ms ease', - fadeIn: 'fadeIn 200ms ease', - fadeOut: 'fadeOut 200ms ease', - enterFromLeft: 'enterFromLeft 250ms ease', - enterFromRight: 'enterFromRight 250ms ease', - exitToLeft: 'exitToLeft 250ms ease', - exitToRight: 'exitToRight 250ms ease', - marqueeLeft: 'marqueeLeftTransform 75s linear infinite', - marqueeLeft2: 'marqueeLeftTransform2 75s linear infinite ', - marqueeLeft3: 'marqueeLeftTransform 90s linear infinite', - marqueeLeft4: 'marqueeLeftTransform2 90s linear infinite ', - marqueeLeft5: 'marqueeLeftTransform 190s linear infinite', - marqueeLeft6: 'marqueeLeftTransform2 190s linear infinite ', - loggingFadeSection1: 'loggingFadeSection1 5s ease-in-out infinite', - loggingFadeSection2: 'loggingFadeSection2 5s ease-in-out infinite' - } - } } } \ No newline at end of file From ac7571118f4a2abaafdc0eed7293ca9d845846d8 Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Wed, 9 Apr 2025 11:14:43 +0100 Subject: [PATCH 4/5] fix colors --- src/components/CodeViewer/index.tsx | 2 +- src/css/custom.scss | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/CodeViewer/index.tsx b/src/components/CodeViewer/index.tsx index 1f6651d391e..3058a6074d0 100644 --- a/src/components/CodeViewer/index.tsx +++ b/src/components/CodeViewer/index.tsx @@ -113,7 +113,7 @@ function CodeViewer({ ): null return ( -
+
{ header } { code_block } diff --git a/src/css/custom.scss b/src/css/custom.scss index 08bb1920800..051c4ca5ce9 100644 --- a/src/css/custom.scss +++ b/src/css/custom.scss @@ -248,7 +248,7 @@ html[data-theme='dark'] pre, html[data-theme='dark'] pre code, html[data-theme='dark'] code { background: none !important; - background-color: #292D3E !important; + background-color: #282828 !important; box-shadow: none !important; filter: none !important; border: none !important; @@ -273,7 +273,7 @@ html[data-theme='light'] pre code { html[data-theme='dark'] pre, html[data-theme='dark'] pre code { - background-color: #292D3E !important; + background-color: #282828 !important; color: var(--prism-color); } From b38ad61daa76471d0bd6e4baf72f142ef85da5fe Mon Sep 17 00:00:00 2001 From: Dale Mcdiarmid Date: Wed, 9 Apr 2025 11:18:55 +0100 Subject: [PATCH 5/5] tailwinds to other langs --- docusaurus.config.en.js | 2 +- docusaurus.config.jp.js | 3 ++- docusaurus.config.ru.js | 3 ++- docusaurus.config.zh.js | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docusaurus.config.en.js b/docusaurus.config.en.js index 2e59baf3afe..cb99578f867 100644 --- a/docusaurus.config.en.js +++ b/docusaurus.config.en.js @@ -287,7 +287,7 @@ const config = { prism: { theme: themes.darkTheme, darkTheme: themes.darkTheme, - additionalLanguages: ["java", "cpp", "rust", "python"], + additionalLanguages: ["java", "cpp", "rust", "python", "javascript"], magicComments: [ // Remember to extend the default highlight class name as well! { diff --git a/docusaurus.config.jp.js b/docusaurus.config.jp.js index ad9ba589602..6659d1cc8af 100644 --- a/docusaurus.config.jp.js +++ b/docusaurus.config.jp.js @@ -254,7 +254,7 @@ const config = { prism: { theme: themes.darkTheme, darkTheme: themes.darkTheme, - additionalLanguages: ["java", "cpp", "rust"], + additionalLanguages: ["java", "cpp", "rust", "python", "javascript"], magicComments: [ // Remember to extend the default highlight class name as well! { @@ -292,6 +292,7 @@ const config = { }, ], chHeader, + ['./plugins/tailwind-config.js', {}], ], customFields: { blogSidebarLink: "/docs/knowledgebase", // Used for KB article page diff --git a/docusaurus.config.ru.js b/docusaurus.config.ru.js index 04dafb79646..296dd6ae3cd 100644 --- a/docusaurus.config.ru.js +++ b/docusaurus.config.ru.js @@ -265,7 +265,7 @@ const config = { prism: { theme: themes.darkTheme, darkTheme: themes.darkTheme, - additionalLanguages: ["java", "cpp", "rust"], + additionalLanguages: ["java", "cpp", "rust", "python", "javascript"], magicComments: [ // Remember to extend the default highlight class name as well! { @@ -309,6 +309,7 @@ const config = { }, ], chHeader, + ['./plugins/tailwind-config.js', {}], ], customFields: { blogSidebarLink: "/docs/knowledgebase", // Used for KB article page diff --git a/docusaurus.config.zh.js b/docusaurus.config.zh.js index 7c83ababc9e..6ffc38e7a45 100644 --- a/docusaurus.config.zh.js +++ b/docusaurus.config.zh.js @@ -254,7 +254,7 @@ const config = { prism: { theme: themes.darkTheme, darkTheme: themes.darkTheme, - additionalLanguages: ["java", "cpp", "rust"], + additionalLanguages: ["java", "cpp", "rust", "python", "javascript"], magicComments: [ // Remember to extend the default highlight class name as well! { @@ -292,6 +292,7 @@ const config = { }, ], chHeader, + ['./plugins/tailwind-config.js', {}], ], customFields: { blogSidebarLink: "/docs/knowledgebase", // Used for KB article page