diff --git a/web/app/components/image-zoom.css b/web/app/components/image-zoom.css new file mode 100644 index 00000000..85ab6957 --- /dev/null +++ b/web/app/components/image-zoom.css @@ -0,0 +1,77 @@ +[data-rmiz] { + display: block; + position: relative; +} + +[data-rmiz-ghost] { + pointer-events: none; + position: absolute; +} + +[data-rmiz-btn-zoom], +[data-rmiz-btn-unzoom] { + display: none; +} + +[data-rmiz-content="found"] img { + cursor: zoom-in; +} + +[data-rmiz-modal][open] { + width: 100vw /* fallback */; + width: 100dvw; + + height: 100vh /* fallback */; + height: 100dvh; + + background-color: transparent; + max-width: none; + max-height: none; + margin: 0; + padding: 0; + position: fixed; + overflow: hidden; +} + +[data-rmiz-modal]:focus-visible { + outline: none; +} + +[data-rmiz-modal-overlay] { + transition: background-color 0.3s; + position: absolute; + inset: 0; +} + +[data-rmiz-modal-overlay="visible"] { + background-color: var(--color-fd-background); +} + +[data-rmiz-modal-overlay="hidden"] { + background-color: transparent; +} + +[data-rmiz-modal-content] { + width: 100%; + height: 100%; + position: relative; +} + +[data-rmiz-modal]::backdrop { + display: none; +} + +[data-rmiz-modal-img] { + cursor: zoom-out; + image-rendering: high-quality; + transform-origin: 0 0; + transition: transform 0.3s; + position: absolute; +} + +@media (prefers-reduced-motion: reduce) { + [data-rmiz-modal-overlay], + [data-rmiz-modal-img] { + transition-duration: 0.01ms !important; + } +} diff --git a/web/app/components/image-zoom.tsx b/web/app/components/image-zoom.tsx new file mode 100644 index 00000000..6f15872e --- /dev/null +++ b/web/app/components/image-zoom.tsx @@ -0,0 +1,58 @@ +"use client"; + +import { Image, type ImageProps } from "fumadocs-core/framework"; +import type { ComponentProps } from "react"; +import Zoom, { type UncontrolledProps } from "react-medium-image-zoom"; +import "@/components/image-zoom.css"; + +export type ImageZoomProps = ImageProps & { + /** + * Image props when zoom in + */ + zoomInProps?: ComponentProps<"img">; + + /** + * Props for `react-medium-image-zoom` + */ + rmiz?: UncontrolledProps; +}; + +function getImageSrc(src: ImageProps["src"]): string { + if (typeof src === "string") return src; + + if (typeof src === "object") { + // Next.js + if ("default" in src) + return (src as { default: { src: string } }).default.src; + return src.src; + } + + return ""; +} + +export function ImageZoom({ + zoomInProps, + children, + rmiz, + ...props +}: ImageZoomProps) { + return ( + + {children ?? ( + + )} + + ); +} diff --git a/web/app/components/probeshell/package-config-card.tsx b/web/app/components/probeshell/package-config-card.tsx index 04154f4b..f93048c0 100644 --- a/web/app/components/probeshell/package-config-card.tsx +++ b/web/app/components/probeshell/package-config-card.tsx @@ -30,7 +30,11 @@ export default function PackageConfigCard({ useEffect(() => { const filteredOptions = (packerConfig ?? []).filter((name) => { - return !name.startsWith("Agent") && !name.toLowerCase().startsWith("xxl") && !name.toLowerCase().endsWith("jar"); + return ( + !name.startsWith("Agent") && + !name.toLowerCase().startsWith("xxl") && + !name.toLowerCase().endsWith("jar") + ); }); const mappedOptions = filteredOptions.map((name) => { diff --git a/web/app/docs/page.tsx b/web/app/docs/page.tsx index f3f29da1..af572340 100644 --- a/web/app/docs/page.tsx +++ b/web/app/docs/page.tsx @@ -1,5 +1,6 @@ import browserCollections from "fumadocs-mdx:collections/browser"; import { useFumadocsLoader } from "fumadocs-core/source/client"; +import { ImageZoom } from "fumadocs-ui/components/image-zoom"; import { DocsLayout } from "fumadocs-ui/layouts/docs"; import { DocsBody, @@ -32,7 +33,12 @@ const clientLoader = browserCollections.docs.createClientLoader({ {frontmatter.title} {frontmatter.description} - + , + }} + /> ); diff --git a/web/biome.json b/web/biome.json index 976a72d1..fd14f490 100644 --- a/web/biome.json +++ b/web/biome.json @@ -19,7 +19,11 @@ "rules": { "recommended": true, "suspicious": { - "noExplicitAny": "off" + "noExplicitAny": "off", + "noDuplicateProperties": "off" + }, + "complexity": { + "noImportantStyles": "off" } }, "domains": { diff --git a/web/bun.lock b/web/bun.lock index 14177735..e2245a3a 100644 --- a/web/bun.lock +++ b/web/bun.lock @@ -14,7 +14,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "framer-motion": "^12.23.25", - "fumadocs-core": "16.2.3", + "fumadocs-core": "^16.2.4", "fumadocs-mdx": "14.1.0", "fumadocs-ui": "16.2.3", "i18next": "^25.7.2", @@ -27,6 +27,7 @@ "react-dom": "^19.2.1", "react-hook-form": "^7.68.0", "react-i18next": "^16.4.0", + "react-medium-image-zoom": "^5.4.0", "react-syntax-highlighter": "^16.1.0", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", @@ -721,7 +722,7 @@ "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "fumadocs-core": ["fumadocs-core@16.2.3", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.6.2", "@orama/orama": "^3.1.16", "@shikijs/rehype": "^3.19.0", "@shikijs/transformers": "^3.19.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^3.19.0", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "@mixedbread/sdk": "^0.19.0", "@orama/core": "1.x.x", "@tanstack/react-router": "1.x.x", "@types/react": "*", "algoliasearch": "5.x.x", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0", "zod": "*" }, "optionalPeers": ["@mixedbread/sdk", "@orama/core", "@tanstack/react-router", "@types/react", "algoliasearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-HFtS0Gwf4izYbmkB8gj0sQWv8G9yyI8tM5RQ3E8fSD5IRVtBWhPq05zOIIM523XUGfDBvm/qDOquDqVF5NDO+A=="], + "fumadocs-core": ["fumadocs-core@16.2.4", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.6.2", "@orama/orama": "^3.1.16", "@shikijs/rehype": "^3.19.0", "@shikijs/transformers": "^3.19.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^3.19.0", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "@mixedbread/sdk": "^0.19.0", "@orama/core": "1.x.x", "@tanstack/react-router": "1.x.x", "@types/react": "*", "algoliasearch": "5.x.x", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0", "zod": "*" }, "optionalPeers": ["@mixedbread/sdk", "@orama/core", "@tanstack/react-router", "@types/react", "algoliasearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-vCxmRdZz8jNSXao4UF0+KgQQ4HgXww5LFGF883PemyJxHrgYuBbCslkSZP0mgpVWWcJWRE52gChUl4hI9YAxBQ=="], "fumadocs-mdx": ["fumadocs-mdx@14.1.0", "", { "dependencies": { "@mdx-js/mdx": "^3.1.1", "@standard-schema/spec": "^1.0.0", "chokidar": "^5.0.0", "esbuild": "^0.27.1", "estree-util-value-to-estree": "^3.5.0", "js-yaml": "^4.1.1", "mdast-util-to-markdown": "^2.1.2", "picocolors": "^1.1.1", "picomatch": "^4.0.3", "remark-mdx": "^3.1.1", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3", "zod": "^4.1.13" }, "peerDependencies": { "@fumadocs/mdx-remote": "^1.4.0", "fumadocs-core": "^15.0.0 || ^16.0.0", "next": "^15.3.0 || ^16.0.0", "react": "*", "vite": "6.x.x || 7.x.x" }, "optionalPeers": ["@fumadocs/mdx-remote", "next", "react", "vite"], "bin": { "fumadocs-mdx": "dist/bin.js" } }, "sha512-6I3nXzM3+dSap5UZvKFQvOaKNKdMfxK5/8Cyu3am6zm0d/acuUxT1r1s1GQpc8H5iB9bFMtwyoZff1WN2qWq8g=="], @@ -1359,6 +1360,8 @@ "fumadocs-mdx/esbuild": ["esbuild@0.27.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.1", "@esbuild/android-arm": "0.27.1", "@esbuild/android-arm64": "0.27.1", "@esbuild/android-x64": "0.27.1", "@esbuild/darwin-arm64": "0.27.1", "@esbuild/darwin-x64": "0.27.1", "@esbuild/freebsd-arm64": "0.27.1", "@esbuild/freebsd-x64": "0.27.1", "@esbuild/linux-arm": "0.27.1", "@esbuild/linux-arm64": "0.27.1", "@esbuild/linux-ia32": "0.27.1", "@esbuild/linux-loong64": "0.27.1", "@esbuild/linux-mips64el": "0.27.1", "@esbuild/linux-ppc64": "0.27.1", "@esbuild/linux-riscv64": "0.27.1", "@esbuild/linux-s390x": "0.27.1", "@esbuild/linux-x64": "0.27.1", "@esbuild/netbsd-arm64": "0.27.1", "@esbuild/netbsd-x64": "0.27.1", "@esbuild/openbsd-arm64": "0.27.1", "@esbuild/openbsd-x64": "0.27.1", "@esbuild/openharmony-arm64": "0.27.1", "@esbuild/sunos-x64": "0.27.1", "@esbuild/win32-arm64": "0.27.1", "@esbuild/win32-ia32": "0.27.1", "@esbuild/win32-x64": "0.27.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-yY35KZckJJuVVPXpvjgxiCuVEJT67F6zDeVTv4rizyPrfGBUpZQsvmxnN+C371c2esD/hNMjj4tpBhuueLN7aA=="], + "fumadocs-ui/fumadocs-core": ["fumadocs-core@16.2.3", "", { "dependencies": { "@formatjs/intl-localematcher": "^0.6.2", "@orama/orama": "^3.1.16", "@shikijs/rehype": "^3.19.0", "@shikijs/transformers": "^3.19.0", "estree-util-value-to-estree": "^3.5.0", "github-slugger": "^2.0.0", "hast-util-to-estree": "^3.1.3", "hast-util-to-jsx-runtime": "^2.3.6", "image-size": "^2.0.2", "negotiator": "^1.0.0", "npm-to-yarn": "^3.0.1", "path-to-regexp": "^8.3.0", "remark": "^15.0.1", "remark-gfm": "^4.0.1", "remark-rehype": "^11.1.2", "scroll-into-view-if-needed": "^3.1.0", "shiki": "^3.19.0", "unist-util-visit": "^5.0.0" }, "peerDependencies": { "@mixedbread/sdk": "^0.19.0", "@orama/core": "1.x.x", "@tanstack/react-router": "1.x.x", "@types/react": "*", "algoliasearch": "5.x.x", "lucide-react": "*", "next": "16.x.x", "react": "^19.2.0", "react-dom": "^19.2.0", "react-router": "7.x.x", "waku": "^0.26.0 || ^0.27.0", "zod": "*" }, "optionalPeers": ["@mixedbread/sdk", "@orama/core", "@tanstack/react-router", "@types/react", "algoliasearch", "lucide-react", "next", "react", "react-dom", "react-router", "waku", "zod"] }, "sha512-HFtS0Gwf4izYbmkB8gj0sQWv8G9yyI8tM5RQ3E8fSD5IRVtBWhPq05zOIIM523XUGfDBvm/qDOquDqVF5NDO+A=="], + "mime-types/mime-db": ["mime-db@1.33.0", "", {}, "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="], "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], diff --git a/web/package.json b/web/package.json index e7923b97..c505d09f 100644 --- a/web/package.json +++ b/web/package.json @@ -21,7 +21,7 @@ "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "framer-motion": "^12.23.25", - "fumadocs-core": "16.2.3", + "fumadocs-core": "^16.2.4", "fumadocs-mdx": "14.1.0", "fumadocs-ui": "16.2.3", "i18next": "^25.7.2", @@ -34,6 +34,7 @@ "react-dom": "^19.2.1", "react-hook-form": "^7.68.0", "react-i18next": "^16.4.0", + "react-medium-image-zoom": "^5.4.0", "react-syntax-highlighter": "^16.1.0", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0",