retail-design-system 1.0.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 (110) hide show
  1. package/.github/workflows/release.yml +46 -0
  2. package/.oxfmtrc.json +17 -0
  3. package/.oxlintrc.json +132 -0
  4. package/.vscode/extensions.json +3 -0
  5. package/.vscode/settings.json +13 -0
  6. package/README.md +56 -0
  7. package/apps/storybook/.storybook/main.ts +8 -0
  8. package/apps/storybook/.storybook/preview.css +9 -0
  9. package/apps/storybook/.storybook/preview.ts +6 -0
  10. package/apps/storybook/package.json +24 -0
  11. package/apps/storybook/stories/button.stories.ts +118 -0
  12. package/apps/storybook/stories/input.stories.ts +127 -0
  13. package/apps/storybook/stories/label.stories.ts +98 -0
  14. package/apps/storybook/tsconfig.app.json +24 -0
  15. package/apps/storybook/tsconfig.json +4 -0
  16. package/apps/storybook/tsconfig.node.json +22 -0
  17. package/apps/storybook/vite.config.ts +15 -0
  18. package/apps/web/app/(sidebar)/components/[...slugs]/get-child-block.ts +17 -0
  19. package/apps/web/app/(sidebar)/components/[...slugs]/get-component-page-match.ts +56 -0
  20. package/apps/web/app/(sidebar)/components/[...slugs]/get-direct-child-block.ts +22 -0
  21. package/apps/web/app/(sidebar)/components/[...slugs]/layout.tsx +25 -0
  22. package/apps/web/app/(sidebar)/components/[...slugs]/page.tsx +32 -0
  23. package/apps/web/app/(sidebar)/components/[...slugs]/pascal-to-kebab-case.ts +9 -0
  24. package/apps/web/app/(sidebar)/components/button2/page.tsx +154 -0
  25. package/apps/web/app/(sidebar)/components/input/page.tsx +98 -0
  26. package/apps/web/app/(sidebar)/experiments/2025-10-22/mayhem-mode-card-badge.tsx +9 -0
  27. package/apps/web/app/(sidebar)/experiments/2025-10-22/mayhem-mode-coin-active-badge.tsx +14 -0
  28. package/apps/web/app/(sidebar)/experiments/2025-10-22/mayhem-mode-coin-inactive-badge.tsx +12 -0
  29. package/apps/web/app/(sidebar)/experiments/2025-10-22/mayhem-mode-create-coin.tsx +44 -0
  30. package/apps/web/app/(sidebar)/experiments/2025-10-22/mayhem-mode-dialog-icon.tsx +47 -0
  31. package/apps/web/app/(sidebar)/experiments/2025-10-22/page.tsx +167 -0
  32. package/apps/web/app/(sidebar)/experiments/2025-11-04/filters.tsx +90 -0
  33. package/apps/web/app/(sidebar)/experiments/2025-11-04/page.tsx +18 -0
  34. package/apps/web/app/(sidebar)/layout.tsx +17 -0
  35. package/apps/web/app/(sidebar)/primitives/colors/page.tsx +49 -0
  36. package/apps/web/app/favicon.ico +0 -0
  37. package/apps/web/app/layout.tsx +39 -0
  38. package/apps/web/app/page.tsx +14 -0
  39. package/apps/web/app/providers.tsx +15 -0
  40. package/apps/web/components/dialog.tsx +21 -0
  41. package/apps/web/components/logo.tsx +11 -0
  42. package/apps/web/components/logomark.tsx +21 -0
  43. package/apps/web/components/logotype.tsx +25 -0
  44. package/apps/web/components/notion/notion-block-content.tsx +401 -0
  45. package/apps/web/components/notion/notion-docs-blocks.tsx +18 -0
  46. package/apps/web/components/notion/notion-docs-code-page.tsx +20 -0
  47. package/apps/web/components/notion/notion-docs-layout.tsx +52 -0
  48. package/apps/web/components/notion/notion-revalidate-button-client.tsx +14 -0
  49. package/apps/web/components/notion/notion-revalidate-button.tsx +20 -0
  50. package/apps/web/components/notion/notion-rich-text-segments.tsx +55 -0
  51. package/apps/web/components/notion/notion-tabs.tsx +38 -0
  52. package/apps/web/components/notion/notion.ts +223 -0
  53. package/apps/web/components/sidebar-client.tsx +60 -0
  54. package/apps/web/components/sidebar-server.tsx +185 -0
  55. package/apps/web/components/tooltip.tsx +53 -0
  56. package/apps/web/components/topbar.tsx +14 -0
  57. package/apps/web/next.config.ts +10 -0
  58. package/apps/web/package.json +42 -0
  59. package/apps/web/postcss.config.mjs +5 -0
  60. package/apps/web/public/2025-10-22-dialog-banner.png +0 -0
  61. package/apps/web/public/pump-logomark.svg +7 -0
  62. package/apps/web/styles/custom.css +31 -0
  63. package/apps/web/styles/font.css +8 -0
  64. package/apps/web/styles/global.css +5 -0
  65. package/apps/web/styles/tailwind-reset.css +102 -0
  66. package/apps/web/styles/tailwind.css +140 -0
  67. package/apps/web/tsconfig.json +34 -0
  68. package/bun.lock +1249 -0
  69. package/bunfig.toml +2 -0
  70. package/package.json +41 -0
  71. package/packages/ui/global.d.ts +4 -0
  72. package/packages/ui/package.json +49 -0
  73. package/packages/ui/src/components/button/button-spinner.module.css +95 -0
  74. package/packages/ui/src/components/button/button-spinner.tsx +18 -0
  75. package/packages/ui/src/components/button/button.module.css +144 -0
  76. package/packages/ui/src/components/button/button.tsx +102 -0
  77. package/packages/ui/src/components/button-link/button-link.tsx +46 -0
  78. package/packages/ui/src/components/column/column.module.css +4 -0
  79. package/packages/ui/src/components/column/column.tsx +65 -0
  80. package/packages/ui/src/components/row/row.module.css +4 -0
  81. package/packages/ui/src/components/row/row.tsx +65 -0
  82. package/packages/ui/src/components/spacer/spacer.module.css +3 -0
  83. package/packages/ui/src/components/spacer/spacer.tsx +30 -0
  84. package/packages/ui/src/components/switch/switch.module.css +62 -0
  85. package/packages/ui/src/components/switch/switch.tsx +58 -0
  86. package/packages/ui/src/components/tabs/tabs-panel.module.css +4 -0
  87. package/packages/ui/src/components/tabs/tabs-panel.tsx +21 -0
  88. package/packages/ui/src/components/tabs/tabs.module.css +5 -0
  89. package/packages/ui/src/components/tabs/tabs.tsx +21 -0
  90. package/packages/ui/src/components/tabs-underline/tabs-underline-indicator.module.css +10 -0
  91. package/packages/ui/src/components/tabs-underline/tabs-underline-indicator.tsx +33 -0
  92. package/packages/ui/src/components/tabs-underline/tabs-underline-list.module.css +8 -0
  93. package/packages/ui/src/components/tabs-underline/tabs-underline-list.tsx +27 -0
  94. package/packages/ui/src/components/tabs-underline/tabs-underline-tab.module.css +24 -0
  95. package/packages/ui/src/components/tabs-underline/tabs-underline-tab.tsx +30 -0
  96. package/packages/ui/src/foundations/colors/colors.ts +475 -0
  97. package/packages/ui/src/foundations/colors/generate-css.ts +34 -0
  98. package/packages/ui/src/foundations/colors/retail-design-system.css +116 -0
  99. package/packages/ui/src/foundations/colors/tailwind-v3.ts +18 -0
  100. package/packages/ui/src/foundations/colors/tailwind-v4.css +116 -0
  101. package/packages/ui/src/index.ts +34 -0
  102. package/packages/ui/src/input.module.css +57 -0
  103. package/packages/ui/src/input.tsx +49 -0
  104. package/packages/ui/src/label.module.css +8 -0
  105. package/packages/ui/src/label.tsx +23 -0
  106. package/packages/ui/tsconfig.json +14 -0
  107. package/packages/ui/tsup.config.ts +31 -0
  108. package/scripts/clean.sh +69 -0
  109. package/scripts/sort-package-json.sh +30 -0
  110. package/turbo.json +15 -0
@@ -0,0 +1,22 @@
1
+ {
2
+ "compilerOptions": {
3
+ "allowImportingTsExtensions": true,
4
+ "erasableSyntaxOnly": true,
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "moduleDetection": "force",
8
+ "moduleResolution": "bundler",
9
+ "noEmit": true,
10
+ "noFallthroughCasesInSwitch": true,
11
+ "noUncheckedSideEffectImports": true,
12
+ "noUnusedLocals": true,
13
+ "noUnusedParameters": true,
14
+ "skipLibCheck": true,
15
+ "strict": true,
16
+ "target": "ES2023",
17
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
18
+ "types": ["node"],
19
+ "verbatimModuleSyntax": true
20
+ },
21
+ "include": ["vite.config.ts"]
22
+ }
@@ -0,0 +1,15 @@
1
+ // oxlint-disable unicorn/prefer-module
2
+ // oxlint-disable import/no-nodejs-modules
3
+
4
+ import path from "node:path"
5
+ import react from "@vitejs/plugin-react"
6
+ import { defineConfig } from "vite"
7
+
8
+ export default defineConfig({
9
+ plugins: [react()],
10
+ resolve: {
11
+ alias: {
12
+ "@": path.resolve(__dirname, "."),
13
+ },
14
+ },
15
+ })
@@ -0,0 +1,17 @@
1
+ import { notion } from "@/components/notion/notion"
2
+
3
+ export type NotionBlock = Awaited<ReturnType<typeof notion.blocks.children.list>>["results"][number]
4
+
5
+ export async function getChildBlocks(blockId: string, cursor?: string): Promise<NotionBlock[]> {
6
+ const response = await notion.blocks.children.list({
7
+ block_id: blockId,
8
+ start_cursor: cursor,
9
+ })
10
+
11
+ if (!response.has_more || !response.next_cursor) {
12
+ return response.results
13
+ }
14
+
15
+ const nextBlocks = await getChildBlocks(blockId, response.next_cursor)
16
+ return [...response.results, ...nextBlocks]
17
+ }
@@ -0,0 +1,56 @@
1
+ import { cacheTag } from "next/cache"
2
+ import { getDirectChildPages } from "@/app/(sidebar)/components/[...slugs]/get-direct-child-block"
3
+ import { pascalToKebabCase } from "@/app/(sidebar)/components/[...slugs]/pascal-to-kebab-case"
4
+
5
+ const NOTION_PAGE_ID = "325b76f65e6e80c49a65d7bbd2636d1e"
6
+
7
+ interface ComponentPage {
8
+ childPageIds: string[]
9
+ id: string
10
+ slug: string
11
+ }
12
+
13
+ interface ComponentPageMatch {
14
+ childPageId?: string
15
+ pageId: string
16
+ }
17
+
18
+ export async function getComponentPageMatch(slug: string): Promise<ComponentPageMatch | undefined> {
19
+ const pages = await getComponentPages()
20
+ const matchedPage = pages.find((page) => page.slug === slug)
21
+
22
+ if (!matchedPage) {
23
+ return undefined
24
+ }
25
+
26
+ return {
27
+ childPageId: matchedPage.childPageIds[0],
28
+ pageId: matchedPage.id,
29
+ }
30
+ }
31
+
32
+ export async function getComponentPageSlugs(): Promise<string[]> {
33
+ const pages = await getComponentPages()
34
+ return pages.filter((page) => page.childPageIds.length > 0).map((page) => page.slug)
35
+ }
36
+
37
+ async function getComponentPages(): Promise<ComponentPage[]> {
38
+ "use cache"
39
+
40
+ cacheTag("notion")
41
+ cacheTag("notion-component-pages")
42
+
43
+ const directChildPages = await getDirectChildPages(NOTION_PAGE_ID)
44
+
45
+ return Promise.all(
46
+ directChildPages.map(async (page) => {
47
+ const childPages = await getDirectChildPages(page.id)
48
+
49
+ return {
50
+ childPageIds: childPages.map((childPage) => childPage.id),
51
+ id: page.id,
52
+ slug: pascalToKebabCase(page.title),
53
+ }
54
+ }),
55
+ )
56
+ }
@@ -0,0 +1,22 @@
1
+ import {
2
+ getChildBlocks,
3
+ type NotionBlock,
4
+ } from "@/app/(sidebar)/components/[...slugs]/get-child-block"
5
+
6
+ interface NotionPageSummary {
7
+ id: string
8
+ title: string
9
+ }
10
+
11
+ export async function getDirectChildPages(pageId: string): Promise<NotionPageSummary[]> {
12
+ const blocks = await getChildBlocks(pageId)
13
+ return blocks
14
+ .filter(
15
+ (block): block is Extract<NotionBlock, { type: "child_page" }> =>
16
+ "type" in block && block.type === "child_page",
17
+ )
18
+ .map((block) => ({
19
+ id: block.id.replaceAll("-", ""),
20
+ title: block.child_page.title,
21
+ }))
22
+ }
@@ -0,0 +1,25 @@
1
+ import { redirect } from "next/navigation"
2
+ import type { PropsWithChildren } from "react"
3
+ import { getComponentPageMatch } from "@/app/(sidebar)/components/[...slugs]/get-component-page-match"
4
+ import { NotionDocsLayout } from "@/components/notion/notion-docs-layout"
5
+
6
+ interface LayoutProps extends PropsWithChildren {
7
+ params: Promise<{
8
+ slugs: string[]
9
+ }>
10
+ }
11
+
12
+ export default async function Layout(props: LayoutProps) {
13
+ const { children, params } = props
14
+ const { slugs } = await params
15
+
16
+ const [slug] = slugs
17
+
18
+ const matchedPage = await getComponentPageMatch(slug)
19
+
20
+ if (!matchedPage) {
21
+ redirect("/")
22
+ }
23
+
24
+ return <NotionDocsLayout pageId={matchedPage.pageId}>{children}</NotionDocsLayout>
25
+ }
@@ -0,0 +1,32 @@
1
+ import { redirect } from "next/navigation"
2
+ import {
3
+ getComponentPageMatch,
4
+ getComponentPageSlugs,
5
+ } from "@/app/(sidebar)/components/[...slugs]/get-component-page-match"
6
+ import { NotionDocsCodePage } from "@/components/notion/notion-docs-code-page"
7
+
8
+ interface PageProps {
9
+ params: Promise<{
10
+ slugs: string[]
11
+ }>
12
+ }
13
+
14
+ export async function generateStaticParams() {
15
+ const slugs = await getComponentPageSlugs()
16
+ return slugs.map((slug) => ({ slugs: [slug] }))
17
+ }
18
+
19
+ export default async function Page(props: PageProps) {
20
+ const { params } = props
21
+ const { slugs } = await params
22
+
23
+ const [slug] = slugs
24
+
25
+ const matchedPage = await getComponentPageMatch(slug)
26
+
27
+ if (!matchedPage) {
28
+ redirect("/")
29
+ }
30
+
31
+ return <NotionDocsCodePage pageId={matchedPage.childPageId ?? ""} />
32
+ }
@@ -0,0 +1,9 @@
1
+ export function pascalToKebabCase(value: string) {
2
+ return value
3
+ .trim()
4
+ .replaceAll(/([A-Z]+)([A-Z][a-z])/g, "$1-$2")
5
+ .replaceAll(/([a-z0-9])([A-Z])/g, "$1-$2")
6
+ .replaceAll(/[\s_]+/g, "-")
7
+ .replaceAll(/-+/g, "-")
8
+ .toLowerCase()
9
+ }
@@ -0,0 +1,154 @@
1
+ import { IconArrowInbox, IconArrowLeft, IconArrowRight } from "@pump-fun/icons-line"
2
+ import { Button } from "@pump-fun/retail-design-system"
3
+
4
+ export default function ButtonPage() {
5
+ return (
6
+ <div className="flex flex-col gap-y-16">
7
+ <Button className="absolute top-64 right-64">Absolute</Button>
8
+
9
+ <p>Variant</p>
10
+ <div className="flex flex-wrap items-center gap-16">
11
+ <Button variant="primary">Primary</Button>
12
+ <Button variant="secondary">Secondary</Button>
13
+ <Button variant="ghost">Ghost</Button>
14
+ </div>
15
+
16
+ <p>Size</p>
17
+ <div className="flex flex-wrap items-center gap-16">
18
+ <Button size={32}>Add goal</Button>
19
+ <Button size={36}>Add goal</Button>
20
+ <Button size={40}>Add goal</Button>
21
+ <Button size={44}>Add goal</Button>
22
+ </div>
23
+
24
+ <p>Rounded</p>
25
+ <div className="flex flex-wrap items-center gap-16">
26
+ <Button isRounded variant="primary">
27
+ Add goal
28
+ </Button>
29
+ <Button isRounded variant="secondary">
30
+ Add goal
31
+ </Button>
32
+ <Button isRounded variant="ghost">
33
+ Add goal
34
+ </Button>
35
+ </div>
36
+
37
+ <p>Disabled</p>
38
+ <div className="flex flex-wrap items-center gap-16">
39
+ <Button isDisabled variant="primary">
40
+ Add goal
41
+ </Button>
42
+ <Button isDisabled variant="secondary">
43
+ Add goal
44
+ </Button>
45
+ <Button isDisabled variant="ghost">
46
+ Add goal
47
+ </Button>
48
+ </div>
49
+
50
+ <p>Loading</p>
51
+ <div className="flex flex-wrap items-center gap-16">
52
+ <Button isLoading variant="primary">
53
+ Add goal
54
+ </Button>
55
+ <Button isLoading variant="secondary">
56
+ Add goal
57
+ </Button>
58
+ <Button isLoading variant="ghost">
59
+ Add goal
60
+ </Button>
61
+ </div>
62
+
63
+ <p>Active</p>
64
+ <div className="flex flex-wrap items-center gap-16">
65
+ <Button isActive variant="primary">
66
+ Add goal
67
+ </Button>
68
+ <Button isActive variant="secondary">
69
+ Add goal
70
+ </Button>
71
+ <Button isActive variant="ghost">
72
+ Add goal
73
+ </Button>
74
+ </div>
75
+
76
+ <p>Icon</p>
77
+ <div className="flex flex-wrap items-center gap-16">
78
+ <Button
79
+ iconEnd={<IconArrowRight size={16} />}
80
+ iconStart={<IconArrowLeft size={16} />}
81
+ variant="primary"
82
+ >
83
+ Add goal
84
+ </Button>
85
+ <Button
86
+ iconEnd={<IconArrowRight size={16} />}
87
+ iconStart={<IconArrowLeft size={16} />}
88
+ variant="secondary"
89
+ >
90
+ Add goal
91
+ </Button>
92
+ <Button
93
+ iconEnd={<IconArrowRight size={16} />}
94
+ iconStart={<IconArrowLeft size={16} />}
95
+ variant="ghost"
96
+ >
97
+ Add goal
98
+ </Button>
99
+ </div>
100
+
101
+ <p>Full width</p>
102
+ <div className="flex flex-wrap items-center gap-16">
103
+ <Button className="max-w-320" isFullWidth>
104
+ Add goal
105
+ </Button>
106
+ </div>
107
+
108
+ <p>Icon only</p>
109
+ <div className="flex flex-wrap items-center gap-16">
110
+ <Button isIconOnly variant="primary">
111
+ <IconArrowInbox size={16} />
112
+ </Button>
113
+ <Button isIconOnly variant="secondary">
114
+ <IconArrowInbox size={16} />
115
+ </Button>
116
+ <Button isIconOnly variant="ghost">
117
+ <IconArrowInbox size={16} />
118
+ </Button>
119
+ </div>
120
+
121
+ <p>Icon only size</p>
122
+ <div className="flex flex-wrap items-center gap-16">
123
+ <Button isIconOnly size={32}>
124
+ <IconArrowInbox size={16} />
125
+ </Button>
126
+ <Button isIconOnly size={36}>
127
+ <IconArrowInbox size={16} />
128
+ </Button>
129
+ <Button isIconOnly size={40}>
130
+ <IconArrowInbox size={16} />
131
+ </Button>
132
+ <Button isIconOnly size={44}>
133
+ <IconArrowInbox size={18} />
134
+ </Button>
135
+ </div>
136
+
137
+ <p>Icon only loading</p>
138
+ <div className="flex flex-wrap items-center gap-16">
139
+ <Button isIconOnly isLoading size={32}>
140
+ <IconArrowInbox size={16} />
141
+ </Button>
142
+ <Button isIconOnly isLoading size={36}>
143
+ <IconArrowInbox size={16} />
144
+ </Button>
145
+ <Button isIconOnly isLoading size={40}>
146
+ <IconArrowInbox size={16} />
147
+ </Button>
148
+ <Button isIconOnly isLoading size={44}>
149
+ <IconArrowInbox size={18} />
150
+ </Button>
151
+ </div>
152
+ </div>
153
+ )
154
+ }
@@ -0,0 +1,98 @@
1
+ import {
2
+ IconArrowBoxRight,
3
+ IconArrowInbox,
4
+ IconCircleBanSign,
5
+ IconEmail1,
6
+ IconEyeOpen,
7
+ IconKey2,
8
+ IconSquareBehindSquare1,
9
+ } from "@pump-fun/icons-line"
10
+ import { Button, Input, Label } from "@pump-fun/retail-design-system"
11
+
12
+ export default function InputPage() {
13
+ return (
14
+ <div className="mx-auto flex max-w-320 flex-col">
15
+ <Label className="mb-4" htmlFor="email">
16
+ Email
17
+ </Label>
18
+ <div className="relative mb-16">
19
+ <IconEmail1 className="absolute top-12 left-12 text-zinc-200" size={16} />
20
+ <Input className="pl-36!" id="email" placeholder="name@example.com" type="email" />
21
+ </div>
22
+
23
+ <Label className="mb-4" htmlFor="password">
24
+ Password
25
+ </Label>
26
+ <div className="relative mb-16">
27
+ <IconKey2 className="absolute top-12 left-12 text-zinc-200" size={16} />
28
+ <Input className="px-36!" id="password" placeholder="••••••••" type="password" />
29
+ <Button className="group absolute! top-4 right-4" isIconOnly size={32} variant="ghost">
30
+ <IconEyeOpen
31
+ className="text-zinc-200 transition-colors group-hover:text-zinc-50 group-active:text-zinc-50"
32
+ size={16}
33
+ />
34
+ </Button>
35
+ </div>
36
+
37
+ <Button iconStart={<IconArrowBoxRight size={16} />} isFullWidth size={44}>
38
+ Sign in
39
+ </Button>
40
+
41
+ <div className="h-80" />
42
+
43
+ <Label className="mb-4" htmlFor="disabled">
44
+ Disabled
45
+ </Label>
46
+ <div className="relative">
47
+ <IconCircleBanSign className="absolute top-12 left-12 text-zinc-200" size={16} />
48
+ <Input className="pl-36!" id="disabled" isDisabled placeholder="Disabled" type="url" />
49
+ </div>
50
+
51
+ <div className="h-80" />
52
+
53
+ <Label className="mb-4" htmlFor="read-only">
54
+ Read Only
55
+ </Label>
56
+ <div className="relative">
57
+ <Input
58
+ className="pr-36!"
59
+ defaultValue="This is a read-only input"
60
+ id="read-only"
61
+ isReadOnly
62
+ type="text"
63
+ />
64
+ <Button className="group absolute! top-4 right-4" isIconOnly size={32} variant="ghost">
65
+ <IconSquareBehindSquare1
66
+ className="group-active:text-zinc-5000 text-zinc-200 transition-colors group-hover:text-gray-100"
67
+ size={16}
68
+ />
69
+ </Button>
70
+ </div>
71
+
72
+ <div className="h-80" />
73
+
74
+ <Label className="mb-4" htmlFor="input-with-end-icon-button">
75
+ Input with end icon button
76
+ </Label>
77
+ <div className="flex">
78
+ <Input
79
+ className="rounded-r-none! hover:z-10 focus-visible:z-80"
80
+ id="input-with-end-icon-button"
81
+ placeholder="Download"
82
+ type="url"
83
+ />
84
+ <Button
85
+ className="group -ml-px rounded-l-none! shadow-none! hover:z-10 focus-visible:z-80"
86
+ isIconOnly
87
+ size={40}
88
+ variant="secondary"
89
+ >
90
+ <IconArrowInbox
91
+ className="text-zinc-200 transition-colors group-hover:text-zinc-50 group-active:text-zinc-50"
92
+ size={16}
93
+ />
94
+ </Button>
95
+ </div>
96
+ </div>
97
+ )
98
+ }
@@ -0,0 +1,9 @@
1
+ export function MayhemModeCardBadge() {
2
+ return (
3
+ <div className="flex size-16 items-center justify-center rounded-full bg-linear-to-b from-green-300 to-red-500">
4
+ <div className="flex size-14 items-center justify-center rounded-full bg-zinc-600">
5
+ <img alt="Pump logomark" className="size-8" src="/pump-logomark.svg" />
6
+ </div>
7
+ </div>
8
+ )
9
+ }
@@ -0,0 +1,14 @@
1
+ import { IconTrending1 } from "@pump-fun/icons-line"
2
+
3
+ export function MayhemModeCoinActiveBadge() {
4
+ return (
5
+ <div className="flex h-18 w-fit items-center justify-center rounded-full bg-linear-to-b from-green-300 to-red-500 p-1">
6
+ <div className="bg-bg-secondary flex h-full items-center justify-center gap-x-2 rounded-full pr-4 pl-6">
7
+ <IconTrending1 className="text-text-accent" size={14} />
8
+ <p className="font-500 text-12 bg-linear-to-b from-green-300 from-50% to-red-500 bg-clip-text text-transparent tabular-nums">
9
+ 63:42:32
10
+ </p>
11
+ </div>
12
+ </div>
13
+ )
14
+ }
@@ -0,0 +1,12 @@
1
+ import { IconTrending1 } from "@pump-fun/icons-line"
2
+
3
+ export function MayhemModeCoinInactiveBadge() {
4
+ return (
5
+ <div className="rounded-8 flex h-28 w-fit items-center justify-center bg-linear-to-b from-green-300 to-red-500 p-1">
6
+ <div className="rounded-8 bg-bg-secondary flex h-full items-center justify-center gap-x-8 px-12">
7
+ <IconTrending1 className="text-text-muted" size={14} />
8
+ <p className="font-500 text-12 text-text-on-muted tabular-nums">Mayhem</p>
9
+ </div>
10
+ </div>
11
+ )
12
+ }
@@ -0,0 +1,44 @@
1
+ import { Switch, Tooltip } from "@base-ui/react"
2
+ import { IconCircleInfo } from "@pump-fun/icons-filled"
3
+ import { MayhemModeDialogIcon } from "@/app/(sidebar)/experiments/2025-10-22/mayhem-mode-dialog-icon"
4
+
5
+ export function MayhemModeCreateCoin() {
6
+ return (
7
+ <div className="rounded-12 bg-bg-secondary flex items-center gap-x-8 p-12">
8
+ <div className="shrink-0">
9
+ <MayhemModeDialogIcon />
10
+ </div>
11
+ <div className="flex w-full flex-col gap-y-1">
12
+ <div className="flex items-center gap-x-4">
13
+ <p className="font-600 text-12 text-text-primary">Mayhem mode</p>
14
+
15
+ <Tooltip.Root>
16
+ <Tooltip.Trigger>
17
+ <IconCircleInfo className="shrink-0" size={16} />
18
+ </Tooltip.Trigger>
19
+ <Tooltip.Portal>
20
+ <Tooltip.Positioner sideOffset={4}>
21
+ <Tooltip.Popup className="rounded-8 bg-bg-secondary outline-border-secondary flex origin-[var(--transform-origin)] flex-col px-6 py-2 text-sm outline transition-[transform,scale,opacity] data-[ending-style]:scale-90 data-[ending-style]:opacity-0 data-[instant]:duration-0 data-[starting-style]:scale-90 data-[starting-style]:opacity-0">
22
+ <p className="text-14 text-text-secondary">Not sure what to put here.</p>
23
+ </Tooltip.Popup>
24
+ </Tooltip.Positioner>
25
+ </Tooltip.Portal>
26
+ </Tooltip.Root>
27
+
28
+ <div className="rounded-6 bg-bg-accent font-600 text-text-on-accent flex h-16 items-center px-6 text-[10px]">
29
+ New
30
+ </div>
31
+ </div>
32
+ <p className="text-12 text-text-tertiary">Temporary increased volatility.</p>
33
+ </div>
34
+ <div className="shrink-0">
35
+ <Switch.Root
36
+ className="from-bg-accent before:outline-bg-accent relative flex h-24 w-40 rounded-full bg-gradient-to-r from-35% to-zinc-500 to-65% bg-[length:120px_100%] bg-[100%_0%] bg-no-repeat p-2 transition-[background-position,box-shadow] duration-[125ms] ease-[cubic-bezier(0.26,0.75,0.38,0.45)] before:absolute before:rounded-full before:outline-offset-2 focus-visible:before:inset-0 focus-visible:before:outline-2 data-[checked]:bg-[0%_0%]"
37
+ defaultChecked
38
+ >
39
+ <Switch.Thumb className="aspect-square h-full rounded-full bg-zinc-50 transition-transform duration-150 data-[checked]:translate-x-16" />
40
+ </Switch.Root>
41
+ </div>
42
+ </div>
43
+ )
44
+ }
@@ -0,0 +1,47 @@
1
+ export function MayhemModeDialogIcon() {
2
+ return (
3
+ <svg fill="none" height="40" viewBox="0 0 41 40" width="41" xmlns="http://www.w3.org/2000/svg">
4
+ <title>Mayhem mode dialog icon</title>
5
+ <rect fill="#18181B" height="39" rx="7.5" width="39" x="1" y="0.5" />
6
+ <rect height="39" rx="7.5" stroke="url(#paint0_linear_12893_5347)" width="39" x="1" y="0.5" />
7
+ <path
8
+ d="M13 20.8426L13.8079 18.9134C14.1063 18.2009 15.1233 18.2401 15.3665 18.9735L16.3505 21.9418C16.6063 22.7133 17.6952 22.703 17.9365 21.9267L20.4246 13.9213C20.6775 13.1075 21.8369 13.1493 22.0312 13.9793L24.849 26.0206C25.0396 26.835 26.169 26.8965 26.446 26.1076L28 21.6805"
9
+ stroke="#FAFAFA"
10
+ strokeLinecap="round"
11
+ strokeLinejoin="round"
12
+ strokeWidth="2"
13
+ />
14
+ <path
15
+ d="M13 20.8426L13.8079 18.9134C14.1063 18.2009 15.1233 18.2401 15.3665 18.9735L16.3505 21.9418C16.6063 22.7133 17.6952 22.703 17.9365 21.9267L20.4246 13.9213C20.6775 13.1075 21.8369 13.1493 22.0312 13.9793L24.849 26.0206C25.0396 26.835 26.169 26.8965 26.446 26.1076L28 21.6805"
16
+ stroke="url(#paint1_linear_12893_5347)"
17
+ strokeLinecap="round"
18
+ strokeLinejoin="round"
19
+ strokeWidth="2"
20
+ />
21
+ <defs>
22
+ <linearGradient
23
+ gradientUnits="userSpaceOnUse"
24
+ id="paint0_linear_12893_5347"
25
+ x1="20.5"
26
+ x2="20.5"
27
+ y1="40"
28
+ y2="-2.83122e-06"
29
+ >
30
+ <stop stopColor="#F43F5E" />
31
+ <stop offset="1" stopColor="#86EFAC" />
32
+ </linearGradient>
33
+ <linearGradient
34
+ gradientUnits="userSpaceOnUse"
35
+ id="paint1_linear_12893_5347"
36
+ x1="20.5"
37
+ x2="20.5"
38
+ y1="26.6666"
39
+ y2="13.3333"
40
+ >
41
+ <stop stopColor="#F43F5E" />
42
+ <stop offset="1" stopColor="#86EFAC" />
43
+ </linearGradient>
44
+ </defs>
45
+ </svg>
46
+ )
47
+ }