diff --git a/libs/remix-ui/grid-view/src/index.ts b/libs/remix-ui/grid-view/src/index.ts new file mode 100644 index 0000000000..db94458115 --- /dev/null +++ b/libs/remix-ui/grid-view/src/index.ts @@ -0,0 +1,4 @@ +export * from './lib/remix-ui-grid-view' +export * from './lib/remix-ui-grid-section' +export * from './lib/remix-ui-grid-cell' + diff --git a/libs/remix-ui/grid-view/src/lib/components/customCheckbox.tsx b/libs/remix-ui/grid-view/src/lib/components/customCheckbox.tsx new file mode 100644 index 0000000000..6993e153e0 --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/components/customCheckbox.tsx @@ -0,0 +1,42 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import React from 'react' +import { useContext } from 'react' +import FiltersContext from ".././filtersContext" + +interface CustomCheckboxProps { + label: string + color?: string +} + +export const CustomCheckbox = (props: CustomCheckboxProps) => { + const filterCon = useContext(FiltersContext) + let textColor = props.color + let defChecked = true + if (filterCon.keyValueMap[props.label]) defChecked = filterCon.keyValueMap[props.label].enabled + if (!textColor || textColor == '') textColor = filterCon.keyValueMap[props.label].color + + return ( +
+ { + if (props.label == 'no tag') + filterCon.showUntagged = ! filterCon.showUntagged + else filterCon.updateValue(props.label, e.target.checked, textColor)}} + type="checkbox" + /> + +
+ ) +} + +export default CustomCheckbox diff --git a/libs/remix-ui/grid-view/src/lib/filtersContext.tsx b/libs/remix-ui/grid-view/src/lib/filtersContext.tsx new file mode 100644 index 0000000000..0513247b11 --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/filtersContext.tsx @@ -0,0 +1,16 @@ +import React, { createContext, useState, useContext } from 'react'; + +interface FilterContextType { + showUntagged: boolean + keyValueMap: Record; + updateValue: (key: string, enabled: boolean, color: string) => void + addValue: (key: string, enabled: boolean, color: string) => void +} +const FiltersContext = createContext({ + showUntagged: false, + keyValueMap: {}, + updateValue: () => {}, + addValue: () => {}, +}); + +export default FiltersContext diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.css b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.css new file mode 100644 index 0000000000..19d630ddce --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.css @@ -0,0 +1,21 @@ +.remixui_grid_cell { + font-weight: normal; +} + +.remixui_grid_cell_container { + width: fit-content; +} + +.remixui_grid_cell_title{ + font-size: 0.8rem; + font-style: italic; +} + +.remixui_grid_cell_btn { + width: 32px; +} + +.remixui_grid_cell_logo { + width: 3rem; + height: 3rem; +} diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx new file mode 100644 index 0000000000..0642eb074c --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx @@ -0,0 +1,71 @@ +import React, {useState, useEffect, useContext, useRef, ReactNode} from 'react' // eslint-disable-line + +import './remix-ui-grid-cell.css' +import FiltersContext from "./filtersContext" +import { CustomTooltip } from '@remix-ui/helper' + + +declare global { + interface Window { + _paq: any + } +} +const _paq = window._paq = window._paq || [] + +interface RemixUIGridCellProps { + plugin: any + logo?: string + title?: string + tagList?: string[] // max 8, others will be ignored + classList?: string + styleList?: any + children?: ReactNode +} + +export const RemixUIGridCell = (props: RemixUIGridCellProps) => { + const filterCon = useContext(FiltersContext) + const [anyEnabled, setAnyEnabled] = useState(false) + + useEffect(() => { + if (props.tagList) setAnyEnabled(props.tagList.some((key) => filterCon.keyValueMap[key]?.enabled)) + else setAnyEnabled(filterCon.showUntagged) + }, [filterCon, props.tagList]) + + return ( +
+ { anyEnabled &&
+
+
+
+ { props.logo && } + { props.title && } +
+ { props.children } +
+
+ { props.tagList &&
+ { Object.keys(props.tagList).map((key) => ( + filterCon.keyValueMap[props.tagList[key]].enabled && ( + + + + + ) + )) } +
} + { !props.tagList && + } +
} +
+ ) +} + +export default RemixUIGridCell diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.css b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.css new file mode 100644 index 0000000000..5c79533a71 --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.css @@ -0,0 +1,26 @@ +.remixui_grid_section { + font-weight: normal; +} + +.remixui_grid_section_container { + width: fit-content; +} + +.remixui_grid_section_title{ + font-size: 0.8rem; + font-style: italic; +} + +.remixui_grid_section_btn { + width: 32px; +} + +.remixui_grid_section_logo { + width: 3rem; + height: 3rem; +} + +* { + scrollbar-width: thin; + scrollbar-color: var(--bg-dark) var(--bg-light); +} \ No newline at end of file diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.tsx b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.tsx new file mode 100644 index 0000000000..4dd5409678 --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-section.tsx @@ -0,0 +1,70 @@ +import React, {useState, useEffect, useContext, useRef, ReactNode} from 'react' // eslint-disable-line + +import './remix-ui-grid-section.css' +import {ThemeContext, themes} from './themeContext' + +declare global { + interface Window { + _paq: any + } +} +const _paq = window._paq = window._paq || [] + +interface RemixUIGridSectionProps { + plugin: any + title?: string + hScrollable: boolean + classList?: string + styleList?: any + children?: ReactNode +} + +export const RemixUIGridSection = (props: RemixUIGridSectionProps) => { + const {plugin} = props.plugin + const searchInputRef = useRef(null) + + console.log('props.hScrollable ', props.hScrollable) + const [state, setState] = useState<{ + themeQuality: {filter: string; name: string} + }>({ + themeQuality: themes.light + }) + + useEffect(() => { + plugin?.call('theme', 'currentTheme').then((theme) => { + // update theme quality. To be used for for images + setState((prevState) => { + return { + ...prevState, + themeQuality: theme.quality === 'dark' ? themes.dark : themes.light + } + }) + }) + plugin?.on('theme', 'themeChanged', (theme) => { + // update theme quality. To be used for for images + setState((prevState) => { + return { + ...prevState, + themeQuality: theme.quality === 'dark' ? themes.dark : themes.light + } + }) + }) + }, [plugin]) + + return ( +
+
+ { props.title &&
{ props.title }
} +
+ { props.children } +
+
+
+ ) +} + +export default RemixUIGridSection diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.css b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.css new file mode 100644 index 0000000000..89e41d0cdf --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.css @@ -0,0 +1,25 @@ +.remixui_grid_view { + font-weight: normal; +} + +.remixui_grid_view_container { + overflow: auto; +} + +.remixui_grid_view_title{ + font-size: 0.8rem; + font-style: italic; +} + +.remixui_grid_view_btn { + width: 32px; +} + +.remixui_grid_view_logo { + width: 3rem; + height: 3rem; +} + +.remixui_grid_view_titlebar { + min-width: max-content; +} \ No newline at end of file diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.tsx b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.tsx new file mode 100644 index 0000000000..8f260487bd --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-view.tsx @@ -0,0 +1,145 @@ +import React, {useState, useEffect, useContext, useRef, ReactNode} from 'react' // eslint-disable-line + +import './remix-ui-grid-view.css' +import {ThemeContext, themes} from './themeContext' +import CustomCheckbox from './components/customCheckbox' +import FiltersContext from "./filtersContext" + +declare global { + interface Window { + _paq: any + } +} +const _paq = window._paq = window._paq || [] + +interface RemixUIGridViewProps { + plugin: any + logo?: string + title?: string + enableFilter?: boolean + tagList?: [string, string][] // max 8, others will be ignored + showUntagged?: boolean + classList?: string + styleList?: any + description?: string + children?: ReactNode +} + +export const RemixUIGridView = (props: RemixUIGridViewProps) => { + const [keyValueMap, setKeyValueMap] = useState>({}); + + const showUntagged = props.showUntagged || false + const updateValue = (key: string, enabled: boolean, color?: string) => { + if (!color || color === '') color = setKeyValueMap[key].color + setKeyValueMap((prevMap) => ({ + ...prevMap, + [key]: {color, enabled}, + })) + } + + const addValue = (key: string, enabled: boolean, color: string) => { + // Check if the key already exists, if so, do not add + if (key in keyValueMap) { + return + } + + // Add the new key-value pair + setKeyValueMap((prevMap) => ({ + ...prevMap, + [key]: { enabled, color }, + })) + } + + const {plugin} = props.plugin + const searchInputRef = useRef(null) + + const [state, setState] = useState<{ + themeQuality: {filter: string; name: string} + }>({ + themeQuality: themes.light + }) + + // Initialize filters context with data from props + useEffect(() => { + if (props.tagList && Array.isArray(props.tagList)) { + const initialKeyValueMap: Record = {}; + + // Limit to first 8 elements, ignoring the rest + for (let i = 0; i < props.tagList.length; i++) { + const [key, color] = props.tagList[i] + initialKeyValueMap[key] = { enabled: true, color } + } + if (showUntagged) initialKeyValueMap['no tag'] = { enabled: true, color: 'primary' } + setKeyValueMap(initialKeyValueMap) + } + }, []) + + useEffect(() => { + plugin?.call('theme', 'currentTheme').then((theme) => { + // update theme quality. To be used for for images + setState((prevState) => { + return { + ...prevState, + themeQuality: theme.quality === 'dark' ? themes.dark : themes.light + } + }) + }) + plugin?.on('theme', 'themeChanged', (theme) => { + // update theme quality. To be used for for images + setState((prevState) => { + return { + ...prevState, + themeQuality: theme.quality === 'dark' ? themes.dark : themes.light + } + }) + }) + }, [plugin]) + + return ( + +
+ +
+
+
+ { props.logo && } + { props.title &&

{ props.title }

} +
+ { props.description &&
{ props.description }
} + { props.enableFilter &&
+
+
+ + +
+
+ { Object.keys(keyValueMap).map((key) => ( + + )) } +
+
+
} +
+ { props.children } +
+
+
+
+ ) +} + +export default RemixUIGridView diff --git a/libs/remix-ui/grid-view/src/lib/themeContext.tsx b/libs/remix-ui/grid-view/src/lib/themeContext.tsx new file mode 100644 index 0000000000..fc67007dac --- /dev/null +++ b/libs/remix-ui/grid-view/src/lib/themeContext.tsx @@ -0,0 +1,16 @@ +import React from 'react' // eslint-disable-line + +export const themes = { + light: { + filter: 'invert(0)', + name: 'light' + }, + dark: { + filter: 'invert(1)', + name: 'dark' + } +} + +export const ThemeContext = React.createContext( + themes.dark // default value +)