diff --git a/components/ui/dialog.tsx b/components/ui/dialog.tsx new file mode 100644 index 000000000..bf20e0e83 --- /dev/null +++ b/components/ui/dialog.tsx @@ -0,0 +1,143 @@ +/* eslint-disable linebreak-style */ +/* eslint-disable react/prop-types */ +import * as React from 'react'; +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { XIcon } from 'lucide-react'; + +import { cn } from '@/lib/utils'; + +function Dialog({ + ...props +}: React.ComponentProps) { + return ; +} + +function DialogTrigger({ + ...props +}: React.ComponentProps) { + return ; +} + +function DialogPortal({ + ...props +}: React.ComponentProps) { + return ; +} + +function DialogClose({ + ...props +}: React.ComponentProps) { + return ; +} + +function DialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean; +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ); +} + +function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +}; diff --git a/components/ui/table.tsx b/components/ui/table.tsx new file mode 100644 index 000000000..df422c53a --- /dev/null +++ b/components/ui/table.tsx @@ -0,0 +1,116 @@ +/* eslint-disable linebreak-style */ +/* eslint-disable react/prop-types */ +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +function Table({ className, ...props }: React.ComponentProps<'table'>) { + return ( +
+ + + ); +} + +function TableHeader({ className, ...props }: React.ComponentProps<'thead'>) { + return ( + + ); +} + +function TableBody({ className, ...props }: React.ComponentProps<'tbody'>) { + return ( + + ); +} + +function TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) { + return ( + tr]:last:border-b-0', + className, + )} + {...props} + /> + ); +} + +function TableRow({ className, ...props }: React.ComponentProps<'tr'>) { + return ( + + ); +} + +function TableHead({ className, ...props }: React.ComponentProps<'th'>) { + return ( +
[role=checkbox]]:translate-y-[2px]', + className, + )} + {...props} + /> + ); +} + +function TableCell({ className, ...props }: React.ComponentProps<'td'>) { + return ( + [role=checkbox]]:translate-y-[2px]', + className, + )} + {...props} + /> + ); +} + +function TableCaption({ + className, + ...props +}: React.ComponentProps<'caption'>) { + return ( +
+ ); +} + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +}; diff --git a/package.json b/package.json index 8e6358e44..188cc57dc 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@docsearch/react": "3.9.0", "@radix-ui/react-checkbox": "^1.3.1", "@radix-ui/react-collapsible": "^1.1.11", + "@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-radio-group": "^1.3.7", "@radix-ui/react-separator": "^1.1.7", diff --git a/pages/tools/components/ToolingDetailModal.tsx b/pages/tools/components/ToolingDetailModal.tsx index 8c91a50e1..6746ac98e 100644 --- a/pages/tools/components/ToolingDetailModal.tsx +++ b/pages/tools/components/ToolingDetailModal.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react'; import CancelIcon from '~/public/icons/cancel.svg'; import { Button } from '~/components/ui/button'; +import { Dialog, DialogContent } from '~/components/ui/dialog'; import Badge from './ui/Badge'; import type { JSONSchemaTool } from '../JSONSchemaTool'; @@ -18,34 +19,16 @@ export default function ToolingDetailModal({ tool: JSONSchemaTool; onClose: () => void; }) { - useEffect(() => { - document.body.classList.add('no-scroll'); - return () => { - document.body.classList.remove('no-scroll'); - }; - }, []); - - useEffect(() => { - const clickEsc = (event: KeyboardEvent) => { - if (event.key === 'Escape') { - onClose(); - } - }; - document.addEventListener('keydown', clickEsc); - return () => { - document.removeEventListener('keydown', clickEsc); - }; - }, [onClose]); - return ( -
-
-
onClose()}> +
-
-
+ + ); } diff --git a/pages/tools/components/ToolingTable.tsx b/pages/tools/components/ToolingTable.tsx index 95bdc6ec7..13e4addfa 100644 --- a/pages/tools/components/ToolingTable.tsx +++ b/pages/tools/components/ToolingTable.tsx @@ -1,3 +1,4 @@ +/* eslint-disable linebreak-style */ import React, { Dispatch, ReactNode, @@ -10,6 +11,14 @@ import { Headline2 } from '~/components/Headlines'; import InfoIcon from '~/public/icons/icons8-info.svg'; import OutLinkIcon from '~/public/icons/outlink.svg'; import { Button } from '~/components/ui/button'; +import { + Table, + TableBody, + TableCell as ShadcnTableCell, + TableHead, + TableHeader, + TableRow, +} from '~/components/ui/table'; import toTitleCase from '../lib/toTitleCase'; import type { GroupedTools, Transform } from '../hooks/useToolsTransform'; @@ -117,219 +126,210 @@ const ToolingTable = ({ {toTitleCase(group, '-')} )} -
+
{/* Desktop Table */} - - - - - Name - - {transform.groupBy !== 'toolingTypes' && ( - +
+ + + - Tooling Type - - )} - {transform.groupBy !== 'languages' && ( + Name + + {transform.groupBy !== 'toolingTypes' && ( + + Tooling Type + + )} + {transform.groupBy !== 'languages' && ( + + Languages + + )} - Languages + Dialects - )} - - Dialects - - - License - - - Bowtie - - - - - {toolsByGroup[group].map((tool: JSONSchemaTool, index) => { - const bowtieData = getBowtieData(tool); - if (bowtieData) { - tool.bowtie = bowtieData; - } - return ( - openModal(tool)} + - segment.length > 25) ? 'break-all' : ''} gap-x-2 gap-y-1`, - style: { - flexBasis: '240px', - flexShrink: 1, - flexGrow: 0, - }, - title: 'See details', - }} + License + + + Bowtie + + + + + {toolsByGroup[group].map((tool: JSONSchemaTool, index) => { + const bowtieData = getBowtieData(tool); + if (bowtieData) { + tool.bowtie = bowtieData; + } + return ( + openModal(tool)} > - {tool.name} - {tool.status === 'obsolete' && ( - {tool.status} + +
+ segment.length > 25) + ? 'break-all' + : 'break-words' + } + > + {tool.name} + + {tool.status === 'obsolete' && ( + {tool.status} + )} +
+
+ {transform.groupBy !== 'toolingTypes' && ( + + {tool.toolingTypes + ?.map((type) => toTitleCase(type, '-')) + .join(', ')} + + )} + {transform.groupBy !== 'languages' && ( + {tool.languages?.join(', ')} )} - - {transform.groupBy !== 'toolingTypes' && ( - {tool.toolingTypes - ?.map((type) => toTitleCase(type, '-')) - .join(', ')} +
+ {tool.supportedDialects?.draft?.map((draft) => { + return {draft}; + })} +
- )} - {transform.groupBy !== 'languages' && ( + {tool.license} - {tool.languages?.join(', ')} + {bowtieReport && ( + + )} - )} - - {tool.supportedDialects?.draft?.map((draft) => { - return {draft}; - })} - - - {tool.license} - - + ); + })} +
+
+
+ + {/* Mobile Table */} +
+ + + {toolsByGroup[group].map((tool: JSONSchemaTool, index) => { + const bowtieData = getBowtieData(tool); + if (bowtieData) { + tool.bowtie = bowtieData; + } + return ( + openModal(tool)} > - {bowtieReport && ( -
- {bowtieData ? ( + + {bowtieData && ( + - )} - - - ); - })} - -
+
+ )} - {/* Mobile Table */} - - - {toolsByGroup[group].map((tool: JSONSchemaTool, index) => { - const bowtieData = getBowtieData(tool); - if (bowtieData) { - tool.bowtie = bowtieData; - } - return ( - openModal(tool)} - > - - - ); - })} - -
- {bowtieData && ( -
- Bowtie: - event.stopPropagation()} - title='See at Bowtie' - className='ml-1' - > - - +
+
+ {tool.name} + {tool.status === 'obsolete' && ( + {tool.status} + )} +
- )} - -
-
- {tool.name} - {tool.status === 'obsolete' && ( - {tool.status} - )} +
+ Languages: {tool.languages?.join(', ')} +
+
+ Supported Dialects: +
+
+ {tool.supportedDialects?.draft?.map((draft) => ( + {draft} + ))}
-
-
- Languages: {tool.languages?.join(', ')} -
-
- Supported Dialects: -
-
- {tool.supportedDialects?.draft?.map((draft) => ( - {draft} - ))} -
-
- License: {tool.license} -
-
+
+ License: {tool.license} +
+ + + ); + })} + +
+
))} @@ -347,15 +347,15 @@ const TableColumnHeader = ({ attributes?: Record; }) => { return ( - {children} - + ); }; @@ -436,16 +436,16 @@ const TableCell = ({ attributes?: Record; }) => { return ( - {children} - + ); }; diff --git a/yarn.lock b/yarn.lock index b3c9bc0ff..deabab9bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2436,6 +2436,38 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-dialog@npm:^1.1.14": + version: 1.1.14 + resolution: "@radix-ui/react-dialog@npm:1.1.14" + dependencies: + "@radix-ui/primitive": "npm:1.1.2" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-context": "npm:1.1.2" + "@radix-ui/react-dismissable-layer": "npm:1.1.10" + "@radix-ui/react-focus-guards": "npm:1.1.2" + "@radix-ui/react-focus-scope": "npm:1.1.7" + "@radix-ui/react-id": "npm:1.1.1" + "@radix-ui/react-portal": "npm:1.1.9" + "@radix-ui/react-presence": "npm:1.1.4" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-slot": "npm:1.2.3" + "@radix-ui/react-use-controllable-state": "npm:1.2.2" + aria-hidden: "npm:^1.2.4" + react-remove-scroll: "npm:^2.6.3" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/ab7bc783510ed8fccfe91020b214f4a571d5a1d46d398faa33f4c151bc9f586c47483b307e72b67687b06694c194b3aa80dd1de728460fa765db9f3057690ba3 + languageName: node + linkType: hard + "@radix-ui/react-direction@npm:1.1.1": version: 1.1.1 resolution: "@radix-ui/react-direction@npm:1.1.1" @@ -2449,6 +2481,63 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-dismissable-layer@npm:1.1.10": + version: 1.1.10 + resolution: "@radix-ui/react-dismissable-layer@npm:1.1.10" + dependencies: + "@radix-ui/primitive": "npm:1.1.2" + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + "@radix-ui/react-use-escape-keydown": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/21a2d03689f5e06586135b6a735937ef14f2571fdf6044a3019bc3f9fa368a9400b5a9b631f43e8ad3682693449e369ffa7cc8642764246ce18ebe7359a45faf + languageName: node + linkType: hard + +"@radix-ui/react-focus-guards@npm:1.1.2": + version: 1.1.2 + resolution: "@radix-ui/react-focus-guards@npm:1.1.2" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/8d6fa55752b9b6e55d1eebb643178e38a824e8ba418eb29031b2979077a12c4e3922892de9f984dd326f77071a14960cd81e99a960beea07598b8c80da618dc5 + languageName: node + linkType: hard + +"@radix-ui/react-focus-scope@npm:1.1.7": + version: 1.1.7 + resolution: "@radix-ui/react-focus-scope@npm:1.1.7" + dependencies: + "@radix-ui/react-compose-refs": "npm:1.1.2" + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/8a6071331bdeeb79b223463de75caf759b8ad19339cab838e537b8dbb2db236891a1f4df252445c854d375d43d9d315dfcce0a6b01553a2984ec372bb8f1300e + languageName: node + linkType: hard + "@radix-ui/react-id@npm:1.1.1": version: 1.1.1 resolution: "@radix-ui/react-id@npm:1.1.1" @@ -2483,6 +2572,26 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-portal@npm:1.1.9": + version: 1.1.9 + resolution: "@radix-ui/react-portal@npm:1.1.9" + dependencies: + "@radix-ui/react-primitive": "npm:2.1.3" + "@radix-ui/react-use-layout-effect": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + "@types/react-dom": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + "@types/react-dom": + optional: true + checksum: 10c0/45b432497c722720c72c493a29ef6085bc84b50eafe79d48b45c553121b63e94f9cdb77a3a74b9c49126f8feb3feee009fe400d48b7759d3552396356b192cd7 + languageName: node + linkType: hard + "@radix-ui/react-presence@npm:1.1.4": version: 1.1.4 resolution: "@radix-ui/react-presence@npm:1.1.4" @@ -2689,6 +2798,21 @@ __metadata: languageName: node linkType: hard +"@radix-ui/react-use-escape-keydown@npm:1.1.1": + version: 1.1.1 + resolution: "@radix-ui/react-use-escape-keydown@npm:1.1.1" + dependencies: + "@radix-ui/react-use-callback-ref": "npm:1.1.1" + peerDependencies: + "@types/react": "*" + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/bff53be99e940fef1d3c4df7d560e1d9133182e5a98336255d3063327d1d3dd4ec54a95dc5afe15cca4fb6c184f0a956c70de2815578c318cf995a7f9beabaa1 + languageName: node + linkType: hard + "@radix-ui/react-use-layout-effect@npm:1.1.1": version: 1.1.1 resolution: "@radix-ui/react-use-layout-effect@npm:1.1.1" @@ -3725,6 +3849,15 @@ __metadata: languageName: node linkType: hard +"aria-hidden@npm:^1.2.4": + version: 1.2.6 + resolution: "aria-hidden@npm:1.2.6" + dependencies: + tslib: "npm:^2.0.0" + checksum: 10c0/7720cb539497a9f760f68f98a4b30f22c6767aa0e72fa7d58279f7c164e258fc38b2699828f8de881aab0fc8e9c56d1313a3f1a965046fc0381a554dbc72b54a + languageName: node + linkType: hard + "aria-query@npm:^5.3.0": version: 5.3.0 resolution: "aria-query@npm:5.3.0" @@ -5085,6 +5218,13 @@ __metadata: languageName: node linkType: hard +"detect-node-es@npm:^1.1.0": + version: 1.1.0 + resolution: "detect-node-es@npm:1.1.0" + checksum: 10c0/e562f00de23f10c27d7119e1af0e7388407eb4b06596a25f6d79a360094a109ff285de317f02b090faae093d314cf6e73ac3214f8a5bb3a0def5bece94557fbe + languageName: node + linkType: hard + "didyoumean@npm:^1.2.2": version: 1.2.2 resolution: "didyoumean@npm:1.2.2" @@ -6544,6 +6684,13 @@ __metadata: languageName: node linkType: hard +"get-nonce@npm:^1.0.0": + version: 1.0.1 + resolution: "get-nonce@npm:1.0.1" + checksum: 10c0/2d7df55279060bf0568549e1ffc9b84bc32a32b7541675ca092dce56317cdd1a59a98dcc4072c9f6a980779440139a3221d7486f52c488e69dc0fd27b1efb162 + languageName: node + linkType: hard + "get-package-type@npm:^0.1.0": version: 0.1.0 resolution: "get-package-type@npm:0.1.0" @@ -7789,6 +7936,7 @@ __metadata: "@next/eslint-plugin-next": "npm:^14.0.1" "@radix-ui/react-checkbox": "npm:^1.3.1" "@radix-ui/react-collapsible": "npm:^1.1.11" + "@radix-ui/react-dialog": "npm:^1.1.14" "@radix-ui/react-label": "npm:^2.1.7" "@radix-ui/react-radio-group": "npm:^1.3.7" "@radix-ui/react-separator": "npm:^1.1.7" @@ -9529,6 +9677,57 @@ __metadata: languageName: node linkType: hard +"react-remove-scroll-bar@npm:^2.3.7": + version: 2.3.8 + resolution: "react-remove-scroll-bar@npm:2.3.8" + dependencies: + react-style-singleton: "npm:^2.2.2" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/9a0675c66cbb52c325bdbfaed80987a829c4504cefd8ff2dd3b6b3afc9a1500b8ec57b212e92c1fb654396d07bbe18830a8146fe77677d2a29ce40b5e1f78654 + languageName: node + linkType: hard + +"react-remove-scroll@npm:^2.6.3": + version: 2.7.1 + resolution: "react-remove-scroll@npm:2.7.1" + dependencies: + react-remove-scroll-bar: "npm:^2.3.7" + react-style-singleton: "npm:^2.2.3" + tslib: "npm:^2.1.0" + use-callback-ref: "npm:^1.3.3" + use-sidecar: "npm:^1.1.3" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/7ad8f6ffd3e2aedf9b3d79f0c9088a9a3d7c5332d80c923427a6d97fe0626fb4cb33a6d9174d19fad57d860be69c96f68497a0619c3a8af0e8a5332e49bdde31 + languageName: node + linkType: hard + +"react-style-singleton@npm:^2.2.2, react-style-singleton@npm:^2.2.3": + version: 2.2.3 + resolution: "react-style-singleton@npm:2.2.3" + dependencies: + get-nonce: "npm:^1.0.0" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/841938ff16d16a6b76895f4cb2e1fea957e5fe3b30febbf03a54892dae1c9153f2383e231dea0b3ba41192ad2f2849448fa859caccd288943bce32639e971bee + languageName: node + linkType: hard + "react-syntax-highlighter@npm:^15.6.1": version: 15.6.1 resolution: "react-syntax-highlighter@npm:15.6.1" @@ -10955,6 +11154,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:^2.0.0": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 + languageName: node + linkType: hard + "tslib@npm:^2.0.3, tslib@npm:^2.1.0": version: 2.6.3 resolution: "tslib@npm:2.6.3" @@ -11337,6 +11543,37 @@ __metadata: languageName: node linkType: hard +"use-callback-ref@npm:^1.3.3": + version: 1.3.3 + resolution: "use-callback-ref@npm:1.3.3" + dependencies: + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/f887488c6e6075cdad4962979da1714b217bcb1ee009a9e57ce9a844bcfc4c3a99e93983dfc2e5af9e0913824d24e730090ff255e902c516dcb58d2d3837e01c + languageName: node + linkType: hard + +"use-sidecar@npm:^1.1.3": + version: 1.1.3 + resolution: "use-sidecar@npm:1.1.3" + dependencies: + detect-node-es: "npm:^1.1.0" + tslib: "npm:^2.0.0" + peerDependencies: + "@types/react": "*" + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + "@types/react": + optional: true + checksum: 10c0/161599bf921cfaa41c85d2b01c871975ee99260f3e874c2d41c05890d41170297bdcf314bc5185e7a700de2034ac5b888e3efc8e9f35724f4918f53538d717c9 + languageName: node + linkType: hard + "util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2"