diff --git a/components/ParameterBox.tsx b/components/ParameterBox.tsx new file mode 100644 index 0000000..3261d36 --- /dev/null +++ b/components/ParameterBox.tsx @@ -0,0 +1,71 @@ +import React, { useState } from "react"; +import { ParameterDetail } from "../utils/types"; +import { Box, Paper, Typography, IconButton } from "@mui/material"; +import { Link } from "@mui/icons-material"; +import { useTheme } from "@mui/material/styles"; + +export const ParameterBox: React.FC<{ parameter: ParameterDetail }> = ({ parameter }) => { + + const [hover, setHover] = useState(false); + const parts = parameter.name.split('.'); + const groupName = parts.length > 1 ? parts.slice(0, -1).join('.') : null; + const parameterName = parts.length > 1 ? parts[parts.length - 1] : parameter.name; + const parameterId = parameter.name.replace(".", "-") + const theme = useTheme(); + + return ( + setHover(true)} + onMouseLeave={() => setHover(false)} + onClick={async () => { + // Copy link to clipboard + const url = new URL(window.location.href); + url.hash = parameterId; + await navigator.clipboard.writeText(url.toString()); + }} + > + + + + + {parameterName} + + {hover && ( + + + + )} + + {/* If groupName exists, display it on a separate line */} + {groupName && ( + + {groupName} + + )} + + + {parameter.description} + + + {parameter.components && ( + + Components: [{parameter.components.join(", ")}] + + )} + + Type: {parameter.type} + + + Default: {parameter.default === "" ? '""' : parameter.default.toString()} + + + + + ); + }; \ No newline at end of file diff --git a/components/ParameterChips.tsx b/components/ParameterChips.tsx new file mode 100644 index 0000000..c47e202 --- /dev/null +++ b/components/ParameterChips.tsx @@ -0,0 +1,38 @@ +import { Chip, Stack, Divider, Typography, Box } from "@mui/material"; +import { parameterGroups } from "../utils/types"; +import ClearIcon from '@mui/icons-material/Clear'; + +interface ParameterChipsProps { + handleClick: (group: string) => void; +} + +export const ParameterChips: React.FC = ({handleClick}) => { + return ( + + Filter by component + } + sx={{ marginBottom: 2 }} + justifyContent={"center"} + > + {parameterGroups.map((component, index) => ( + handleClick(component)} + /> + ))} + handleClick("")} + icon={} + /> + + + ); +}; \ No newline at end of file diff --git a/components/Parameters.tsx b/components/Parameters.tsx index efabc53..2884a97 100644 --- a/components/Parameters.tsx +++ b/components/Parameters.tsx @@ -1,142 +1,108 @@ -import { Box, Paper, Typography, Autocomplete, TextField, Divider, IconButton} from '@mui/material'; -import {Link} from "@mui/icons-material"; +import { Box, Typography, Autocomplete, TextField, Divider, IconButton} from '@mui/material'; import React, {useState, useMemo} from "react"; +import { ParametersArray, ParameterDetail } from "../utils/types"; +import { ParameterBox } from "./ParameterBox"; +import { ParameterChips } from './ParameterChips'; +import { Link } from "@mui/icons-material"; +import { DarkLightContainer } from '@/utils/darkLightContainer'; -interface ParameterDetail { - components: string[]; - default: boolean | string; - description: string; - name: string; - type: string; - } - -interface Parameter { - [key: string]: ParameterDetail; - } - -type ParametersArray = Parameter[]; - -const ParameterBox: React.FC<{ parameter: ParameterDetail }> = ({ parameter }) => { - +const Parameters: React.FC<{ parameters: ParametersArray }> = ({ parameters }) => { + const [searchValue, setSearchValue] = useState(''); + const [selectedComponent, setSelectedComponent] = useState(null); const [hover, setHover] = useState(false); - const parts = parameter.name.split('.'); - const groupName = parts.length > 1 ? parts.slice(0, -1).join('.') : null; - const parameterName = parts.length > 1 ? parts[parts.length - 1] : parameter.name; - const parameterId = parameter.name.replace(".", "-") + const filteredParameters = useMemo(() => { + const searchLower = searchValue.toLowerCase(); + return parameters.filter((parameter) => { + const parameterName = Object.keys(parameter)[0].toLowerCase(); + const detail = Object.values(parameter)[0]; + // Ensure detail.components is defined and is an array before calling includes. + const isComponentMatch = selectedComponent ? (Array.isArray(detail.components) && detail.components.includes(selectedComponent)) : true; + return parameterName.includes(searchLower) && isComponentMatch; + }); + }, [searchValue, parameters, selectedComponent]); + + const groupedParameters = useMemo(() => { + const groups: { [key: string]: ParameterDetail[] } = {}; + filteredParameters.forEach((param) => { + const detail = Object.values(param)[0]; + const parent = detail.name.split('.').slice(0, -1).join('.'); + const group = parent || ''; + + if (!groups[group]) { + groups[group] = []; + } + groups[group].push(detail); + }); + return groups; + }, [filteredParameters]); return ( - + + Object.keys(param)[0])} + onInputChange={(_, value) => setSearchValue(value)} + sx={{ marginBottom: 2 }} + fullWidth={true} + freeSolo + renderInput={(params) => ( + setSearchValue(event.target.value)} + /> + )} + /> + { + setSelectedComponent(component); + setSearchValue(''); + }} /> + {Object.entries(groupedParameters).map(([group, groupParams]) => ( + setHover(true)} onMouseLeave={() => setHover(false)} onClick={async () => { // Copy link to clipboard const url = new URL(window.location.href); - url.hash = parameterId; - await navigator.clipboard.writeText(url); + url.hash = group + await navigator.clipboard.writeText(url.toString()); }} - > - - - - - {parameterName} - - {hover && ( - - - - )} - - {/* If groupName exists, display it on a separate line */} - {groupName && ( - - {groupName} - + > + + {group} + {hover && group && group !== "" && ( + + + )} - - - {parameter.description} - - {parameter.components && ( - - Components: [{parameter.components.join(", ")}] - - )} - - Type: {parameter.type} - - - Default: {parameter.default === "" ? '""' : parameter.default.toString()} - - - - - ); - }; - - const Parameters: React.FC<{ parameters: ParametersArray }> = ({ parameters }) => { - const [searchValue, setSearchValue] = useState(''); - - const filteredParameters = useMemo(() => { - const searchLower = searchValue.toLowerCase(); - return parameters.filter((parameter) => { - const parameterName = Object.keys(parameter)[0].toLowerCase(); - return parameterName.includes(searchLower); - }); - }, [searchValue, parameters]); - - const groupedParameters = useMemo(() => { - const groups: { [key: string]: ParameterDetail[] } = {}; - filteredParameters.forEach((param) => { - const detail = Object.values(param)[0]; - const parent = detail.name.split('.').slice(0, -1).join('.'); - const group = parent || ''; - - if (!groups[group]) { - groups[group] = []; - } - groups[group].push(detail); - }); - return groups; - }, [filteredParameters]); - - return ( - - Object.keys(param)[0])} - onInputChange={(_, value) => setSearchValue(value)} - sx={{marginBottom: 2}} - fullWidth={true} - renderInput={(params) => ( - setSearchValue(event.target.value)} - /> - )} - /> - {Object.entries(groupedParameters).map(([group, groupParams]) => ( - - {group} + {group && group !== "" && ( - + )} {groupParams.map((param, index) => ( - + ))} - + ))} - {filteredParameters.length === 0 && searchValue ? ( - No results found + {filteredParameters.length === 0 && (searchValue || selectedComponent) ? ( + No results found ) : null} - - ); - }; - - export default Parameters; \ No newline at end of file + + + ); + }; + + export default Parameters; \ No newline at end of file diff --git a/utils/darkLightContainer.tsx b/utils/darkLightContainer.tsx index b684a0d..ac166c9 100644 --- a/utils/darkLightContainer.tsx +++ b/utils/darkLightContainer.tsx @@ -1,29 +1,37 @@ -import React, {useState} from "react"; +import React, { use, useEffect, useState } from "react"; import { PaletteMode, ThemeProvider, createTheme } from '@mui/material'; import { useTheme } from 'next-themes'; import CssBaseline from '@mui/material/CssBaseline'; export const DarkLightContainer = ({ children }) => { - const {theme, setTheme} = useTheme() + const { resolvedTheme } = useTheme(); + const [theme, setTheme] = useState('dark'); + useEffect(() => { + let mounted = true; + if (resolvedTheme === 'system') { + if (window.matchMedia('(prefers-color-scheme: dark)').matches) { + setTheme('dark'); + } + else { + setTheme('light'); + } + } else { + setTheme(resolvedTheme); + } - const getSystemTheme = () => { - return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; - }; + return () => { + mounted = false; + }; + }, [resolvedTheme]); - // Create a theme instance with the state - const materialTheme = React.useMemo(() => { - // Determine the effective theme mode: 'light', 'dark', or system's preference - const effectiveThemeMode = theme === 'system' ? getSystemTheme() : theme; - - return createTheme({ - palette: { - mode: effectiveThemeMode as PaletteMode, - }, - }); - }, [theme]); + const muiTheme = createTheme({ + palette: { + mode: theme as PaletteMode, + } + }); return ( - + {children} diff --git a/utils/types.ts b/utils/types.ts index 1000a5e..af4a780 100644 --- a/utils/types.ts +++ b/utils/types.ts @@ -85,4 +85,6 @@ export const compatibilityRules = { "darwin": ["arm64", "x86_64"], "windows": ["x86_64"], "linux": ["arm64", "amd64", "ppc64", "x86_64", "aarch64"] -}; \ No newline at end of file +}; + +export const parameterGroups = ["origin", "nsregistry", "director", "client"]; \ No newline at end of file