@digital-ai/dot-illustrations 2.0.37 → 2.0.39

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.
package/demo/demo.css CHANGED
@@ -1,95 +1,19 @@
1
- * {
2
- box-sizing: border-box;
3
- }
4
-
5
- body {
6
- font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
7
- margin: 0 auto;
8
- height: 100%;
9
- text-align: center;
10
- }
1
+ /* dot-illustrations demo — custom styles
2
+ Tailwind handles layout; this file fills the gaps. */
11
3
 
12
- img {
13
- align-items: center;
14
- height: 160px;
15
- width: 160px;
16
- max-width: 160px;
17
- max-height: 160px;
18
- min-width: 92px;
19
- min-height: 92px;
20
- margin: auto;
21
- }
4
+ *, *::before, *::after { box-sizing: border-box; }
22
5
 
23
- span {
24
- margin: 0 auto;
25
- display: flex;
26
- flex-wrap: wrap;
27
- font-family: 'Lato', sans-serif;
28
- font-size: 14px;
29
- margin-top: 8px;
30
- text-align: center;
31
- color: #667385;
32
- z-index: 0;
33
- }
6
+ /* ── Prevent legacy img rule from overriding card images ─────────────────── */
7
+ /* Only illustration img elements inside .dot-illustration get size treatment */
8
+ .dot-illustration img { display: block; }
34
9
 
35
- .copy-container{}
10
+ /* ── Hidden clipboard source ────────────────────────────────────────────── */
11
+ .codeBlock { display: none !important; }
36
12
 
37
- /* Tooltip for copy buttons */
38
- .tooltiptext {
39
- visibility: hidden;
40
- background-color: black;
41
- color: #fff;
42
- text-align: center;
43
- border-radius: 5px;
44
- padding: 5px;
45
- position: absolute;
46
- z-index: 1;
47
- bottom: 125%;
48
- left: 50%;
49
- transform: translateX(-50%);
50
- opacity: 0;
51
- transition: opacity 0.3s;
52
- white-space: nowrap;
53
- }
54
-
55
- .button:hover .tooltiptext {
56
- visibility: visible;
57
- opacity: 1;
58
- }
59
-
60
- .codeBlock {
61
- visibility: hidden;
62
- white-space: pre-wrap;
63
- background-color: #f4f4f4;
64
- padding: 10px;
65
- border: 1px solid #ddd;
66
- border-radius: 5px;
67
- max-width: 300px;
68
- overflow: auto;
69
- }
70
-
71
- .codeInclude {
72
- color: rgb(43, 50, 55);
73
- white-space: pre-wrap;
74
- background-color: #f4f4f4;
75
- padding: 10px;
76
- border: 1px solid #ddd;
77
- border-radius: 5px;
78
- max-width: 300px;
79
- overflow: auto;
80
- }
81
-
82
- /* When dark mode is active */
83
- body.dark-mode .dot-illustration img.light {
84
- display: none;
85
- }
86
-
87
- body.dark-mode .dot-illustration img.dark {
88
- display: block;
89
- background-color: #232E40;
90
- border-radius: 8px;
91
- }
13
+ /* ── Tooltip (legacy compat — kept for copyText/copyCode) ───────────────── */
14
+ .tooltiptext { display: none; }
92
15
 
16
+ /* ── Floating bar — hidden off-screen, slides in on scroll ─────────────── */
93
17
  #floating-bar {
94
18
  pointer-events: none;
95
19
  opacity: 0;
@@ -99,110 +23,40 @@ body.dark-mode .dot-illustration img.dark {
99
23
  pointer-events: auto;
100
24
  opacity: 1;
101
25
  transform: translateY(0);
102
- transition: transform 0.3s cubic-bezier(0.4,0,0.2,1), opacity 0.3s cubic-bezier(0.4,0,0.2,1);
103
- }
104
- .floating-search {
105
- min-width: 0;
106
- width: 120px;
107
- max-width: 200px;
108
- }
109
- @media (min-width: 640px) {
110
- .floating-search {
111
- width: 200px;
112
- max-width: 320px;
113
- }
114
- }
115
- .floating-tab {
116
- min-width: 60px;
117
- padding-left: 0.75rem;
118
- padding-right: 0.75rem;
119
- font-size: 0.85rem;
26
+ transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1),
27
+ opacity 0.28s cubic-bezier(0.4, 0, 0.2, 1);
120
28
  }
121
29
 
122
- /* Modal styles */
123
- #illustration-modal {
124
- display: none;
125
- align-items: center;
126
- justify-content: center;
127
- background: rgba(0,0,0,0.5);
128
- }
129
- #illustration-modal.active {
130
- display: flex;
131
- }
132
- #illustration-modal .modal-content {
133
- background: white;
134
- border-radius: 1rem;
135
- box-shadow: 0 10px 40px rgba(0,0,0,0.2);
136
- max-width: 90vw;
137
- max-height: 90vh;
138
- overflow-y: auto;
139
- padding: 2rem;
140
- position: relative;
141
- }
142
- #illustration-modal .modal-image img {
143
- width: 220px;
144
- height: 220px;
145
- object-fit: contain;
146
- border-radius: 0.75rem;
147
- background: #f3f4f6;
148
- margin-bottom: 1rem;
149
- }
150
- #illustration-modal .iconID {
151
- font-size: 1.2rem;
152
- font-weight: 600;
153
- }
154
- #illustration-modal .button-group {
155
- margin-bottom: 1rem;
156
- }
157
- #illustration-modal #modal-close {
158
- position: absolute;
159
- top: 1rem;
160
- right: 1rem;
161
- background: none;
162
- border: none;
163
- font-size: 2rem;
164
- color: #aaa;
165
- cursor: pointer;
166
- z-index: 10;
167
- transition: color 0.2s;
30
+ /* ── Scrollable navs (no scrollbar) ─────────────────────────────────────── */
31
+ #illus-sub-tabs,
32
+ #floating-tabs,
33
+ #section-switcher {
34
+ overflow-x: auto;
35
+ scrollbar-width: none;
168
36
  }
169
- #illustration-modal #modal-close:hover {
170
- color: #333;
37
+ #illus-sub-tabs::-webkit-scrollbar,
38
+ #floating-tabs::-webkit-scrollbar,
39
+ #section-switcher::-webkit-scrollbar { display: none; }
40
+
41
+ /* ── GitHub user badge ──────────────────────────────────────────────────── */
42
+ #gh-user-badge { display: none; }
43
+ #gh-user-badge.connected { display: flex; }
44
+
45
+ /* ── Card grid items — slide-up action bar ──────────────────────────────── */
46
+ .copy-container { position: relative; }
47
+ .copy-container .action-bar {
48
+ transform: translateY(100%);
49
+ transition: transform 0.15s ease-out;
171
50
  }
172
- @media (max-width: 600px) {
173
- #illustration-modal .modal-content {
174
- padding: 1rem;
175
- max-width: 98vw;
176
- }
177
- #illustration-modal .modal-image img {
178
- width: 140px;
179
- height: 140px;
180
- }
51
+ .copy-container:hover .action-bar {
52
+ transform: translateY(0);
181
53
  }
182
54
 
183
55
  /* ── Alphabet strip ─────────────────────────────────────────────────────── */
184
56
  #alphabet-strip {
185
57
  display: flex;
186
58
  flex-wrap: wrap;
187
- justify-content: center;
188
- gap: 0.25rem;
189
- }
190
-
191
- /* ── Tab nav horizontal scroll ──────────────────────────────────────────── */
192
- #main-tabs {
193
- overflow-x: auto;
194
- scrollbar-width: none;
195
- }
196
- #main-tabs::-webkit-scrollbar { display: none; }
197
- #floating-tabs { scrollbar-width: none; }
198
- #floating-tabs::-webkit-scrollbar { display: none; }
199
-
200
- /* ── GitHub user badge flex ─────────────────────────────────────────────── */
201
- #gh-user-badge[style*="flex"] { display: flex !important; }
202
-
203
- /* ── Integration card image sizing ─────────────────────────────────────── */
204
- .dot-integration img {
205
- width: 100%;
206
- height: 100%;
207
- object-fit: contain;
59
+ align-items: center;
60
+ gap: 0.125rem;
61
+ row-gap: 0.25rem;
208
62
  }
package/demo/index.html CHANGED
@@ -78,134 +78,160 @@
78
78
  <!-- ── Page body ──────────────────────────────────────────────────────── -->
79
79
  <main class="max-w-7xl mx-auto px-4 py-6">
80
80
 
81
- <!-- Search -->
82
- <div class="relative mb-5 max-w-xl">
83
- <svg class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"/></svg>
84
- <input id="myInput" type="text" autocomplete="off" placeholder="Search illustrations and integrations…"
85
- class="w-full pl-10 pr-4 py-2.5 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl text-sm text-gray-900 dark:text-white outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 transition">
86
- <div id="search-suggestions" class="absolute top-full left-0 right-0 z-50 mt-1 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-lg hidden max-h-64 overflow-y-auto"></div>
87
- </div>
88
-
89
- <!-- Section switcher: Illustrations | Integrations -->
90
- <div class="flex items-center gap-1 mb-5 bg-gray-100 dark:bg-gray-800 rounded-xl p-1 w-fit" id="section-switcher">
91
- <button id="section-illustrations" data-section="illustrations"
92
- class="section-btn px-5 py-2 text-sm font-semibold rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm focus:outline-none transition">
93
- 🖼 Illustrations
94
- </button>
95
- <button id="section-integrations" data-section="integrations"
96
- class="section-btn px-5 py-2 text-sm font-semibold rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white focus:outline-none transition">
97
- 🔌 Integrations
98
- </button>
81
+ <!-- Row 1: Search + Section switcher -->
82
+ <div class="flex items-center gap-3 mb-4">
83
+ <div class="relative flex-1">
84
+ <svg class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400 pointer-events-none" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"/></svg>
85
+ <input id="myInput" type="text" autocomplete="off" placeholder="Search…"
86
+ class="w-full pl-10 pr-4 py-2.5 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl text-sm text-gray-900 dark:text-white outline-none focus:border-blue-500 focus:ring-2 focus:ring-blue-500/20 transition">
87
+ <div id="search-suggestions" class="absolute top-full left-0 right-0 z-50 mt-1 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl shadow-lg hidden max-h-64 overflow-y-auto"></div>
88
+ </div>
89
+ <!-- Section switcher inline with search -->
90
+ <div class="flex items-center bg-gray-100 dark:bg-gray-800 rounded-xl p-1 shrink-0" id="section-switcher">
91
+ <button id="section-illustrations" data-section="illustrations"
92
+ class="section-btn px-4 py-1.5 text-sm font-semibold rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm focus:outline-none transition whitespace-nowrap">
93
+ Illustrations
94
+ </button>
95
+ <button id="section-integrations" data-section="integrations"
96
+ class="section-btn px-4 py-1.5 text-sm font-semibold rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white focus:outline-none transition whitespace-nowrap">
97
+ Integrations
98
+ </button>
99
+ </div>
99
100
  </div>
100
101
 
101
- <!-- Illustration sub-tabs -->
102
- <div id="illus-sub-tabs" class="flex items-center gap-1 mb-4 bg-gray-100 dark:bg-gray-800 rounded-xl p-1 w-fit" role="tablist">
103
- <button class="tab-btn px-4 py-1.5 text-sm font-medium rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm focus:outline-none transition" data-tab="all" role="tab">All</button>
104
- <button class="tab-btn px-4 py-1.5 text-sm font-medium rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white focus:outline-none transition" data-tab="global" role="tab">Global</button>
105
- <button class="tab-btn px-4 py-1.5 text-sm font-medium rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white focus:outline-none transition" data-tab="dashboards" role="tab">Dashboards</button>
106
- <button class="tab-btn px-4 py-1.5 text-sm font-medium rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white focus:outline-none transition" data-tab="favourites" role="tab">Favourites ⭐</button>
102
+ <!-- Row 2: Sub-tabs (illustrations) + Alphabet strip -->
103
+ <div class="flex items-center justify-between gap-4 mb-4 flex-wrap">
104
+ <div id="illus-sub-tabs" class="flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded-xl p-1 w-fit" role="tablist">
105
+ <button class="tab-btn px-3 py-1.5 text-sm font-medium rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm focus:outline-none transition" data-tab="all" role="tab">All</button>
106
+ <button class="tab-btn px-3 py-1.5 text-sm font-medium rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white focus:outline-none transition" data-tab="global" role="tab">Global</button>
107
+ <button class="tab-btn px-3 py-1.5 text-sm font-medium rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white focus:outline-none transition" data-tab="dashboards" role="tab">Dashboards</button>
108
+ <button class="tab-btn px-3 py-1.5 text-sm font-medium rounded-lg text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-white focus:outline-none transition" data-tab="favourites" role="tab">Favourites</button>
109
+ </div>
110
+ <div id="alphabet-strip" class="hidden items-center flex-wrap gap-0.5"></div>
107
111
  </div>
108
112
 
109
- <!-- Alphabet filter -->
110
- <div id="alphabet-strip" class="hidden flex flex-wrap gap-1 mb-4"></div>
111
-
112
113
  <!-- Result count -->
113
114
  <p id="result-count" class="text-xs text-gray-400 dark:text-gray-500 mb-3"></p>
114
115
 
115
116
  <!-- Grid -->
116
117
  <div id="illustration-list"
117
- class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-3 max-h-[calc(100vh-280px)] overflow-y-auto pr-1">
118
+ class="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-6 gap-3 max-h-[calc(100vh-280px)] overflow-y-auto pr-1">
118
119
  </div>
119
120
 
120
- <!-- Upload panel (slide-in below header) -->
121
- <div id="upload-panel" class="hidden mt-6">
122
- <div class="bg-white dark:bg-gray-900 rounded-2xl border border-gray-200 dark:border-gray-700 shadow-lg p-6 max-w-2xl">
123
- <h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-5">Upload new asset → Create PR</h2>
124
- <div class="grid md:grid-cols-2 gap-6">
121
+ <!-- Upload modal rendered as fixed overlay, NOT inline -->
122
+ <div id="upload-panel" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/40 dark:bg-black/60 backdrop-blur-sm p-4">
125
123
 
126
- <!-- Illustration upload -->
127
- <div class="flex flex-col gap-3">
128
- <h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 flex items-center gap-2">
129
- <span class="w-5 h-5 bg-purple-100 dark:bg-purple-900/40 text-purple-700 dark:text-purple-300 rounded text-xs flex items-center justify-center">🖼</span>
130
- Illustration (light + dark)
131
- </h3>
132
- <div id="upload-illus-auth-gate" class="flex items-center gap-2 p-3 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg text-xs text-amber-700 dark:text-amber-300">
133
- <svg class="w-4 h-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"/></svg>
134
- Connect GitHub to enable uploads
124
+ <!-- Modal inner container -->
125
+ <div class="relative bg-white dark:bg-gray-900 rounded-2xl shadow-2xl border border-gray-200 dark:border-gray-700 w-full max-w-md max-h-[90vh] overflow-y-auto">
126
+ <button id="upload-modal-close" class="absolute top-4 right-4 z-10 p-1.5 rounded-lg text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 transition">
127
+ <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12"/></svg>
128
+ </button>
129
+
130
+ <!-- Step 1: choose type -->
131
+ <div id="upload-type-picker" class="p-6">
132
+ <h2 class="text-base font-semibold text-gray-900 dark:text-white mb-1">What do you want to upload?</h2>
133
+ <p class="text-xs text-gray-400 dark:text-gray-500 mb-5">A PR will be created automatically once you fill in the details.</p>
134
+ <div class="grid grid-cols-2 gap-3">
135
+ <button id="pick-illustration"
136
+ class="flex flex-col items-center gap-3 p-5 rounded-xl border-2 border-gray-200 dark:border-gray-700 hover:border-blue-500 dark:hover:border-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition group focus:outline-none focus:border-blue-500">
137
+ <span class="text-4xl">🖼</span>
138
+ <div class="text-center">
139
+ <p class="text-sm font-semibold text-gray-900 dark:text-white group-hover:text-blue-700 dark:group-hover:text-blue-300 transition">Illustration</p>
140
+ <p class="text-xs text-gray-400 dark:text-gray-500 mt-0.5">Light + dark SVG variants</p>
135
141
  </div>
136
- <div id="upload-illus-form" class="hidden flex flex-col gap-3">
137
- <input id="upload-illus-id" type="text" placeholder="Illustration ID (e.g. my-illustration)"
138
- class="w-full px-3 py-2 text-sm bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white outline-none focus:border-blue-500 transition">
139
- <select id="upload-illus-category"
140
- class="w-full px-3 py-2 text-sm bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white outline-none focus:border-blue-500 transition">
141
- <option value="global">Global</option>
142
- <option value="dashboards">Dashboards</option>
143
- </select>
144
- <div class="grid grid-cols-2 gap-2">
145
- <label class="flex flex-col gap-1">
146
- <span class="text-xs text-gray-500 dark:text-gray-400">☀️ Light SVG</span>
147
- <div id="illus-light-drop" class="border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-lg p-3 text-center text-xs text-gray-400 cursor-pointer hover:border-blue-400 transition">
148
- Drop or click<input id="illus-light-input" type="file" accept=".svg" class="hidden">
149
- </div>
150
- <p id="illus-light-name" class="hidden text-xs text-green-600 dark:text-green-400 truncate"></p>
151
- </label>
152
- <label class="flex flex-col gap-1">
153
- <span class="text-xs text-gray-500 dark:text-gray-400">🌙 Dark SVG</span>
154
- <div id="illus-dark-drop" class="border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-lg p-3 text-center text-xs text-gray-400 cursor-pointer hover:border-blue-400 transition">
155
- Drop or click<input id="illus-dark-input" type="file" accept=".svg" class="hidden">
156
- </div>
157
- <p id="illus-dark-name" class="hidden text-xs text-green-600 dark:text-green-400 truncate"></p>
158
- </label>
159
- </div>
160
- <button id="upload-illus-btn"
161
- class="w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition disabled:opacity-50">
162
- Create Pull Request
163
- </button>
164
- <div id="upload-illus-status" class="hidden text-xs text-center"></div>
165
- <div id="upload-illus-pr-link" class="hidden">
166
- <a id="upload-illus-pr-anchor" href="#" target="_blank"
167
- class="flex items-center justify-center gap-2 px-4 py-2 bg-green-600 hover:bg-green-700 text-white text-sm font-medium rounded-lg transition">
168
- View Pull Request ↗
169
- </a>
170
- </div>
142
+ </button>
143
+ <button id="pick-integration"
144
+ class="flex flex-col items-center gap-3 p-5 rounded-xl border-2 border-gray-200 dark:border-gray-700 hover:border-blue-500 dark:hover:border-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition group focus:outline-none focus:border-blue-500">
145
+ <span class="text-4xl">🔌</span>
146
+ <div class="text-center">
147
+ <p class="text-sm font-semibold text-gray-900 dark:text-white group-hover:text-blue-700 dark:group-hover:text-blue-300 transition">Integration</p>
148
+ <p class="text-xs text-gray-400 dark:text-gray-500 mt-0.5">Single SVG, no dark variant</p>
171
149
  </div>
150
+ </button>
151
+ </div>
152
+ </div>
153
+
154
+ <!-- Step 2a: Illustration form -->
155
+ <div id="upload-illus-panel" class="hidden p-6 flex flex-col gap-4">
156
+ <div class="flex items-center gap-3 mb-1">
157
+ <button id="back-from-illus" class="text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition">
158
+ <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18"/></svg>
159
+ </button>
160
+ <div>
161
+ <h2 class="text-base font-semibold text-gray-900 dark:text-white">🖼 Upload Illustration</h2>
162
+ <p class="text-xs text-gray-400 dark:text-gray-500">Requires light and dark SVG variants</p>
172
163
  </div>
164
+ </div>
173
165
 
174
- <!-- Integration upload -->
175
- <div class="flex flex-col gap-3">
176
- <h3 class="text-sm font-semibold text-gray-700 dark:text-gray-300 flex items-center gap-2">
177
- <span class="w-5 h-5 bg-blue-100 dark:bg-blue-900/40 text-blue-700 dark:text-blue-300 rounded text-xs flex items-center justify-center">🔌</span>
178
- Integration logo (single SVG)
179
- </h3>
180
- <div id="upload-integ-auth-gate" class="flex items-center gap-2 p-3 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg text-xs text-amber-700 dark:text-amber-300">
181
- <svg class="w-4 h-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"/></svg>
182
- Connect GitHub to enable uploads
183
- </div>
184
- <div id="upload-integ-form" class="hidden flex flex-col gap-3">
185
- <input id="upload-integ-id" type="text" placeholder="Integration ID (e.g. my-tool)"
186
- class="w-full px-3 py-2 text-sm bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white outline-none focus:border-blue-500 transition">
187
- <div id="integ-svg-drop" class="border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-lg p-4 text-center text-sm text-gray-400 cursor-pointer hover:border-blue-400 transition">
188
- Drop SVG here or click to browse<input id="integ-svg-input" type="file" accept=".svg" class="hidden">
166
+ <div id="upload-illus-auth-gate" class="flex items-center gap-2 p-3 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg text-xs text-amber-700 dark:text-amber-300">
167
+ <svg class="w-4 h-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"/></svg>
168
+ Connect GitHub to enable uploads
169
+ </div>
170
+ <div id="upload-illus-form" class="hidden flex flex-col gap-3">
171
+ <input id="upload-illus-id" type="text" placeholder="Illustration ID (e.g. my-illustration)"
172
+ class="w-full px-3 py-2 text-sm bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white outline-none focus:border-blue-500 transition">
173
+ <select id="upload-illus-category"
174
+ class="w-full px-3 py-2 text-sm bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white outline-none focus:border-blue-500 transition">
175
+ <option value="global">Global</option>
176
+ <option value="dashboards">Dashboards</option>
177
+ </select>
178
+ <div class="grid grid-cols-2 gap-3">
179
+ <div>
180
+ <p class="text-xs text-gray-500 dark:text-gray-400 mb-1">☀️ Light SVG <span class="text-red-400">*</span></p>
181
+ <div id="illus-light-drop" class="border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-lg p-4 text-center text-xs text-gray-400 cursor-pointer hover:border-blue-400 transition">
182
+ Drop or click<input id="illus-light-input" type="file" accept=".svg" class="hidden">
189
183
  </div>
190
- <p id="integ-svg-name" class="hidden text-xs text-green-600 dark:text-green-400 truncate"></p>
191
- <p class="text-xs text-gray-400 dark:text-gray-500">Single-theme only — no dark variant for integrations.</p>
192
- <button id="upload-integ-btn"
193
- class="w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition disabled:opacity-50">
194
- Create Pull Request
195
- </button>
196
- <div id="upload-integ-status" class="hidden text-xs text-center"></div>
197
- <div id="upload-integ-pr-link" class="hidden">
198
- <a id="upload-integ-pr-anchor" href="#" target="_blank"
199
- class="flex items-center justify-center gap-2 px-4 py-2 bg-green-600 hover:bg-green-700 text-white text-sm font-medium rounded-lg transition">
200
- View Pull Request ↗
201
- </a>
184
+ <p id="illus-light-name" class="hidden text-xs text-green-600 dark:text-green-400 mt-1 truncate"></p>
185
+ </div>
186
+ <div>
187
+ <p class="text-xs text-gray-500 dark:text-gray-400 mb-1">🌙 Dark SVG <span class="text-red-400">*</span></p>
188
+ <div id="illus-dark-drop" class="border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-lg p-4 text-center text-xs text-gray-400 cursor-pointer hover:border-blue-400 transition">
189
+ Drop or click<input id="illus-dark-input" type="file" accept=".svg" class="hidden">
202
190
  </div>
191
+ <p id="illus-dark-name" class="hidden text-xs text-green-600 dark:text-green-400 mt-1 truncate"></p>
203
192
  </div>
204
193
  </div>
194
+ <button id="upload-illus-btn" class="w-full px-4 py-2.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition disabled:opacity-50">Create Pull Request</button>
195
+ <div id="upload-illus-status" class="hidden text-xs text-center"></div>
196
+ <div id="upload-illus-pr-link" class="hidden">
197
+ <a id="upload-illus-pr-anchor" href="#" target="_blank" class="flex items-center justify-center gap-2 px-4 py-2 bg-green-600 hover:bg-green-700 text-white text-sm font-medium rounded-lg transition">View Pull Request ↗</a>
198
+ </div>
199
+ </div>
200
+ </div>
201
+
202
+ <!-- Step 2b: Integration form -->
203
+ <div id="upload-integ-panel" class="hidden p-6 flex flex-col gap-4">
204
+ <div class="flex items-center gap-3 mb-1">
205
+ <button id="back-from-integ" class="text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition">
206
+ <svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M10.5 19.5L3 12m0 0l7.5-7.5M3 12h18"/></svg>
207
+ </button>
208
+ <div>
209
+ <h2 class="text-base font-semibold text-gray-900 dark:text-white">🔌 Upload Integration</h2>
210
+ <p class="text-xs text-gray-400 dark:text-gray-500">Single SVG — no dark variant required</p>
211
+ </div>
212
+ </div>
205
213
 
214
+ <div id="upload-integ-auth-gate" class="flex items-center gap-2 p-3 bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg text-xs text-amber-700 dark:text-amber-300">
215
+ <svg class="w-4 h-4 shrink-0" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"/></svg>
216
+ Connect GitHub to enable uploads
217
+ </div>
218
+ <div id="upload-integ-form" class="hidden flex flex-col gap-3">
219
+ <input id="upload-integ-id" type="text" placeholder="Integration ID (e.g. my-tool)"
220
+ class="w-full px-3 py-2 text-sm bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white outline-none focus:border-blue-500 transition">
221
+ <div id="integ-svg-drop" class="border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-xl p-6 text-center text-sm text-gray-400 cursor-pointer hover:border-blue-400 transition">
222
+ Drop SVG here or click to browse<input id="integ-svg-input" type="file" accept=".svg" class="hidden">
223
+ </div>
224
+ <p id="integ-svg-name" class="hidden text-xs text-green-600 dark:text-green-400 truncate"></p>
225
+ <button id="upload-integ-btn" class="w-full px-4 py-2.5 bg-blue-600 hover:bg-blue-700 text-white text-sm font-medium rounded-lg transition disabled:opacity-50">Create Pull Request</button>
226
+ <div id="upload-integ-status" class="hidden text-xs text-center"></div>
227
+ <div id="upload-integ-pr-link" class="hidden">
228
+ <a id="upload-integ-pr-anchor" href="#" target="_blank" class="flex items-center justify-center gap-2 px-4 py-2 bg-green-600 hover:bg-green-700 text-white text-sm font-medium rounded-lg transition">View Pull Request ↗</a>
229
+ </div>
206
230
  </div>
207
231
  </div>
208
- </div>
232
+
233
+ </div><!-- /modal inner container -->
234
+ </div><!-- /upload-panel modal overlay -->
209
235
 
210
236
  </main>
211
237
 
@@ -218,23 +244,37 @@
218
244
  <div id="modal-image" class="mb-4 p-4 bg-gray-50 dark:bg-gray-800 rounded-xl"></div>
219
245
  <p class="text-base font-semibold text-gray-900 dark:text-white mb-4" id="modal-illustration-name"></p>
220
246
  <div class="w-full space-y-3 mb-4">
221
- <div>
222
- <label class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1 block">Dot Code</label>
223
- <div class="flex gap-2">
224
- <textarea id="modal-dot-code" readonly rows="2"
225
- class="flex-1 px-3 py-2 text-xs font-mono bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white resize-none outline-none"></textarea>
226
- <button id="modal-copy-dot-code"
227
- class="px-3 py-1 text-xs bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-blue-50 dark:hover:bg-blue-900/30 transition">Copy</button>
247
+ <!-- Illustration fields (shown for illustrations) -->
248
+ <div id="modal-illus-fields">
249
+ <div class="mb-3">
250
+ <label class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1 block">Dot Code</label>
251
+ <div class="flex gap-2">
252
+ <textarea id="modal-dot-code" readonly rows="2"
253
+ class="flex-1 px-3 py-2 text-xs font-mono bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white resize-none outline-none"></textarea>
254
+ <button id="modal-copy-dot-code"
255
+ class="px-3 py-1 text-xs bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-blue-50 dark:hover:bg-blue-900/30 transition">Copy</button>
256
+ </div>
257
+ </div>
258
+ <div>
259
+ <label class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1 block">HTML Code</label>
260
+ <div class="flex gap-2">
261
+ <textarea id="modal-code" readonly rows="2"
262
+ class="flex-1 px-3 py-2 text-xs font-mono bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white resize-none outline-none"></textarea>
263
+ <button id="modal-copy-code"
264
+ class="px-3 py-1 text-xs bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-blue-50 dark:hover:bg-blue-900/30 transition">Copy</button>
265
+ </div>
228
266
  </div>
229
267
  </div>
230
- <div>
231
- <label class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1 block">HTML Code</label>
268
+ <!-- Integration field — single usage snippet (no React component equivalent) -->
269
+ <div id="modal-integ-fields" class="hidden">
270
+ <label class="text-xs font-medium text-gray-500 dark:text-gray-400 mb-1 block">Usage</label>
232
271
  <div class="flex gap-2">
233
- <textarea id="modal-code" readonly rows="2"
272
+ <textarea id="modal-integ-code" readonly rows="2"
234
273
  class="flex-1 px-3 py-2 text-xs font-mono bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg text-gray-900 dark:text-white resize-none outline-none"></textarea>
235
- <button id="modal-copy-code"
274
+ <button id="modal-copy-integ-code"
236
275
  class="px-3 py-1 text-xs bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-blue-50 dark:hover:bg-blue-900/30 transition">Copy</button>
237
276
  </div>
277
+ <p class="text-[10px] text-gray-400 dark:text-gray-500 mt-1.5">Requires <code class="font-mono">index.css</code> — no React component equivalent.</p>
238
278
  </div>
239
279
  </div>
240
280
  <button id="modal-close-bottom"
package/demo/script.js CHANGED
@@ -118,21 +118,43 @@ document.addEventListener('DOMContentLoaded', () => {
118
118
  const floatingTabs = document.querySelectorAll('.floating-tab');
119
119
 
120
120
  // ── Upload New button (in header) ────────────────────────────────────────
121
- let uploadPanelOpen = false;
122
- document.getElementById('upload-new-btn')?.addEventListener('click', () => {
123
- uploadPanelOpen = !uploadPanelOpen;
121
+ // ── Upload New: type picker → form ──────────────────────────────────────
122
+ function showUploadStep(step) {
123
+ // step: 'picker' | 'illustration' | 'integration'
124
+ document.getElementById('upload-type-picker').classList.toggle('hidden', step !== 'picker');
125
+ document.getElementById('upload-illus-panel').classList.toggle('hidden', step !== 'illustration');
126
+ document.getElementById('upload-integ-panel').classList.toggle('hidden', step !== 'integration');
127
+ }
128
+
129
+ function openUploadModal() {
124
130
  const panel = document.getElementById('upload-panel');
125
- panel.classList.toggle('hidden', !uploadPanelOpen);
126
- if (uploadPanelOpen) {
127
- panel.scrollIntoView({ behavior: 'smooth', block: 'start' });
128
- updateUploadAuthUI();
129
- }
130
- const btn = document.getElementById('upload-new-btn');
131
- btn.classList.toggle('bg-blue-700', uploadPanelOpen);
132
- btn.classList.toggle('ring-2', uploadPanelOpen);
133
- btn.classList.toggle('ring-blue-400', uploadPanelOpen);
131
+ panel.classList.remove('hidden');
132
+ showUploadStep('picker');
133
+ updateUploadAuthUI();
134
+ document.getElementById('upload-new-btn').classList.add('ring-2','ring-blue-400','bg-blue-700');
135
+ }
136
+ function closeUploadModal() {
137
+ document.getElementById('upload-panel').classList.add('hidden');
138
+ document.getElementById('upload-new-btn').classList.remove('ring-2','ring-blue-400','bg-blue-700');
139
+ }
140
+
141
+ document.getElementById('upload-new-btn')?.addEventListener('click', openUploadModal);
142
+
143
+ // Backdrop click does NOT close — use X button or Escape
144
+
145
+ // Close on X button
146
+ document.getElementById('upload-modal-close')?.addEventListener('click', closeUploadModal);
147
+
148
+ // Close on Escape
149
+ document.addEventListener('keydown', e => {
150
+ if (e.key === 'Escape' && !document.getElementById('upload-panel').classList.contains('hidden')) closeUploadModal();
134
151
  });
135
152
 
153
+ document.getElementById('pick-illustration')?.addEventListener('click', () => { showUploadStep('illustration'); updateUploadAuthUI(); });
154
+ document.getElementById('pick-integration')?.addEventListener('click', () => { showUploadStep('integration'); updateUploadAuthUI(); });
155
+ document.getElementById('back-from-illus')?.addEventListener('click', () => showUploadStep('picker'));
156
+ document.getElementById('back-from-integ')?.addEventListener('click', () => showUploadStep('picker'));
157
+
136
158
  // ── Section switcher (Illustrations | Integrations) — pill style ──────────
137
159
  function updateSectionUI(section) {
138
160
  document.querySelectorAll('.section-btn, .floating-section-btn').forEach(btn => {
@@ -162,15 +184,19 @@ document.addEventListener('DOMContentLoaded', () => {
162
184
 
163
185
  if (section === 'integrations') {
164
186
  grid.classList.remove('hidden');
165
- alphaStrip.classList.add('hidden');
166
187
  illusSubTabs.classList.add('hidden');
167
188
  if (floatingTabs) floatingTabs.classList.add('hidden');
189
+ // Alphabet strip — show as flex for integrations (110 items benefit from A–Z jump)
190
+ alphaStrip.style.display = 'flex';
191
+ renderAlphabetStrip();
168
192
  renderIllustrations();
169
193
  } else {
194
+ // Illustrations — search is sufficient for 72 items; hide alphabet strip
170
195
  grid.classList.remove('hidden');
171
196
  illusSubTabs.classList.remove('hidden');
172
197
  if (floatingTabs) floatingTabs.classList.remove('hidden');
173
- renderAlphabetStrip();
198
+ alphaStrip.style.display = 'none';
199
+ alphabetFilter = '';
174
200
  renderIllustrations();
175
201
  }
176
202
  }
@@ -351,43 +377,58 @@ document.addEventListener('DOMContentLoaded', () => {
351
377
  if (!descriptionsLoaded) return;
352
378
 
353
379
  const themeClass = root.classList.contains('dark') ? 'dark' : 'light';
354
- const isInteg = type === 'integration' || integrationsList.includes(item) && !illustrations.includes(item);
380
+ const isInteg = type === 'integration' || (integrationsList.includes(item) && !illustrations.includes(item));
381
+
382
+ // Toggle field visibility
383
+ const illusFields = document.getElementById('modal-illus-fields');
384
+ const integFields = document.getElementById('modal-integ-fields');
385
+ if (illusFields) illusFields.classList.toggle('hidden', isInteg);
386
+ if (integFields) integFields.classList.toggle('hidden', !isInteg);
355
387
 
356
- let imgHtml, dotCodeString, codeString;
357
388
  if (isInteg) {
358
- imgHtml = `<span class="dot-integration" style="display:inline-flex;align-items:center;justify-content:center;width:200px;height:200px;"><img class="${item}" style="width:100%;height:100%;object-fit:contain;"/></span>`;
359
- dotCodeString = `<span class="dot-integration"><img class="${item}"/></span>`;
360
- codeString = dotCodeString;
389
+ // Integration modal single usage field
390
+ modalImage.innerHTML = `<img src="../integrations/${item}.svg" alt="${item}" style="width:140px;height:140px;object-fit:contain;" />`;
391
+ const usageCode = `<span class="dot-integration"><img class="${item}"/></span>`;
392
+ const integCodeEl = document.getElementById('modal-integ-code');
393
+ if (integCodeEl) integCodeEl.value = usageCode;
394
+ const copyInteg = document.getElementById('modal-copy-integ-code');
395
+ if (copyInteg) {
396
+ copyInteg.onclick = () => {
397
+ navigator.clipboard.writeText(usageCode).then(() => {
398
+ copyInteg.textContent = 'Copied!';
399
+ showToast('Copied: ' + usageCode);
400
+ setTimeout(() => { copyInteg.textContent = 'Copy'; }, 2000);
401
+ });
402
+ };
403
+ }
361
404
  } else {
405
+ // Illustration modal — Dot Code + HTML Code
362
406
  const cat = globalList.includes(item) ? 'global' : 'dashboards';
363
407
  const svgPath = `illustrations/${themeClass}/${cat}/${item}.svg`;
364
- imgHtml = `<span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}" style="width:286px;height:286px;object-fit:contain;"/></span>`;
365
- dotCodeString = `<DotIllustration illustrationId="${item}" />`;
366
- codeString = `<span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}"/></span>`;
408
+ modalImage.innerHTML = `<span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}" style="width:220px;height:220px;object-fit:contain;"/></span>`;
409
+
410
+ const dotCode = `<DotIllustration illustrationId="${item}" />`;
411
+ const htmlCode = `<span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}"/></span>`;
412
+ const modalDotCode = document.getElementById('modal-dot-code');
413
+ if (modalDotCode) modalDotCode.value = dotCode;
414
+ modalCode.value = htmlCode;
415
+
416
+ const modalCopyDotCode = document.getElementById('modal-copy-dot-code');
417
+ if (modalCopyDotCode) {
418
+ modalCopyDotCode.onclick = () => {
419
+ navigator.clipboard.writeText(dotCode).then(() => {
420
+ modalCopyDotCode.textContent = 'Copied!';
421
+ showToast('Copied: ' + dotCode);
422
+ setTimeout(() => { modalCopyDotCode.textContent = 'Copy'; }, 2000);
423
+ });
424
+ };
425
+ }
367
426
  }
368
427
 
369
- modalImage.innerHTML = imgHtml;
370
- const modalIllustrationName = document.getElementById('modal-illustration-name');
371
- if (modalIllustrationName) modalIllustrationName.textContent = item;
372
- const modalDotCode = document.getElementById('modal-dot-code');
373
- if (modalDotCode) modalDotCode.value = dotCodeString;
374
- modalCode.value = codeString;
375
-
428
+ const nameEl = document.getElementById('modal-illustration-name');
429
+ if (nameEl) nameEl.textContent = item;
376
430
  modal.classList.add('active');
377
431
  modal.classList.remove('hidden');
378
-
379
- const modalCopyDotCode = document.getElementById('modal-copy-dot-code');
380
- if (modalCopyDotCode) {
381
- modalCopyDotCode.onclick = () => {
382
- if (modalDotCode) {
383
- navigator.clipboard.writeText(modalDotCode.value).then(() => {
384
- modalCopyDotCode.textContent = 'Copied!';
385
- showToast('Copied Dot Code: ' + modalDotCode.value);
386
- setTimeout(() => { modalCopyDotCode.textContent = 'Copy Dot Code'; }, 2000);
387
- });
388
- }
389
- };
390
- }
391
432
  }
392
433
  function closeModal() {
393
434
  modal.classList.remove('active');
@@ -412,14 +453,19 @@ document.addEventListener('DOMContentLoaded', () => {
412
453
  const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
413
454
 
414
455
  strip.innerHTML = `
415
- <button class="alpha-btn px-2 py-1 text-xs rounded-lg font-mono font-medium ${alphabetFilter === '' ? 'bg-blue-600 text-white shadow-sm' : 'bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-400 border border-gray-200 dark:border-gray-700 hover:border-blue-400 hover:text-blue-600 dark:hover:text-blue-400'} transition" data-letter="">All</button>
456
+ <button class="alpha-btn text-xs font-medium px-1.5 py-0.5 rounded-md transition-all ${
457
+ alphabetFilter === ''
458
+ ? 'text-blue-600 dark:text-blue-400 font-semibold'
459
+ : 'text-gray-400 dark:text-gray-500 hover:text-gray-700 dark:hover:text-gray-300'
460
+ }" data-letter="">All</button>
461
+ <span class="text-gray-200 dark:text-gray-700 text-xs select-none">|</span>
416
462
  ${letters.map(l => `
417
- <button class="alpha-btn px-2 py-1 text-xs rounded-lg font-mono font-medium ${
463
+ <button class="alpha-btn text-xs font-medium px-1.5 py-0.5 rounded-md transition-all ${
418
464
  available.has(l)
419
465
  ? alphabetFilter === l
420
- ? 'bg-blue-600 text-white shadow-sm'
421
- : 'bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-400 border border-gray-200 dark:border-gray-700 hover:border-blue-400 hover:text-blue-600 dark:hover:text-blue-400 transition'
422
- : 'opacity-25 cursor-default text-gray-400 dark:text-gray-600'
466
+ ? 'text-blue-600 dark:text-blue-400 font-semibold bg-blue-50 dark:bg-blue-900/30'
467
+ : 'text-gray-500 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 hover:bg-gray-100 dark:hover:bg-gray-800'
468
+ : 'text-gray-200 dark:text-gray-700 cursor-default'
423
469
  }" data-letter="${l}" ${available.has(l) ? '' : 'disabled'}>${l}</button>
424
470
  `).join('')}
425
471
  `;
@@ -475,56 +521,53 @@ document.addEventListener('DOMContentLoaded', () => {
475
521
 
476
522
  if (isInteg) {
477
523
  // Integration card — use direct <img src> so the image always loads
524
+ // ── Integration card ─────────────────────────────────────────────
478
525
  const htmlCode = `<span class="dot-integration"><img class="${item}"/></span>`;
479
526
  const div = document.createElement('div');
480
- div.setAttribute('class', 'copy-container relative group flex flex-col items-center justify-between bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl shadow-lg p-2 md:p-3 transition-transform duration-200 hover:scale-105 hover:shadow-2xl h-[302px] w-full');
481
- div.dataset.itemId = item;
527
+ div.className = 'copy-container group relative bg-white dark:bg-gray-900 rounded-2xl overflow-hidden cursor-pointer shadow-sm transition-all duration-200 hover:shadow-md hover:ring-2 hover:ring-blue-400/30 dark:hover:ring-blue-500/30';
528
+ div.dataset.itemId = item;
482
529
  div.dataset.itemType = 'integration';
483
530
  div.innerHTML = `
484
- <button class="absolute top-2 right-2 z-10 p-1 rounded-full bg-white/80 dark:bg-gray-800/80 hover:bg-yellow-100 dark:hover:bg-yellow-300 transition" title="Toggle favourite" onclick="event.stopPropagation();window.toggleFavourite('${item}')">
485
- <svg class="h-5 w-5" fill="${isFav ? 'gold' : 'none'}" viewBox="0 0 24 24" stroke="gold"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l2.036 6.29a1 1 0 00.95.69h6.631c.969 0 1.371 1.24.588 1.81l-5.37 3.905a1 1 0 00-.364 1.118l2.036 6.29c.3.921-.755 1.688-1.54 1.118l-5.37-3.905a1 1 0 00-1.176 0l-5.37 3.905c-.784.57-1.838-.197-1.54-1.118l2.036-6.29a1 1 0 00-.364-1.118L2.342 11.717c-.783-.57-.38-1.81.588-1.81h6.631a1 1 0 00.95-.69l2.036-6.29z"/></svg>
531
+ <button class="fav-btn absolute top-2.5 right-2.5 z-20 opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded-lg bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm shadow-sm" onclick="event.stopPropagation();window.toggleFavourite('${item}')">
532
+ <svg class="w-3.5 h-3.5" fill="${isFav ? '#FBBF24' : 'none'}" viewBox="0 0 24 24" stroke="${isFav ? '#FBBF24' : '#9CA3AF'}" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l2.036 6.29a1 1 0 00.95.69h6.631c.969 0 1.371 1.24.588 1.81l-5.37 3.905a1 1 0 00-.364 1.118l2.036 6.29c.3.921-.755 1.688-1.54 1.118l-5.37-3.905a1 1 0 00-1.176 0l-5.37 3.905c-.784.57-1.838-.197-1.54-1.118l2.036-6.29a1 1 0 00-.364-1.118L2.342 11.717c-.783-.57-.38-1.81.588-1.81h6.631a1 1 0 00.95-.69l2.036-6.29z"/></svg>
486
533
  </button>
487
- <div class="flex-1 flex flex-col justify-center items-center">
488
- <img src="../integrations/${item}.svg" alt="${item}" class="w-28 h-28 object-contain" loading="lazy" />
489
- <span class="iconID block text-center text-base font-medium text-gray-800 dark:text-gray-200 my-2">${item}</span>
534
+ <div class="flex items-center justify-center h-36 px-4">
535
+ <img src="../integrations/${item}.svg" alt="${item}" class="w-[80px] h-[80px] object-contain" loading="lazy" />
536
+ </div>
537
+ <div class="px-3 py-3">
538
+ <p class="iconID text-[11px] text-center text-gray-500 dark:text-gray-400 font-medium leading-tight truncate">${item}</p>
490
539
  </div>
491
- <div class="button-group flex flex-row items-center justify-center gap-2 mt-2">
492
- <button class="button flex items-center justify-center min-w-[80px] px-1.5 py-0.5 text-[11px] text-gray-400 border border-gray-300 dark:border-gray-700 rounded bg-white dark:bg-gray-800 font-normal hover:bg-blue-100 dark:hover:bg-blue-900 transition relative text-center" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)" onclick="copyText(this)">
493
- Copy Dot Code<span class="tooltiptext left-1/2 -translate-x-1/2 bottom-10 shadow-md">Copy Dot Code</span>
494
- </button>
495
- <button class="button flex items-center justify-center min-w-[80px] px-1.5 py-0.5 text-[11px] text-gray-400 border border-gray-300 dark:border-gray-700 rounded bg-white dark:bg-gray-800 font-normal hover:bg-blue-100 dark:hover:bg-blue-900 transition relative text-center" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)" onclick="copyCode(this)">
496
- Copy Code<span class="tooltiptext left-1/2 -translate-x-1/2 bottom-10 shadow-md">Copy Code</span>
497
- </button>
540
+ <div class="action-bar absolute bottom-0 inset-x-0 bg-white/97 dark:bg-gray-900/97 backdrop-blur-sm border-t border-gray-100 dark:border-gray-800 p-2 flex gap-1.5 translate-y-full group-hover:translate-y-0 transition-transform duration-150 ease-out">
541
+ <button class="button flex-1 py-1.5 text-[10px] font-semibold text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/30 rounded-lg hover:bg-blue-100 dark:hover:bg-blue-900/60 transition" onclick="event.stopPropagation();copyText(this)">Dot Code</button>
542
+ <button class="button flex-1 py-1.5 text-[10px] font-semibold text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 transition" onclick="event.stopPropagation();copyCode(this)">HTML</button>
498
543
  </div>
499
- <pre class="codeBlock"><code class="codeBlock">${htmlCode}</code></pre>
544
+ <pre class="codeBlock hidden"><code class="codeBlock">${htmlCode}</code></pre>
500
545
  `;
501
546
  list.appendChild(div);
502
547
  } else {
503
- // Illustration card (light/dark, dot-illustration wrapper)
548
+ // ── Illustration card ─────────────────────────────────────────────
504
549
  let categoryFolder = globalList.includes(item) ? 'global' : 'dashboards';
505
- const svgPath = `illustrations/${themeClass}/${categoryFolder}/${item}.svg`;
550
+ const svgPath = `illustrations/${themeClass}/${categoryFolder}/${item}.svg`;
506
551
  const codeString = `<span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}"/></span>`;
507
552
  const div = document.createElement('div');
508
- div.setAttribute('class', 'copy-container relative group flex flex-col items-center justify-between bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-xl shadow-lg p-2 md:p-3 transition-transform duration-200 hover:scale-105 hover:shadow-2xl h-[302px] w-full');
509
- div.dataset.itemId = item;
553
+ div.className = 'copy-container group relative bg-white dark:bg-gray-900 rounded-2xl overflow-hidden cursor-pointer shadow-sm transition-all duration-200 hover:shadow-md hover:ring-2 hover:ring-blue-400/30 dark:hover:ring-blue-500/30';
554
+ div.dataset.itemId = item;
510
555
  div.dataset.itemType = 'illustration';
511
556
  div.innerHTML = `
512
- <button class="absolute top-2 right-2 z-10 p-1 rounded-full bg-white/80 dark:bg-gray-800/80 hover:bg-yellow-100 dark:hover:bg-yellow-300 transition" title="Toggle favourite" onclick="event.stopPropagation();window.toggleFavourite('${item}')">
513
- <svg class="h-5 w-5" fill="${isFav ? 'gold' : 'none'}" viewBox="0 0 24 24" stroke="gold"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l2.036 6.29a1 1 0 00.95.69h6.631c.969 0 1.371 1.24.588 1.81l-5.37 3.905a1 1 0 00-.364 1.118l2.036 6.29c.3.921-.755 1.688-1.54 1.118l-5.37-3.905a1 1 0 00-1.176 0l-5.37 3.905c-.784.57-1.838-.197-1.54-1.118l2.036-6.29a1 1 0 00-.364-1.118L2.342 11.717c-.783-.57-.38-1.81.588-1.81h6.631a1 1 0 00.95-.69l2.036-6.29z"/></svg>
557
+ <button class="fav-btn absolute top-2.5 right-2.5 z-20 opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded-lg bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm shadow-sm" onclick="event.stopPropagation();window.toggleFavourite('${item}')">
558
+ <svg class="w-3.5 h-3.5" fill="${isFav ? '#FBBF24' : 'none'}" viewBox="0 0 24 24" stroke="${isFav ? '#FBBF24' : '#9CA3AF'}" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M11.049 2.927c.3-.921 1.603-.921 1.902 0l2.036 6.29a1 1 0 00.95.69h6.631c.969 0 1.371 1.24.588 1.81l-5.37 3.905a1 1 0 00-.364 1.118l2.036 6.29c.3.921-.755 1.688-1.54 1.118l-5.37-3.905a1 1 0 00-1.176 0l-5.37 3.905c-.784.57-1.838-.197-1.54-1.118l2.036-6.29a1 1 0 00-.364-1.118L2.342 11.717c-.783-.57-.38-1.81.588-1.81h6.631a1 1 0 00.95-.69l2.036-6.29z"/></svg>
514
559
  </button>
515
- <div class="flex-1 flex flex-col justify-center items-center">
516
- <span class="dot-illustration"><img src="${svgPath}" class="${item} ${themeClass}"/></span>
517
- <span class="iconID block text-center text-base font-medium text-gray-800 dark:text-gray-200 my-2">${item}</span>
560
+ <div class="flex items-center justify-center h-36 px-4 dot-illustration">
561
+ <img src="${svgPath}" class="${item} ${themeClass}" style="width:120px;height:120px;object-fit:contain;display:block;" />
562
+ </div>
563
+ <div class="px-3 py-3">
564
+ <p class="iconID text-[11px] text-center text-gray-500 dark:text-gray-400 font-medium leading-tight break-words">${item}</p>
518
565
  </div>
519
- <div class="button-group flex flex-row items-center justify-center gap-2 mt-2">
520
- <button id="CopyID" class="button flex items-center justify-center min-w-[80px] px-1.5 py-0.5 text-[11px] text-gray-400 border border-gray-300 dark:border-gray-700 rounded bg-white dark:bg-gray-800 font-normal hover:bg-blue-100 dark:hover:bg-blue-900 transition relative text-center" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)" onclick="copyText(this)">
521
- Copy Dot Code<span class="tooltiptext left-1/2 -translate-x-1/2 bottom-10 shadow-md">Copy Dot Code</span>
522
- </button>
523
- <button class="button flex items-center justify-center min-w-[80px] px-1.5 py-0.5 text-[11px] text-gray-400 border border-gray-300 dark:border-gray-700 rounded bg-white dark:bg-gray-800 font-normal hover:bg-blue-100 dark:hover:bg-blue-900 transition relative text-center" onmouseover="showTooltip(this)" onmouseout="hideTooltip(this)" onclick="copyCode(this)">
524
- Copy Code<span class="tooltiptext left-1/2 -translate-x-1/2 bottom-10 shadow-md">Copy Code</span>
525
- </button>
566
+ <div class="action-bar absolute bottom-0 inset-x-0 bg-white/97 dark:bg-gray-900/97 backdrop-blur-sm border-t border-gray-100 dark:border-gray-800 p-2 flex gap-1.5 translate-y-full group-hover:translate-y-0 transition-transform duration-150 ease-out">
567
+ <button class="button flex-1 py-1.5 text-[10px] font-semibold text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/30 rounded-lg hover:bg-blue-100 dark:hover:bg-blue-900/60 transition" onclick="event.stopPropagation();copyText(this)">Dot Code</button>
568
+ <button class="button flex-1 py-1.5 text-[10px] font-semibold text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-700 transition" onclick="event.stopPropagation();copyCode(this)">HTML</button>
526
569
  </div>
527
- <pre class="codeBlock"><code class="codeBlock">${codeString}</code></pre>
570
+ <pre class="codeBlock hidden"><code class="codeBlock">${codeString}</code></pre>
528
571
  `;
529
572
  list.appendChild(div);
530
573
  }
@@ -728,10 +771,11 @@ document.addEventListener('DOMContentLoaded', () => {
728
771
  document.getElementById('upload-illus-btn')?.addEventListener('click', handleIllusUpload);
729
772
  document.getElementById('upload-integ-btn')?.addEventListener('click', handleIntegUpload);
730
773
 
731
- // Initial render
774
+ // Initial render — start on illustrations, alphabet hidden
775
+ const strip = document.getElementById('alphabet-strip');
776
+ if (strip) strip.style.display = 'none';
732
777
  updateSectionUI('illustrations');
733
778
  updateTabUI('all');
734
- renderAlphabetStrip();
735
779
  renderIllustrations();
736
780
 
737
781
  // --- FLOATING BAR LOGIC ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digital-ai/dot-illustrations",
3
- "version": "2.0.37",
3
+ "version": "2.0.39",
4
4
  "description": "A central place for the design team to keep illustrations and for dev teams to find them.",
5
5
  "main": "./index.css",
6
6
  "scripts": {