@clidey/dory 0.21.4 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/bin/dory.ts +18 -4
  2. package/dist/api-playground-demo.mdx +119 -0
  3. package/dist/api-reference/asyncapi.json +324 -0
  4. package/dist/api-reference/openapi.json +366 -0
  5. package/dist/api-reference/operations/create.mdx +5 -0
  6. package/dist/api-reference/operations/delete.mdx +5 -0
  7. package/dist/api-reference/operations/get.mdx +5 -0
  8. package/dist/api-reference/operations/update.mdx +5 -0
  9. package/dist/api-reference/websocket-operations/receive-chat-message.mdx +5 -0
  10. package/dist/api-reference/websocket-operations/receive-notifications.mdx +5 -0
  11. package/dist/api-reference/websocket-operations/receive-presence-update.mdx +5 -0
  12. package/dist/api-reference/websocket-operations/send-chat-message.mdx +5 -0
  13. package/dist/api-reference/websocket-operations/send-presence-update.mdx +5 -0
  14. package/dist/dory.json +64 -0
  15. package/dist/favicon.svg +75 -0
  16. package/dist/features.mdx +440 -0
  17. package/dist/frontmatter.json +77 -0
  18. package/dist/index.html +55 -0
  19. package/dist/introduction.mdx +44 -0
  20. package/dist/llms.txt +561 -0
  21. package/dist/websocket-playground-demo.mdx +135 -0
  22. package/docs/dory.json +5 -0
  23. package/docs/favicon.svg +1 -1
  24. package/docs/introduction.mdx +2 -2
  25. package/package.json +13 -10
  26. package/src/app.css +2 -0
  27. package/src/components/dropdown.tsx +30 -26
  28. package/src/components/loading.tsx +6 -8
  29. package/src/components/navigation.tsx +8 -6
  30. package/src/components/notification.tsx +9 -93
  31. package/src/components/routes.tsx +1 -1
  32. package/src/components/search.tsx +31 -104
  33. package/src/components/store.ts +4 -1
  34. package/src/main.tsx +9 -5
  35. package/src/mdx/accordion.tsx +21 -28
  36. package/src/mdx/api-playground.tsx +68 -83
  37. package/src/mdx/api.tsx +21 -21
  38. package/src/mdx/async-api.tsx +15 -31
  39. package/src/mdx/callout.tsx +27 -43
  40. package/src/mdx/card.tsx +20 -14
  41. package/src/mdx/code.tsx +26 -26
  42. package/src/mdx/expandable.tsx +21 -25
  43. package/src/mdx/fence.tsx +2 -2
  44. package/src/mdx/list.tsx +2 -2
  45. package/src/mdx/open-api.tsx +31 -45
  46. package/src/mdx/table.tsx +8 -3
  47. package/src/mdx/tag.tsx +27 -40
  48. package/src/mdx/text.tsx +3 -2
  49. package/src/mdx/websocket-playground.tsx +150 -81
  50. package/src/theme.scss +50 -106
  51. package/src/types/config.ts +47 -0
  52. package/src/ui/header.tsx +12 -9
  53. package/src/ui/layout.tsx +5 -4
  54. package/src/ui/mobile-navigation.tsx +36 -63
  55. package/src/ui/table-of-content.tsx +3 -3
  56. package/src/utils/colors.ts +54 -0
  57. package/src/utils/fonts.ts +4 -1
  58. package/vite.config.ts +2 -0
  59. package/.claude/settings.json +0 -29
  60. package/.claude/settings.local.json +0 -12
  61. package/.github/ISSUE_TEMPLATE/anything-else.md +0 -10
  62. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -39
  63. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  64. package/.github/dependabot.yml +0 -11
  65. package/.github/workflows/claude.yml +0 -37
  66. package/docs/assets/dory.jpeg +0 -0
  67. package/k8s/Dockerfile +0 -14
  68. package/k8s/config/nginx-default.conf +0 -22
  69. package/k8s/dev.Dockerfile +0 -16
  70. package/k8s/docs.Dockerfile +0 -15
  71. package/public/demo.mov +0 -0
  72. package/src/components/dark-mode-toggle.tsx +0 -25
  73. package/src/index.css +0 -24
  74. package/src/utils/hooks.ts +0 -46
  75. /package/{assets → dist/logo}/logo.svg +0 -0
@@ -1,11 +1,12 @@
1
- import { Input, Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
1
+ import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
2
2
  import { CheckIcon } from '@heroicons/react/24/outline'
3
3
  import classNames from 'classnames'
4
- import { PencilIcon, TrashIcon, XIcon } from 'lucide-react'
4
+ import { PencilIcon, TrashIcon, XIcon, PlusIcon, MessageCircleIcon } from 'lucide-react'
5
5
  import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
6
6
  import Dropdown from '../components/dropdown'
7
7
  import { Tag } from './tag'
8
8
  import { PlayButton } from './api-playground'
9
+ import { Badge, Button, Card, EmptyState, Sheet, SheetContent, SheetHeader, SheetTitle, Input } from '@clidey/ux'
9
10
 
10
11
  export interface WebSocketServer {
11
12
  url: string;
@@ -156,39 +157,39 @@ export const HeadersTab = ({ wsConfig, setWsConfig }: HeadersTabProps) => {
156
157
  value={hdr.key}
157
158
  onChange={e => updateHeader(idx, 'key', (e.target as HTMLInputElement).value)}
158
159
  placeholder="Header name"
159
- className="w-32 rounded-lg bg-zinc-800 border border-zinc-600 px-2 py-1 text-sm text-white"
160
+ className="w-32 text-sm"
160
161
  />
161
162
  <Input
162
163
  type="text"
163
164
  value={hdr.value}
164
165
  onChange={e => updateHeader(idx, 'value', (e.target as HTMLInputElement).value)}
165
166
  placeholder="Header value"
166
- className="flex-1 rounded-lg bg-zinc-800 border border-zinc-600 px-2 py-1 text-sm text-white"
167
+ className="flex-1 text-sm"
167
168
  />
168
- <button onClick={() => saveHeader(idx)} className="text-white">
169
+ <Button onClick={() => saveHeader(idx)} variant="ghost" size="icon" className="text-white h-8 w-8">
169
170
  <CheckIcon className="w-4 h-4" />
170
- </button>
171
- <button onClick={() => cancelEdit(idx)} className="text-white">
171
+ </Button>
172
+ <Button onClick={() => cancelEdit(idx)} variant="ghost" size="icon" className="text-white h-8 w-8">
172
173
  <XIcon className="w-4 h-4" />
173
- </button>
174
+ </Button>
174
175
  </>
175
176
  ) : (
176
177
  <>
177
178
  <span className="text-sm text-white w-32 truncate">{hdr.key}</span>
178
179
  <span className="text-sm text-white flex-1 truncate">{hdr.value}</span>
179
- <button onClick={() => editHeader(idx)} className="text-white">
180
+ <Button onClick={() => editHeader(idx)} variant="ghost" size="icon" className="text-white h-8 w-8">
180
181
  <PencilIcon className="w-4 h-4" />
181
- </button>
182
- <button onClick={() => removeHeader(idx)} className="text-red-400">
182
+ </Button>
183
+ <Button onClick={() => removeHeader(idx)} variant="ghost" size="icon" className="text-red-400 h-8 w-8">
183
184
  <TrashIcon className="w-4 h-4" />
184
- </button>
185
+ </Button>
185
186
  </>
186
187
  )}
187
188
  </div>
188
189
  ))}
189
- <button onClick={addEmptyHeaderRow} className="text-sm text-sky-400 hover:text-sky-300 mt-2 w-fit">
190
- + Add Header
191
- </button>
190
+ <Button onClick={addEmptyHeaderRow} variant="ghost" size="sm" className="mt-2 w-fit">
191
+ <PlusIcon className="w-4 h-4" /> Add Header
192
+ </Button>
192
193
  </div>
193
194
  )
194
195
  }
@@ -273,38 +274,39 @@ export const SubprotocolsTab = ({ subprotocols, setWsConfig }: SubprotocolsTabPr
273
274
  value={s.value}
274
275
  onChange={e => updateSubprotocol(i, (e.target as HTMLInputElement).value)}
275
276
  placeholder="Subprotocol name"
276
- className="flex-1 rounded-lg bg-zinc-800 border border-zinc-600 px-2 py-1 text-sm text-white"
277
+ className="flex-1 text-sm"
277
278
  />
278
- <button onClick={() => saveSubprotocol(i)} className="text-white">
279
+ <Button onClick={() => saveSubprotocol(i)} variant="ghost" size="icon" className="text-white h-8 w-8">
279
280
  <CheckIcon className="w-4 h-4" />
280
- </button>
281
- <button onClick={() => cancelEdit(i)} className="text-white">
281
+ </Button>
282
+ <Button onClick={() => cancelEdit(i)} variant="ghost" size="icon" className="text-white h-8 w-8">
282
283
  <XIcon className="w-4 h-4" />
283
- </button>
284
+ </Button>
284
285
  </>
285
286
  ) : (
286
287
  <>
287
- <span className="flex-1 truncate text-sm text-white">{s.value}</span>
288
- <button onClick={() => editSubprotocol(i)} className="text-white">
288
+ <span className="flex-1 truncate text-sm">{s.value}</span>
289
+ <Button onClick={() => editSubprotocol(i)} variant="ghost" size="icon" className="text-white h-8 w-8">
289
290
  <PencilIcon className="w-4 h-4" />
290
- </button>
291
- <button onClick={() => removeSubprotocol(i)} className="text-red-400">
291
+ </Button>
292
+ <Button onClick={() => removeSubprotocol(i)} variant="ghost" size="icon" className="text-red-400 h-8 w-8">
292
293
  <TrashIcon className="w-4 h-4" />
293
- </button>
294
+ </Button>
294
295
  </>
295
296
  )}
296
297
  </div>
297
298
  ))}
298
- <button onClick={addSubprotocolRow} className="mt-2 text-sm text-sky-400 hover:text-sky-300 self-start">
299
+ <Button onClick={addSubprotocolRow} variant="ghost" size="sm" className="text-sky-400 hover:text-sky-300 mt-2 self-start">
299
300
  + Add Subprotocol
300
- </button>
301
+ </Button>
301
302
  </div>
302
303
  )
303
304
  }
304
305
 
305
306
  type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'error'
306
307
 
307
- export function WebSocketPlayground({
308
+ // Internal playground component that contains the actual WebSocket UI
309
+ function WebSocketPlaygroundInternal({
308
310
  url,
309
311
  title,
310
312
  description,
@@ -478,10 +480,10 @@ export function WebSocketPlayground({
478
480
  return (
479
481
  <div className="my-6 overflow-hidden rounded-2xl">
480
482
  {/* Header */}
481
- <div className="flex min-h-[calc(--spacing(12)+1px)] flex-wrap items-start gap-x-4 border-b border-zinc-700 bg-zinc-800 px-4 dark:border-zinc-800 dark:bg-transparent pb-4">
483
+ <div className="flex min-h-[calc(--spacing(12)+1px)] flex-wrap items-start gap-x-4 px-4 pt-2 pb-4 justify-between">
482
484
  <div className="flex items-center gap-3 pt-3">
483
485
  <Tag variant="small">WS</Tag>
484
- <span className="font-mono text-sm text-white">{title || url}</span>
486
+ <span className="font-mono text-sm">{title || url}</span>
485
487
  <div className="flex items-center gap-2">
486
488
  <div className={`w-2 h-2 rounded-full ${connectionState === 'connected' ? 'bg-green-400' : connectionState === 'connecting' ? 'bg-yellow-400' : connectionState === 'error' ? 'bg-red-400' : 'bg-zinc-400'}`} />
487
489
  <span className={`text-xs ${getConnectionStatusColor()}`}>
@@ -490,11 +492,11 @@ export function WebSocketPlayground({
490
492
  </div>
491
493
  </div>
492
494
  <div className="flex gap-2 ml-auto pt-3">
493
- <button
495
+ <Button
494
496
  onClick={connectWebSocket}
495
497
  disabled={connectionState === 'connecting' || connectionState === 'connected'}
496
498
  className={classNames(
497
- 'flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition',
499
+ 'flex items-center gap-2',
498
500
  connectionState === 'connecting' || connectionState === 'connected'
499
501
  ? 'bg-zinc-600 text-zinc-400 cursor-not-allowed'
500
502
  : 'bg-green-600 text-white hover:bg-green-700'
@@ -506,34 +508,31 @@ export function WebSocketPlayground({
506
508
  <PlayButton className="h-4 w-4" />
507
509
  )}
508
510
  {connectionState === 'connecting' ? 'Connecting...' : 'Connect'}
509
- </button>
510
- <button
511
+ </Button>
512
+ <Button
511
513
  onClick={disconnectWebSocket}
512
514
  disabled={connectionState === 'disconnected'}
515
+ variant="destructive"
513
516
  className={classNames(
514
- 'flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition',
515
- connectionState === 'disconnected'
516
- ? 'bg-zinc-600 text-zinc-400 cursor-not-allowed'
517
- : 'bg-red-600 text-white hover:bg-red-700'
517
+ 'flex items-center gap-2',
518
+ connectionState === 'disconnected' && 'bg-zinc-600 text-zinc-400 cursor-not-allowed'
518
519
  )}
519
520
  >
520
521
  <DisconnectButton className="h-4 w-4" />
521
522
  Disconnect
522
- </button>
523
+ </Button>
523
524
  </div>
524
525
  </div>
525
526
 
526
527
  {description && (
527
- <div className="px-4 py-3 border-b border-zinc-700 dark:border-zinc-800">
528
- <p className="text-sm text-zinc-300">{description}</p>
529
- </div>
528
+ <p className="text-sm px-4 py-3">{description}</p>
530
529
  )}
531
530
 
532
531
  <div className="flex flex-col lg:flex-row gap-4">
533
532
  {/* Configuration */}
534
533
  <div className="flex-1 min-w-0">
535
534
  <div className="flex flex-col gap-2 p-4">
536
- <label className="text-sm font-medium text-white">Server</label>
535
+ <label className="text-sm font-medium">Server</label>
537
536
  <Dropdown
538
537
  buttonLabel={selectedServer?.description || selectedServer?.url || 'Select Server'}
539
538
  items={servers.map(server => ({
@@ -544,9 +543,9 @@ export function WebSocketPlayground({
544
543
  />
545
544
  </div>
546
545
 
547
- <div className="border-t border-zinc-700 dark:border-zinc-800">
546
+ <div>
548
547
  <TabGroup selectedIndex={selectedTab} onChange={setSelectedTab}>
549
- <TabList className="flex border-b border-zinc-700 dark:border-zinc-800">
548
+ <TabList className="flex">
550
549
  {tabs.map((tab) => (
551
550
  <Tab
552
551
  key={tab.key}
@@ -554,7 +553,7 @@ export function WebSocketPlayground({
554
553
  classNames(
555
554
  'px-4 py-3 text-sm font-medium transition border-b-2',
556
555
  selected
557
- ? 'border-sky-500 text-sky-400'
556
+ ? 'border-brand-foreground text-brand-foreground'
558
557
  : 'border-transparent text-zinc-400 hover:text-zinc-300'
559
558
  )
560
559
  }
@@ -582,7 +581,7 @@ export function WebSocketPlayground({
582
581
  {/* Auth Tab */}
583
582
  <TabPanel className="p-4 space-y-4">
584
583
  <div className="flex flex-col space-y-2">
585
- <label className="text-sm font-medium text-white">Authentication Type</label>
584
+ <label className="text-sm font-medium">Authentication Type</label>
586
585
  <Dropdown
587
586
  buttonLabel={auth.type === 'none' ? 'Select Auth Type' : auth.type.charAt(0).toUpperCase() + auth.type.slice(1)}
588
587
  items={[
@@ -597,26 +596,26 @@ export function WebSocketPlayground({
597
596
 
598
597
  {auth.type === 'bearer' && (
599
598
  <div className="space-y-2">
600
- <label className="text-sm font-medium text-white">Bearer Token</label>
601
- <input
599
+ <label className="text-sm font-medium">Bearer Token</label>
600
+ <Input
602
601
  type="password"
603
602
  value={auth.token}
604
603
  onChange={(e) => setAuth(prev => ({ ...prev, token: (e.target as HTMLInputElement).value }))}
605
604
  placeholder="Enter bearer token..."
606
- className="w-full rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none"
605
+ className="w-full text-sm"
607
606
  />
608
607
  </div>
609
608
  )}
610
609
 
611
610
  {auth.type === 'apiKey' && (
612
611
  <div className="space-y-2">
613
- <label className="text-sm font-medium text-white">API Key</label>
614
- <input
612
+ <label className="text-sm font-medium">API Key</label>
613
+ <Input
615
614
  type="password"
616
615
  value={auth.apiKey}
617
616
  onChange={(e) => setAuth(prev => ({ ...prev, apiKey: (e.target as HTMLInputElement).value }))}
618
617
  placeholder="Enter API key..."
619
- className="w-full rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none"
618
+ className="w-full text-sm"
620
619
  />
621
620
  </div>
622
621
  )}
@@ -624,23 +623,23 @@ export function WebSocketPlayground({
624
623
  {auth.type === 'basic' && (
625
624
  <div className="space-y-4">
626
625
  <div className="space-y-2">
627
- <label className="text-sm font-medium text-white">Username</label>
628
- <input
626
+ <label className="text-sm font-medium">Username</label>
627
+ <Input
629
628
  type="text"
630
629
  value={auth.username}
631
630
  onChange={(e) => setAuth(prev => ({ ...prev, username: (e.target as HTMLInputElement).value }))}
632
631
  placeholder="Enter username..."
633
- className="w-full rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none"
632
+ className="w-full text-sm"
634
633
  />
635
634
  </div>
636
635
  <div className="space-y-2">
637
- <label className="text-sm font-medium text-white">Password</label>
638
- <input
636
+ <label className="text-sm font-medium">Password</label>
637
+ <Input
639
638
  type="password"
640
639
  value={auth.password}
641
640
  onChange={(e) => setAuth(prev => ({ ...prev, password: (e.target as HTMLInputElement).value }))}
642
641
  placeholder="Enter password..."
643
- className="w-full rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none"
642
+ className="w-full text-sm"
644
643
  />
645
644
  </div>
646
645
  </div>
@@ -653,24 +652,22 @@ export function WebSocketPlayground({
653
652
 
654
653
  {/* Messages */}
655
654
  <div className="flex-1 min-w-0">
656
- <div className="border-t lg:border-t-0 lg:border-l border-zinc-700 dark:border-zinc-800">
657
- <div className="flex items-center justify-between px-4 py-3 border-b border-zinc-700 dark:border-zinc-800">
658
- <h3 className="text-sm font-semibold text-white">Messages</h3>
659
- <button
655
+ <div>
656
+ <div className="flex items-center justify-between px-4 py-3">
657
+ <h3 className="text-sm font-semibold">Messages</h3>
658
+ <Button
660
659
  onClick={clearMessages}
660
+ variant="ghost"
661
+ size="sm"
661
662
  className="text-xs text-zinc-400 hover:text-zinc-300"
662
663
  >
663
664
  Clear
664
- </button>
665
+ </Button>
665
666
  </div>
666
667
 
667
668
  <div className="flex flex-col h-64 overflow-y-auto p-4 space-y-2">
668
669
  {messages.length === 0 ? (
669
- <div className="text-center py-8">
670
- <div className="text-zinc-400 text-sm">
671
- Connect to start receiving messages
672
- </div>
673
- </div>
670
+ <EmptyState icon={<MessageCircleIcon className="h-5 w-5" />} title="No messages yet" description="Connect to start receiving messages" />
674
671
  ) : (
675
672
  messages.map((msg) => (
676
673
  <div
@@ -709,29 +706,26 @@ export function WebSocketPlayground({
709
706
  </div>
710
707
 
711
708
  {/* Send Message */}
712
- <div className="border-t border-zinc-700 dark:border-zinc-800 p-4">
709
+ <div className="p-4">
713
710
  <div className="flex gap-2">
714
- <input
711
+ <Input
715
712
  type="text"
716
713
  value={messageInput}
717
714
  onChange={(e) => setMessageInput((e.target as HTMLInputElement).value)}
718
715
  onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
719
716
  placeholder="Enter message to send..."
720
717
  disabled={connectionState !== 'connected'}
721
- className="flex-1 rounded-lg bg-zinc-800 border border-zinc-600 px-3 py-2 text-sm text-white placeholder-zinc-400 focus:border-sky-500 focus:outline-none disabled:bg-zinc-900 disabled:text-zinc-500"
718
+ className="flex-1 text-sm"
722
719
  />
723
- <button
720
+ <Button
724
721
  onClick={sendMessage}
725
722
  disabled={connectionState !== 'connected' || !messageInput.trim()}
726
- className={classNames(
727
- 'px-4 py-2 rounded-lg text-sm font-medium transition',
728
- connectionState === 'connected' && messageInput.trim()
729
- ? 'bg-sky-600 text-white hover:bg-sky-700'
730
- : 'bg-zinc-600 text-zinc-400 cursor-not-allowed'
731
- )}
723
+ className={classNames({
724
+ 'bg-sky-600 text-white hover:bg-sky-700': connectionState === 'connected' && messageInput.trim()
725
+ })}
732
726
  >
733
727
  Send
734
- </button>
728
+ </Button>
735
729
  </div>
736
730
  </div>
737
731
  </div>
@@ -739,7 +733,7 @@ export function WebSocketPlayground({
739
733
  </div>
740
734
 
741
735
  {error && (
742
- <div className="border-t border-zinc-700 dark:border-zinc-800 p-4">
736
+ <div className="p-4">
743
737
  <div className="flex items-center gap-2">
744
738
  <span className="inline-flex items-center rounded-full bg-rose-500/10 px-2 py-1 text-xs font-medium text-rose-400 ring-1 ring-rose-500/20">
745
739
  Error
@@ -752,4 +746,79 @@ export function WebSocketPlayground({
752
746
  )}
753
747
  </div>
754
748
  )
749
+ }
750
+
751
+ // Main exported component with Sheet wrapper
752
+ export function WebSocketPlayground(props: WebSocketPlaygroundProps) {
753
+ const [showPlayground, setShowPlayground] = useState(false)
754
+
755
+ const handleShowPlayground = () => {
756
+ setShowPlayground(true)
757
+ }
758
+
759
+ return (
760
+ <div className="max-w-none w-full my-6">
761
+ <Sheet open={showPlayground} onOpenChange={setShowPlayground} modal={true}>
762
+ <SheetContent side="bottom" className="h-[90vh] w-full overflow-y-auto p-8">
763
+ <SheetHeader className="p-0">
764
+ <SheetTitle>WebSocket Playground</SheetTitle>
765
+ </SheetHeader>
766
+ <WebSocketPlaygroundInternal {...props} />
767
+ </SheetContent>
768
+ </Sheet>
769
+
770
+ <Card className="overflow-hidden py-0 border-1 border-black/10">
771
+ <div className="flex items-center justify-between px-4 py-3">
772
+ <div className="flex items-center gap-3">
773
+ <Tag variant="small">WS</Tag>
774
+ <span className="font-mono text-sm">{props.title || props.url}</span>
775
+ </div>
776
+ <Button
777
+ onClick={handleShowPlayground}
778
+ className="flex items-center gap-2"
779
+ >
780
+ Try
781
+ <PlayButton className="h-4 w-4" />
782
+ </Button>
783
+ </div>
784
+
785
+ {props.description && (
786
+ <p className="text-sm px-4 py-3">{props.description}</p>
787
+ )}
788
+
789
+ <div className="px-4 py-3">
790
+ <div className="flex flex-col gap-2">
791
+ <div className="flex items-center gap-2">
792
+ <span className="text-xs font-medium text-zinc-400">Endpoint:</span>
793
+ <Badge>
794
+ {props.servers?.[0]?.url || 'ws://localhost'}{props.url}
795
+ </Badge>
796
+ </div>
797
+
798
+ {props.subprotocols && props.subprotocols.length > 0 && (
799
+ <div className="flex items-center gap-2">
800
+ <span className="text-xs font-medium text-zinc-400">Subprotocols:</span>
801
+ <div className="flex gap-1">
802
+ {props.subprotocols.map((protocol, idx) => (
803
+ <Badge key={idx}>
804
+ {protocol}
805
+ </Badge>
806
+ ))}
807
+ </div>
808
+ </div>
809
+ )}
810
+
811
+ {props.authType && props.authType !== 'none' && (
812
+ <div className="flex items-center gap-2">
813
+ <span className="text-xs font-medium text-zinc-400">Authentication:</span>
814
+ <Badge>
815
+ {props.authType}
816
+ </Badge>
817
+ </div>
818
+ )}
819
+ </div>
820
+ </div>
821
+ </Card>
822
+ </div>
823
+ )
755
824
  }
package/src/theme.scss CHANGED
@@ -1,124 +1,68 @@
1
- html {
2
- background-color: #ffffff !important;
1
+ :root {
2
+ font-synthesis: none;
3
+ text-rendering: optimizeLegibility;
4
+ -webkit-font-smoothing: antialiased;
5
+ -moz-osx-font-smoothing: grayscale;
6
+
7
+ // Brand colors (dynamically set from dory.json via loadColors())
8
+ // These variables are set at runtime:
9
+ // --brand-primary: primary color
10
+ // --brand-light: light mode accent
11
+ // --brand-dark: dark mode accent
12
+ // --brand-foreground: legacy/fallback (set to primary)
13
+
14
+ // Default fallback colors (will be overridden by loadColors())
15
+ --brand-foreground: #0ea5e9;
16
+ --brand-primary: #0ea5e9;
17
+ --brand-light: #38bdf8;
18
+ --brand-dark: #0284c7;
19
+
20
+ // ShadCN/clidey/ux compatible primary color
21
+ // Using light color for light mode
22
+ --primary: var(--brand-light);
23
+ --primary-rgb: var(--brand-light-rgb);
3
24
  }
4
25
 
5
- h1, h2, h3, h4, h5, h6, p, li {
6
- color: #000000 !important;
26
+ // Dark mode overrides
27
+ :root.dark {
28
+ // Use dark color for dark mode
29
+ --primary: var(--brand-dark);
30
+ --primary-rgb: var(--brand-dark-rgb);
7
31
  }
8
-
9
- .mermaid {
10
- background-color: #ffffff !important;
11
- color: #000000 !important;
12
- font-size: 12px !important;
13
- }
14
-
15
- .mermaid rect {
16
- fill: #f8f8f8 !important;
17
- stroke: #333333 !important;
18
- }
19
-
20
- .mermaid p {
21
- color: #000000 !important;
32
+
33
+ article h2:first-of-type {
34
+ display: none;
22
35
  }
23
36
 
24
- .mermaid path {
25
- stroke: #555555 !important;
37
+ article hr:first-of-type {
38
+ display: none;
26
39
  }
27
40
 
28
- .mermaid p {
29
- background-color: #f8f8f8 !important;
30
- color: #000000 !important;
41
+ article img {
42
+ margin-top: 1rem;
43
+ margin-bottom: 1rem;
31
44
  }
32
45
 
33
- .mermaid p, .mermaid text, .mermaid text > tspan {
34
- color: #000000 !important;
35
- fill: #000000 !important;
46
+ [data-testid="header-actions"] button,
47
+ [data-slot="dropdown-menu-content"] {
48
+ border-color: rgba(0, 0, 0, 0.1);
36
49
  }
37
50
 
38
- .mermaid line {
39
- stroke: #333333 !important;
51
+ [data-slot="search-input-wrapper"] {
52
+ font-size: 12px;
53
+ outline: none;
40
54
  }
41
55
 
42
- .mermaid .note {
43
- fill: #ffffcc !important;
44
- stroke: #999999 !important;
45
- color: #000000 !important;
56
+ [data-slot="search-input"] {
57
+ font-size: 12px;
46
58
  }
47
59
 
48
- .docucod-mdx-code {
49
- background-color: #f8f8f8 !important;
60
+ [data-slot="search-input-wrapper"]:focus-within {
61
+ outline: none !important;
50
62
  }
51
63
 
52
- body.dark {
53
- background-color: #1e1e1e !important;
54
-
55
- #container {
56
- background-color: #1e1e1e !important;
57
- }
58
-
59
- h1, h2, h3, h4, h5, h6, p, li, th, td {
60
- color: #ffffff !important;
61
- }
62
-
63
- .mermaid {
64
- background-color: #1e1e1e !important;
65
- color: #ffffff !important;
66
- }
67
-
68
- .mermaid rect {
69
- fill: #2a2a2a !important;
70
- stroke: #aaaaaa !important;
71
- }
72
-
73
- .mermaid p {
74
- color: #ffffff !important;
75
- }
76
-
77
- .mermaid path {
78
- stroke: #cccccc !important;
79
- }
80
-
81
- .mermaid p {
82
- background-color: #2a2a2a !important;
83
- color: #ffffff !important;
84
- }
85
-
86
- .mermaid rect,
87
- .mermaid polygon,
88
- .mermaid circle,
89
- .mermaid ellipse {
90
- fill: #2a2a2a !important;
91
- stroke: #444444 !important;
92
- }
93
-
94
- .mermaid p, .mermaid text, .mermaid text > tspan {
95
- color: #ffffff !important;
96
- fill: #ffffff !important;
97
- }
98
-
99
- .mermaid line {
100
- stroke: #444444 !important;
101
- }
102
-
103
- .mermaid .note {
104
- fill: #2a2a2a !important;
105
- stroke: #444444 !important;
106
- color: #ffffff !important;
107
- }
108
-
109
- .docucod-mdx-code {
110
- background-color: #2a2a2a !important;
111
- }
112
-
113
- .docucod-mdx-code-group {
114
- background-color: #2a2a2a !important;
115
- }
116
-
117
- .docucod-mdx-code-group-header {
118
- background-color: #2a2a2a !important;
119
- }
120
-
121
- .prism-code {
122
- background-color: transparent !important;
123
- }
64
+ [role="dialog"] [data-slot="search-input-wrapper"]:focus-within {
65
+ outline: none !important;
66
+ border: 0px;
67
+ box-shadow: none !important;
124
68
  }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * TypeScript interfaces for dory.json configuration
3
+ */
4
+
5
+ export interface DoryColors {
6
+ primary: string;
7
+ light: string;
8
+ dark: string;
9
+ }
10
+
11
+ export interface DoryFonts {
12
+ family: string;
13
+ source: string;
14
+ format: string;
15
+ }
16
+
17
+ export interface DoryLogo {
18
+ light: string;
19
+ dark: string;
20
+ }
21
+
22
+ export interface DoryNavigationPage {
23
+ [key: string]: string;
24
+ }
25
+
26
+ export interface DoryNavigationGroup {
27
+ group: string;
28
+ pages: string[];
29
+ }
30
+
31
+ export interface DoryNavigationTab {
32
+ tab: string;
33
+ groups: DoryNavigationGroup[];
34
+ }
35
+
36
+ export interface DoryNavigation {
37
+ tabs: DoryNavigationTab[];
38
+ }
39
+
40
+ export interface DoryConfig {
41
+ name: string;
42
+ favicon: string;
43
+ colors?: DoryColors;
44
+ fonts?: DoryFonts;
45
+ navigation: DoryNavigation;
46
+ logo: DoryLogo;
47
+ }