From 69d432b6af5f2b8c92da7015df47342c795d8cd4 Mon Sep 17 00:00:00 2001 From: Benjamin Toby Date: Fri, 13 Feb 2026 19:04:07 +0100 Subject: [PATCH] Updates --- .gitignore | 1 + bun.lockb | Bin 217638 -> 225539 bytes components/lib/(partials)/ModalComponent.tsx | 2 +- components/lib/base.css | 1 + .../composites/docs/TWUIDocsRightAside.tsx | 2 - components/lib/editors/AceEditor.tsx | 45 +++-- components/lib/elements/LinkList.tsx | 11 +- components/lib/elements/Loading.tsx | 8 +- components/lib/elements/LoadingOverlay.tsx | 7 +- components/lib/elements/Modal.tsx | 6 +- components/lib/elements/RemoteCodeBlock.tsx | 5 +- components/lib/elements/Search.tsx | 6 +- components/lib/elements/StarRating.tsx | 20 +- components/lib/elements/Tabs.tsx | 53 ++++- components/lib/elements/Toast.tsx | 24 ++- .../lib/elements/ai/AIPromptHistoryModal.tsx | 2 +- .../lib/elements/ai/AIPromptPreview.tsx | 6 +- components/lib/elements/lucide-icon.tsx | 20 ++ components/lib/form/Checkbox.tsx | 12 +- components/lib/form/Form.tsx | 10 +- components/lib/form/ImageUpload.tsx | 51 ++++- .../lib/form/Input/NumberInputButtons.tsx | 22 ++- components/lib/form/Input/index.tsx | 123 ++++++------ components/lib/hooks/useReady.tsx | 2 +- components/lib/hooks/useStatus.tsx | 31 +++ components/lib/hooks/useWebSocket.tsx | 183 +++++++----------- components/lib/hooks/userWindowFocus.tsx | 24 +++ components/lib/layout/Button.tsx | 81 ++++---- .../lib/layout/LoadingRectangleBlock.tsx | 5 +- components/lib/layout/Span.tsx | 5 +- .../MarkdownEditorPreviewComponent.tsx | 4 +- components/lib/utils/ejson.ts | 38 ++++ components/lib/utils/fetch/fetchApi.ts | 45 ++--- components/lib/utils/numberfy.ts | 1 - components/lib/utils/serialize-query.ts | 42 ++++ components/lib/utils/slugify.ts | 1 - .../blog/(sections)/BlogPostsListCard.tsx | 4 +- package.json | 4 +- pages/blog/[slug]/index.tsx | 20 +- pages/blog/index.tsx | 7 +- types.ts | 21 +- types/dsql.ts | 55 ++++++ 42 files changed, 650 insertions(+), 360 deletions(-) mode change 100644 => 100755 bun.lockb create mode 100644 components/lib/elements/lucide-icon.tsx create mode 100644 components/lib/hooks/useStatus.tsx create mode 100644 components/lib/hooks/userWindowFocus.tsx create mode 100644 components/lib/utils/ejson.ts create mode 100644 components/lib/utils/serialize-query.ts create mode 100644 types/dsql.ts diff --git a/.gitignore b/.gitignore index d32cc78..8fd41ae 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +dsql-schema-to-typedef.json \ No newline at end of file diff --git a/bun.lockb b/bun.lockb old mode 100644 new mode 100755 index 1ce9291326d19fb9adf72c8bce24e031a81ce02e..4134ef23e47c7a64deee713e9db7524d9e06182d GIT binary patch delta 46383 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 delta 43107 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%0D3Lj)>)T^buh2d*Bt;IjMG)d(>?{rD&7m%WU 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 diff --git a/components/lib/(partials)/ModalComponent.tsx b/components/lib/(partials)/ModalComponent.tsx index ff71a83..00c999d 100644 --- a/components/lib/(partials)/ModalComponent.tsx +++ b/components/lib/(partials)/ModalComponent.tsx @@ -40,7 +40,7 @@ export default function ModalComponent({ open, setOpen, ...props }: Props) { ; + editorRef?: MutableRefObject; readOnly?: boolean; /** Function to call when Ctrl+Enter is pressed */ ctrlEnterFn?: (editor: AceAjax.Editor) => void; content?: string; placeholder?: string; + title?: string; mode?: (typeof AceEditorModes)[number]; fontSize?: string; previewMode?: boolean; @@ -18,7 +20,9 @@ export type AceEditorComponentType = { React.HTMLAttributes, HTMLDivElement >; - refresh?: number; + refreshDepArr?: any[]; + editorOptions?: AceEditorOptions; + showLabel?: boolean; }; let timeout: any; @@ -40,13 +44,15 @@ export default function AceEditor({ previewMode, onChange, delay = 500, - refresh: externalRefresh, + refreshDepArr, wrapperProps, + editorOptions, + showLabel, + title, }: AceEditorComponentType) { try { - const editorElementRef = React.useRef(null); - // const editorRefInstance = React.useRef(null); - const editorRefInstance = React.useRef(null); + const editorElementRef = React.useRef(undefined); + const editorRefInstance = React.useRef(undefined); const [refresh, setRefresh] = React.useState(0); const [darkMode, setDarkMode] = React.useState(false); @@ -84,9 +90,7 @@ export default function AceEditor({ showLineNumbers: previewMode ? false : true, wrap: true, wrapMethod: "code", - // onchange: (e) => { - // console.log(e); - // }, + ...editorOptions, }); editor.commands.addCommand({ @@ -103,7 +107,9 @@ export default function AceEditor({ clearTimeout(timeout); setTimeout(() => { - onChange(editor.getValue()); + try { + onChange(editor.getValue()); + } catch (error) {} }, delay); } }); @@ -114,7 +120,7 @@ export default function AceEditor({ return function () { editor.destroy(); }; - }, [refresh, darkMode, ready, externalRefresh]); + }, [refresh, darkMode, ready, mode, ...(refreshDepArr || [])]); React.useEffect(() => { const htmlClassName = document.documentElement.className; @@ -129,12 +135,23 @@ export default function AceEditor({
+ {showLabel && title ? ( + + ) : null}
{links @@ -104,7 +105,7 @@ export default function LinkList({ {...link.buttonProps} className={twMerge( "p-2 cursor-pointer whitespace-nowrap", - linkProps?.className + linkProps?.className, )} onClick={(e) => { link.onClick?.(e); @@ -113,7 +114,7 @@ export default function LinkList({ > {link.icon} - {link.title} + {link.component || link.title} {finalDivider} @@ -131,7 +132,7 @@ export default function LinkList({ className={twMerge( "p-2 cursor-pointer whitespace-nowrap", linkProps?.className, - link.linkProps?.className + link.linkProps?.className, )} strict={link.strict} onClick={(e) => { @@ -144,7 +145,7 @@ export default function LinkList({ link.iconPosition == "before" ? link.icon : null} - {link.title} + {link.component || link.title} {link.iconPosition == "after" ? link.icon : null} diff --git a/components/lib/elements/Loading.tsx b/components/lib/elements/Loading.tsx index d93ea9e..608a8e3 100644 --- a/components/lib/elements/Loading.tsx +++ b/components/lib/elements/Loading.tsx @@ -31,14 +31,18 @@ export default function Loading({ size, svgClassName, ...props }: Props) { })(); return ( -
+
diff --git a/components/lib/elements/Modal.tsx b/components/lib/elements/Modal.tsx index 2ca1783..e617152 100644 --- a/components/lib/elements/Modal.tsx +++ b/components/lib/elements/Modal.tsx @@ -146,7 +146,11 @@ export default function Modal(props: TWUI_MODAL_PROPS) { {target ? (
setOpen(!open)} + onClick={(e) => { + e.preventDefault(); + e.stopPropagation(); + setOpen(!open); + }} ref={finalTargetRef} onMouseEnter={ isPopover && (trigger === "hover" || hoverOpen) diff --git a/components/lib/elements/RemoteCodeBlock.tsx b/components/lib/elements/RemoteCodeBlock.tsx index 5a7c3d5..b35fcc8 100644 --- a/components/lib/elements/RemoteCodeBlock.tsx +++ b/components/lib/elements/RemoteCodeBlock.tsx @@ -9,6 +9,7 @@ export const TWUIPrismLanguages = ["shell", "javascript"] as const; type Props = { content: string; + refresh?: number; }; /** @@ -16,7 +17,7 @@ type Props = { * * @className `twui-remote-code-block-wrapper` */ -export default function RemoteCodeBlock({ content }: Props) { +export default function RemoteCodeBlock({ content, refresh }: Props) { const [mdxSource, setMdxSource] = React.useState>(); @@ -31,7 +32,7 @@ export default function RemoteCodeBlock({ content }: Props) { }).then((mdxSrc) => { setMdxSource(mdxSrc); }); - }, []); + }, [refresh]); if (!mdxSource) { return null; diff --git a/components/lib/elements/Search.tsx b/components/lib/elements/Search.tsx index 36c2e7d..0f639c5 100644 --- a/components/lib/elements/Search.tsx +++ b/components/lib/elements/Search.tsx @@ -78,12 +78,12 @@ export default function Search({ value={input} onChange={(e) => setInput(e.target.value)} className={twMerge( - "rounded-r-none", + "rounded-r-none!", "twui-search-input", inputProps?.className )} wrapperProps={{ - className: "rounded-r-none", + className: "rounded-r-none!", }} componentRef={inputRef} /> @@ -93,7 +93,7 @@ export default function Search({ variant="outlined" color="gray" className={twMerge( - "rounded-l-none ml-[1px]", + "rounded-l-none! ml-[1px]", "twui-search-button", buttonProps?.className )} diff --git a/components/lib/elements/StarRating.tsx b/components/lib/elements/StarRating.tsx index 0dfab43..54ed9ae 100644 --- a/components/lib/elements/StarRating.tsx +++ b/components/lib/elements/StarRating.tsx @@ -14,6 +14,7 @@ type StarProps = { starProps?: LucideProps; allowRating?: boolean; setValueExternal?: React.Dispatch>; + changeHandler?: (value: number) => void; }; export type TWUI_STAR_RATING_PROPS = DetailedHTMLProps< @@ -35,6 +36,7 @@ export default function StarRating({ starProps, allowRating, setValueExternal, + changeHandler, ...props }: TWUI_STAR_RATING_PROPS) { const totalArray = Array(total).fill(null); @@ -58,7 +60,7 @@ export default function StarRating({ className={twMerge( "flex flex-row items-center gap-0 -ml-[2px]", "twui-star-rating", - props.className + props.className, )} onMouseEnter={() => { sectionHovered.current = true; @@ -68,6 +70,8 @@ export default function StarRating({ }} > {totalArray.map((_, index) => { + const isActive = index + 1 <= finalValue; + return ( @@ -93,34 +99,31 @@ export default function StarRating({ } function StarComponent({ - value = 0, size = 20, starProps, index, allowRating, - finalValue, setFinalValue, starClicked, sectionHovered, setSelectedStarValue, selectedStarValue, + isActive, + changeHandler, }: StarProps & { index: number; - finalValue: number; setFinalValue: React.Dispatch>; setSelectedStarValue: React.Dispatch>; starClicked: React.MutableRefObject; sectionHovered: React.MutableRefObject; selectedStarValue: number; + isActive: boolean; }) { - const isActive = index < finalValue; - return (
{ if (!allowRating) return; - setFinalValue(index + 1); }} onMouseLeave={() => { @@ -145,6 +148,7 @@ function StarComponent({ starClicked.current = true; setSelectedStarValue(index + 1); + changeHandler?.(index + 1); }} > diff --git a/components/lib/elements/Tabs.tsx b/components/lib/elements/Tabs.tsx index b936772..6da7138 100644 --- a/components/lib/elements/Tabs.tsx +++ b/components/lib/elements/Tabs.tsx @@ -27,6 +27,8 @@ export type TWUI_TOGGLE_PROPS = React.ComponentProps & { switchComponent?: ReactNode; setActiveValue?: React.Dispatch>; changeHandler?: (value: TWUITabsObject) => void; + defaultValue?: string | null; + hrefUpdate?: boolean; }; /** @@ -47,6 +49,8 @@ export default function Tabs({ switchComponent, setActiveValue: existingSetActiveValue, changeHandler, + defaultValue, + hrefUpdate, ...props }: TWUI_TOGGLE_PROPS) { const finalTabsContentArray = tabsContentArray @@ -54,31 +58,60 @@ export default function Tabs({ .filter((ct) => Boolean(ct?.title)) as TWUITabsObject[]; const values = finalTabsContentArray.map( - (obj) => obj.value || twuiSlugify(obj.title) + (obj) => obj.value || twuiSlugify(obj.title), ); const defaultActiveObj = finalTabsContentArray.find( - (ctn) => ctn.defaultActive + (ctn) => ctn.defaultActive, ); const [activeValue, setActiveValue] = React.useState( - defaultActiveObj - ? defaultActiveObj?.value || twuiSlugify(defaultActiveObj.title) - : values[0] || undefined + defaultValue + ? defaultValue + : defaultActiveObj + ? defaultActiveObj?.value || twuiSlugify(defaultActiveObj.title) + : values[0] || undefined, ); + const [ready, setReady] = React.useState(false); const targetContent = finalTabsContentArray.find( (ctn) => - ctn.value == activeValue || twuiSlugify(ctn.title) == activeValue + ctn.value == activeValue || twuiSlugify(ctn.title) == activeValue, ); React.useEffect(() => { + if (!ready) return; existingSetActiveValue?.(activeValue); if (targetContent && activeValue) { changeHandler?.(targetContent); + + if (hrefUpdate) { + const url = new URL(window.location.href); + url.searchParams.set("tab", activeValue); + window.history.pushState({}, "", url); + } } }, [activeValue]); + React.useEffect(() => { + if (hrefUpdate) { + const url = new URL(window.location.href); + + const activeTab = url.searchParams.get("tab"); + + if (activeTab && activeValue !== activeTab) { + setActiveValue(undefined); + setActiveValue(activeTab); + } + + setTimeout(() => { + setReady(true); + }, 500); + } else { + setReady(true); + } + }, []); + return ( {values.map((value, index) => { const targetObject = finalTabsContentArray.find( (ctn) => ctn.value == value || - twuiSlugify(ctn.title) == value + twuiSlugify(ctn.title) == value, ); const isActive = value == activeValue; @@ -120,7 +153,7 @@ export default function Tabs({ ? "bg-primary dark:bg-primary-dark text-white outline-none twui-tab-button-active" : "text-slate-400 dark:text-white/40 hover:text-slate-800 dark:hover:text-white" + " cursor-pointer", - "twui-tab-buttons" + "twui-tab-buttons", )} onClick={() => { setActiveValue(undefined); diff --git a/components/lib/elements/Toast.tsx b/components/lib/elements/Toast.tsx index 6440049..c8750f3 100644 --- a/components/lib/elements/Toast.tsx +++ b/components/lib/elements/Toast.tsx @@ -14,6 +14,7 @@ export type TWUIToastProps = DetailedHTMLProps< > & { open?: boolean; setOpen?: React.Dispatch>; + closeDispatch?: (open?: boolean) => void; closeDelay?: number; color?: (typeof ToastStyles)[number]; }; @@ -33,6 +34,7 @@ export default function Toast({ setOpen, closeDelay = 4000, color, + closeDispatch, ...props }: TWUIToastProps) { const [ready, setReady] = React.useState(false); @@ -56,10 +58,12 @@ export default function Toast({ timeout = setTimeout(() => { setOpen?.(false); + closeDispatch?.(open); }, closeDelay); return function () { setOpen?.(false); + closeDispatch?.(open); }; }, [ready, open]); @@ -73,12 +77,12 @@ export default function Toast({ "fixed bottom-4 right-4 z-[250] border-none", "pl-6 pr-8 py-4 bg-primary dark:bg-primary-dark", color == "success" - ? "bg-success dark:bg-success-dark twui-toast-success" + ? "bg-success-dark dark:bg-success-dark twui-toast-success" : color == "error" - ? "bg-error dark:bg-error-dark twui-toast-error" - : "", + ? "bg-error dark:bg-error-dark twui-toast-error" + : "", props.className, - "twui-toast" + "twui-toast", )} onMouseEnter={() => { window.clearTimeout(timeout); @@ -86,22 +90,28 @@ export default function Toast({ onMouseLeave={(e) => { timeout = setTimeout(() => { setOpen?.(false); + closeDispatch?.(open); }, closeDelay); }} > { + e.preventDefault(); + e.stopPropagation(); setOpen?.(false); + closeDispatch?.(open); }} > - {props.children} + + {props.children} + , - document.getElementById(IDName) as HTMLElement + document.getElementById(IDName) as HTMLElement, ); } diff --git a/components/lib/elements/ai/AIPromptHistoryModal.tsx b/components/lib/elements/ai/AIPromptHistoryModal.tsx index 074051d..bcb6bd4 100644 --- a/components/lib/elements/ai/AIPromptHistoryModal.tsx +++ b/components/lib/elements/ai/AIPromptHistoryModal.tsx @@ -32,7 +32,7 @@ export default function AIPromptHistoryModal({ history }: Props) { View History } - className="max-w-[900px] bg-slate-100 dark:bg-white/5 xl:p-10" + className="max-w-[900px] bg-slate-100 dark:bg-white/5 xl:p-8" > diff --git a/components/lib/elements/ai/AIPromptPreview.tsx b/components/lib/elements/ai/AIPromptPreview.tsx index a172544..dce06d2 100644 --- a/components/lib/elements/ai/AIPromptPreview.tsx +++ b/components/lib/elements/ai/AIPromptPreview.tsx @@ -1,7 +1,7 @@ -import Divider from "@/src/components/twui/layout/Divider"; -import Stack from "@/src/components/twui/layout/Stack"; +import Divider from "../../layout/Divider"; +import Stack from "../../layout/Stack"; import React from "react"; -import MarkdownEditorPreviewComponent from "@/src/components/twui/mdx/markdown/MarkdownEditorPreviewComponent"; +import MarkdownEditorPreviewComponent from "../../mdx/markdown/MarkdownEditorPreviewComponent"; import { ChatCompletionMessageParam } from "openai/resources/index"; type Props = { diff --git a/components/lib/elements/lucide-icon.tsx b/components/lib/elements/lucide-icon.tsx new file mode 100644 index 0000000..48c5d0a --- /dev/null +++ b/components/lib/elements/lucide-icon.tsx @@ -0,0 +1,20 @@ +import type { LucideProps } from "lucide-react"; +import * as icons from "lucide-react"; +import React from "react"; + +export type TWUILucideIconName = keyof typeof icons; + +export type TWUILucideIconProps = LucideProps & { + name: TWUILucideIconName; +}; + +export default function LucideIcon({ name, ...props }: TWUILucideIconProps) { + const IconComponent = icons[name] as any; + + if (!IconComponent) { + console.warn(`Lucide icon "${name}" not found`); + return null; + } + + return ; +} diff --git a/components/lib/form/Checkbox.tsx b/components/lib/form/Checkbox.tsx index d2baed6..acf69df 100644 --- a/components/lib/form/Checkbox.tsx +++ b/components/lib/form/Checkbox.tsx @@ -66,7 +66,7 @@ export default function Checkbox({ const finalSize = size || 20; const [checked, setChecked] = React.useState( - defaultChecked || externalChecked || false + defaultChecked || externalChecked || false, ); const finalTitle = title @@ -93,7 +93,7 @@ export default function Checkbox({ "flex items-start md:items-center gap-2 flex-wrap md:flex-nowrap", readOnly ? "opacity-70 pointer-events-none" : "", wrapperClassName, - wrapperProps?.className + wrapperProps?.className, )} onClick={() => { setChecked(!checked); @@ -108,7 +108,7 @@ export default function Checkbox({ ? "bg-primary twui-checkbox-checked text-white outline-slate-400" : "dark:outline-white/50 outline-2 -outline-offset-2 twui-checkbox-unchecked", "twui-checkbox", - props.className + props.className, )} style={{ minWidth: finalSize + "px", @@ -125,7 +125,7 @@ export default function Checkbox({ {...labelProps} className={twMerge( "select-none whitespace-normal md:whitespace-nowrap", - labelProps?.className + labelProps?.className, )} > {label || finalTitle} @@ -134,8 +134,8 @@ export default function Checkbox({ )}
{info && ( - - + + {info} diff --git a/components/lib/form/Form.tsx b/components/lib/form/Form.tsx index 7d7bd49..fb8308e 100644 --- a/components/lib/form/Form.tsx +++ b/components/lib/form/Form.tsx @@ -1,11 +1,12 @@ import _ from "lodash"; -import { DetailedHTMLProps, FormHTMLAttributes } from "react"; +import { DetailedHTMLProps, FormHTMLAttributes, RefObject } from "react"; import { twMerge } from "tailwind-merge"; type Props = DetailedHTMLProps, HTMLFormElement> & { submitHandler?: (e: React.FormEvent, data: T) => void; changeHandler?: (e: React.FormEvent, data: T) => void; + formRef?: RefObject; }; /** @@ -13,8 +14,8 @@ type Props = * @className twui-form */ export default function Form< - T extends { [key: string]: any } = { [key: string]: any } ->({ ...props }: Props) { + T extends { [key: string]: any } = { [key: string]: any }, +>({ formRef, ...props }: Props) { const finalProps = _.omit(props, ["submitHandler", "changeHandler"]); return ( @@ -23,7 +24,7 @@ export default function Form< className={twMerge( "flex flex-col items-stretch gap-2 w-full bg-transparent", "twui-form", - props.className + props.className, )} onSubmit={(e) => { e.preventDefault(); @@ -42,6 +43,7 @@ export default function Form< props.changeHandler?.(e, data); props.onChange?.(e); }} + ref={formRef} > {props.children} diff --git a/components/lib/form/ImageUpload.tsx b/components/lib/form/ImageUpload.tsx index e74bf36..779b3a3 100644 --- a/components/lib/form/ImageUpload.tsx +++ b/components/lib/form/ImageUpload.tsx @@ -10,13 +10,15 @@ import imageInputToBase64, { } from "../utils/form/imageInputToBase64"; import { twMerge } from "tailwind-merge"; import Tag from "../elements/Tag"; +import Input from "./Input"; +import Row from "../layout/Row"; type ImageUploadProps = DetailedHTMLProps< React.HTMLAttributes, HTMLDivElement > & { onChangeHandler?: ( - imgData: ImageInputToBase64FunctionReturn | undefined + imgData: ImageInputToBase64FunctionReturn | undefined, ) => any; fileInputProps?: DetailedHTMLProps< React.InputHTMLAttributes, @@ -45,6 +47,7 @@ type ImageUploadProps = DetailedHTMLProps< React.SetStateAction >; setLoading?: React.Dispatch>; + setImgURL?: React.Dispatch>; externalImage?: ImageInputToBase64FunctionReturn; restoreImageFn?: () => void; }; @@ -67,6 +70,7 @@ export default function ImageUpload({ multiple, restoreImageFn, setLoading, + setImgURL, ...props }: ImageUploadProps) { const [imageObject, setImageObject] = React.useState< @@ -74,6 +78,11 @@ export default function ImageUpload({ >(externalImage); const [src, setSrc] = React.useState(existingImageUrl); const inputRef = React.useRef(null); + const imageUrlRef = React.useRef(""); + + React.useEffect(() => { + setImgURL?.(src); + }, [src]); React.useEffect(() => { if (existingImageUrl) setSrc(existingImageUrl); @@ -84,7 +93,7 @@ export default function ImageUpload({ {...props} className={twMerge( "w-full h-[300px] overflow-hidden", - props?.className + props?.className, )} > @@ -157,10 +166,10 @@ export default function ImageUpload({ {...previewImageProps} /> )} - +
) : ( { const targetEl = e.target as HTMLElement | undefined; @@ -199,6 +208,30 @@ export default function ImageUpload({ {label || "Click to Upload Image"} + + { + imageUrlRef.current = value; + }} + showLabel + /> + + {existingImageUrl && (