@oddsmith/ui 0.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 (185) hide show
  1. package/.eleventy.cjs +14 -0
  2. package/LICENSE +28 -0
  3. package/README.md +118 -0
  4. package/custom-elements.json +1539 -0
  5. package/docs/_README/index.html +4 -0
  6. package/docs/api/index.html +2100 -0
  7. package/docs/components.bundle.js +1669 -0
  8. package/docs/components.bundle.js.map +1 -0
  9. package/docs/docs.css +162 -0
  10. package/docs/examples/index.html +56 -0
  11. package/docs/index.html +53 -0
  12. package/docs/install/index.html +45 -0
  13. package/docs/prism-okaidia.css +123 -0
  14. package/docs-src/.nojekyll +0 -0
  15. package/docs-src/_README.md +7 -0
  16. package/docs-src/_data/api.11tydata.js +8 -0
  17. package/docs-src/_includes/example.11ty.js +35 -0
  18. package/docs-src/_includes/footer.11ty.js +6 -0
  19. package/docs-src/_includes/header.11ty.js +7 -0
  20. package/docs-src/_includes/nav.11ty.js +11 -0
  21. package/docs-src/_includes/page.11ty.js +32 -0
  22. package/docs-src/_includes/relative-path.cjs +9 -0
  23. package/docs-src/api.11ty.js +85 -0
  24. package/docs-src/bundle.ts +9 -0
  25. package/docs-src/docs.css +162 -0
  26. package/docs-src/examples/index.md +15 -0
  27. package/docs-src/index.md +39 -0
  28. package/docs-src/install.md +28 -0
  29. package/docs-src/package.json +3 -0
  30. package/index.html +19 -0
  31. package/karma.conf.cjs +24 -0
  32. package/main.css +210 -0
  33. package/main.ts +124 -0
  34. package/package.json +86 -0
  35. package/previews/casino.ts +12 -0
  36. package/previews/catalog.ts +94 -0
  37. package/previews/leaderboard-v1.ts +12 -0
  38. package/previews/leaderboard-v2.ts +17 -0
  39. package/previews/sample-data.ts +101 -0
  40. package/previews/sf-leaderboard.ts +100 -0
  41. package/previews/sf-live-feed.ts +15 -0
  42. package/previews/streaks.ts +40 -0
  43. package/previews/types.ts +18 -0
  44. package/src/components/README.md +16 -0
  45. package/src/components/casino-leaderboard/casino-leaderboard.html +80 -0
  46. package/src/components/casino-leaderboard/casino-leaderboard.scss +585 -0
  47. package/src/components/casino-leaderboard/casino-leaderboard.ts +136 -0
  48. package/src/components/casino-leaderboard/data.ts +111 -0
  49. package/src/components/casino-leaderboard/index.ts +5 -0
  50. package/src/components/casino-leaderboard/todo.txt +2 -0
  51. package/src/components/casino-leaderboard/types.ts +19 -0
  52. package/src/components/leaderboard/components/leaderboard.ts +373 -0
  53. package/src/components/leaderboard/components/player-card.ts +342 -0
  54. package/src/components/leaderboard/components/ui.ts +452 -0
  55. package/src/components/leaderboard/data.ts +152 -0
  56. package/src/components/leaderboard/index.ts +2 -0
  57. package/src/components/leaderboard/main.ts +42 -0
  58. package/src/components/leaderboard/styles.ts +67 -0
  59. package/src/components/leaderboard/types.ts +28 -0
  60. package/src/components/leaderboard-v2/components/sf-leaderboard-player.ts +451 -0
  61. package/src/components/leaderboard-v2/components/sf-leaderboard-ui.ts +512 -0
  62. package/src/components/leaderboard-v2/components/sf-leaderboard.ts +205 -0
  63. package/src/components/leaderboard-v2/constants.ts +16 -0
  64. package/src/components/leaderboard-v2/demo/sample-data.ts +152 -0
  65. package/src/components/leaderboard-v2/events.ts +13 -0
  66. package/src/components/leaderboard-v2/icons.ts +22 -0
  67. package/src/components/leaderboard-v2/index.ts +23 -0
  68. package/src/components/leaderboard-v2/sf-leaderboard.html +1 -0
  69. package/src/components/leaderboard-v2/sf-leaderboard.scss +382 -0
  70. package/src/components/leaderboard-v2/tokens.ts +35 -0
  71. package/src/components/leaderboard-v2/types.ts +30 -0
  72. package/src/components/sf-leaderboard/index.ts +77 -0
  73. package/src/components/sf-leaderboard/sections/footer-section/footer-section.host.ts +3 -0
  74. package/src/components/sf-leaderboard/sections/footer-section/footer-section.html +3 -0
  75. package/src/components/sf-leaderboard/sections/footer-section/footer-section.scss +18 -0
  76. package/src/components/sf-leaderboard/sections/footer-section/footer-section.ts +22 -0
  77. package/src/components/sf-leaderboard/sections/header-section/header-section.host.ts +14 -0
  78. package/src/components/sf-leaderboard/sections/header-section/header-section.html +27 -0
  79. package/src/components/sf-leaderboard/sections/header-section/header-section.scss +189 -0
  80. package/src/components/sf-leaderboard/sections/header-section/header-section.ts +70 -0
  81. package/src/components/sf-leaderboard/sections/ranking-section/ranking-section.host.ts +22 -0
  82. package/src/components/sf-leaderboard/sections/ranking-section/ranking-section.html +38 -0
  83. package/src/components/sf-leaderboard/sections/ranking-section/ranking-section.scss +99 -0
  84. package/src/components/sf-leaderboard/sections/ranking-section/ranking-section.ts +121 -0
  85. package/src/components/sf-leaderboard/sections/stats-section/stats-section.host.ts +8 -0
  86. package/src/components/sf-leaderboard/sections/stats-section/stats-section.html +6 -0
  87. package/src/components/sf-leaderboard/sections/stats-section/stats-section.scss +44 -0
  88. package/src/components/sf-leaderboard/sections/stats-section/stats-section.ts +41 -0
  89. package/src/components/sf-leaderboard/sections/table-section/table-section.host.ts +17 -0
  90. package/src/components/sf-leaderboard/sections/table-section/table-section.html +19 -0
  91. package/src/components/sf-leaderboard/sections/table-section/table-section.scss +37 -0
  92. package/src/components/sf-leaderboard/sections/table-section/table-section.ts +108 -0
  93. package/src/components/sf-leaderboard/services/index.ts +22 -0
  94. package/src/components/sf-leaderboard/services/sf-leaderboard-data.service.ts +54 -0
  95. package/src/components/sf-leaderboard/services/sf-leaderboard.state.ts +160 -0
  96. package/src/components/sf-leaderboard/shared/components/activity-feed/activity-feed.host.ts +7 -0
  97. package/src/components/sf-leaderboard/shared/components/activity-feed/activity-feed.html +10 -0
  98. package/src/components/sf-leaderboard/shared/components/activity-feed/activity-feed.scss +180 -0
  99. package/src/components/sf-leaderboard/shared/components/activity-feed/activity-feed.ts +88 -0
  100. package/src/components/sf-leaderboard/shared/components/filters/filters.host.ts +12 -0
  101. package/src/components/sf-leaderboard/shared/components/filters/filters.html +22 -0
  102. package/src/components/sf-leaderboard/shared/components/filters/filters.scss +122 -0
  103. package/src/components/sf-leaderboard/shared/components/filters/filters.ts +75 -0
  104. package/src/components/sf-leaderboard/shared/components/player-avatar/player-avatar.host.ts +9 -0
  105. package/src/components/sf-leaderboard/shared/components/player-avatar/player-avatar.html +5 -0
  106. package/src/components/sf-leaderboard/shared/components/player-avatar/player-avatar.scss +81 -0
  107. package/src/components/sf-leaderboard/shared/components/player-avatar/player-avatar.ts +34 -0
  108. package/src/components/sf-leaderboard/shared/components/podium/map-players.ts +24 -0
  109. package/src/components/sf-leaderboard/shared/components/podium/podium.host.ts +10 -0
  110. package/src/components/sf-leaderboard/shared/components/podium/podium.html +53 -0
  111. package/src/components/sf-leaderboard/shared/components/podium/podium.scss +580 -0
  112. package/src/components/sf-leaderboard/shared/components/podium/podium.ts +49 -0
  113. package/src/components/sf-leaderboard/shared/components/podium/podium.types.ts +9 -0
  114. package/src/components/sf-leaderboard/shared/components/rank-badge/rank-badge.host.ts +11 -0
  115. package/src/components/sf-leaderboard/shared/components/rank-badge/rank-badge.html +9 -0
  116. package/src/components/sf-leaderboard/shared/components/rank-badge/rank-badge.scss +98 -0
  117. package/src/components/sf-leaderboard/shared/components/rank-badge/rank-badge.ts +63 -0
  118. package/src/components/sf-leaderboard/shared/components/stat-card/stat-card.host.ts +9 -0
  119. package/src/components/sf-leaderboard/shared/components/stat-card/stat-card.html +15 -0
  120. package/src/components/sf-leaderboard/shared/components/stat-card/stat-card.scss +210 -0
  121. package/src/components/sf-leaderboard/shared/components/stat-card/stat-card.ts +36 -0
  122. package/src/components/sf-leaderboard/shared/components/table/table.host.ts +5 -0
  123. package/src/components/sf-leaderboard/shared/components/table/table.html +11 -0
  124. package/src/components/sf-leaderboard/shared/components/table/table.scss +212 -0
  125. package/src/components/sf-leaderboard/shared/components/table/table.ts +111 -0
  126. package/src/components/sf-leaderboard/shared/constants/defaults.ts +7 -0
  127. package/src/components/sf-leaderboard/shared/constants/filters.ts +16 -0
  128. package/src/components/sf-leaderboard/shared/constants/index.ts +5 -0
  129. package/src/components/sf-leaderboard/shared/constants/player-stats.ts +3 -0
  130. package/src/components/sf-leaderboard/shared/constants/stats-overview.ts +38 -0
  131. package/src/components/sf-leaderboard/shared/constants/tags.ts +16 -0
  132. package/src/components/sf-leaderboard/shared/styles/_section.scss +35 -0
  133. package/src/components/sf-leaderboard/shared/types/data.ts +29 -0
  134. package/src/components/sf-leaderboard/shared/types/events.ts +30 -0
  135. package/src/components/sf-leaderboard/shared/types/player-stats.ts +3 -0
  136. package/src/components/sf-leaderboard/shared/types/sections.ts +100 -0
  137. package/src/components/sf-leaderboard/shared/utils/utils.ts +17 -0
  138. package/src/components/sf-leaderboard/theme/THEMING.md +54 -0
  139. package/src/components/sf-leaderboard/theme/context.ts +16 -0
  140. package/src/components/sf-leaderboard/theme/default-theme.ts +4 -0
  141. package/src/components/sf-leaderboard/theme/hex-to-rgb.ts +25 -0
  142. package/src/components/sf-leaderboard/theme/index.ts +18 -0
  143. package/src/components/sf-leaderboard/theme/inject-theme.ts +39 -0
  144. package/src/components/sf-leaderboard/theme/load-theme.ts +26 -0
  145. package/src/components/sf-leaderboard/theme/merge-theme.ts +59 -0
  146. package/src/components/sf-leaderboard/theme/scss/_colors.scss +101 -0
  147. package/src/components/sf-leaderboard/theme/scss/shared.scss +123 -0
  148. package/src/components/sf-leaderboard/theme/styles.ts +6 -0
  149. package/src/components/sf-leaderboard/theme/theme-to-css-vars.ts +99 -0
  150. package/src/components/sf-leaderboard/theme/themes/fallback.json +62 -0
  151. package/src/components/sf-leaderboard/theme/themes/red.json +62 -0
  152. package/src/components/sf-leaderboard/theme/types.ts +71 -0
  153. package/src/components/sf-live-feed/components/avatar/avatar.host.ts +5 -0
  154. package/src/components/sf-live-feed/components/avatar/avatar.html +3 -0
  155. package/src/components/sf-live-feed/components/avatar/avatar.scss +24 -0
  156. package/src/components/sf-live-feed/components/avatar/avatar.ts +27 -0
  157. package/src/components/sf-live-feed/components/sf-live-feed/sf-live-feed.host.ts +8 -0
  158. package/src/components/sf-live-feed/components/sf-live-feed/sf-live-feed.html +10 -0
  159. package/src/components/sf-live-feed/components/sf-live-feed/sf-live-feed.scss +177 -0
  160. package/src/components/sf-live-feed/components/sf-live-feed/sf-live-feed.ts +65 -0
  161. package/src/components/sf-live-feed/constants.ts +4 -0
  162. package/src/components/sf-live-feed/demo/sample-data.ts +34 -0
  163. package/src/components/sf-live-feed/index.ts +19 -0
  164. package/src/components/sf-live-feed/styles/theme.scss +19 -0
  165. package/src/components/sf-live-feed/styles/theme.ts +5 -0
  166. package/src/components/sf-live-feed/types.ts +19 -0
  167. package/src/components/sf-live-feed/utils.ts +17 -0
  168. package/src/components/streaks/constants.ts +17 -0
  169. package/src/components/streaks/demo/sample-steps.ts +10 -0
  170. package/src/components/streaks/events.ts +8 -0
  171. package/src/components/streaks/index.ts +16 -0
  172. package/src/components/streaks/sf-streaks.html +26 -0
  173. package/src/components/streaks/sf-streaks.scss +351 -0
  174. package/src/components/streaks/sf-streaks.ts +235 -0
  175. package/src/components/streaks/types.ts +7 -0
  176. package/src/lib/lit/component.ts +10 -0
  177. package/src/lib/lit/safe-custom-element.ts +12 -0
  178. package/src/lib/lit/scss.ts +6 -0
  179. package/src/vite-env.d.ts +18 -0
  180. package/styles/global.css +125 -0
  181. package/todo.txt +54 -0
  182. package/tsconfig.json +31 -0
  183. package/vite.config.ts +56 -0
  184. package/vite.docs.config.ts +33 -0
  185. package/vite.lit-html-plugin.ts +43 -0
@@ -0,0 +1,585 @@
1
+ :host {
2
+ display: block;
3
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI',
4
+ sans-serif;
5
+ }
6
+
7
+ .leaderboard {
8
+ background: linear-gradient(145deg, #12151a 0%, #0d1015 100%);
9
+ border: 1px solid rgba(212, 175, 55, 0.2);
10
+ border-radius: 24px;
11
+ padding: 2rem;
12
+ width: 100%;
13
+ max-width: 900px;
14
+ box-shadow: 0 0 60px rgba(212, 175, 55, 0.1),
15
+ 0 25px 50px -12px rgba(0, 0, 0, 0.8),
16
+ inset 0 1px 0 rgba(255, 255, 255, 0.05);
17
+ overflow: hidden;
18
+ position: relative;
19
+ }
20
+
21
+ .leaderboard::before {
22
+ content: '';
23
+ position: absolute;
24
+ top: 0;
25
+ left: 0;
26
+ right: 0;
27
+ height: 3px;
28
+ background: linear-gradient(
29
+ 90deg,
30
+ transparent,
31
+ #d4af37 20%,
32
+ #ffd700 50%,
33
+ #d4af37 80%,
34
+ transparent
35
+ );
36
+ }
37
+
38
+ .header {
39
+ display: flex;
40
+ align-items: center;
41
+ justify-content: space-between;
42
+ margin-bottom: 2rem;
43
+ padding-bottom: 1.5rem;
44
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
45
+ }
46
+
47
+ .header-left {
48
+ display: flex;
49
+ align-items: center;
50
+ gap: 1rem;
51
+ }
52
+
53
+ .trophy-icon {
54
+ width: 48px;
55
+ height: 48px;
56
+ background: linear-gradient(145deg, #ffd700, #d4af37);
57
+ border-radius: 12px;
58
+ display: flex;
59
+ align-items: center;
60
+ justify-content: center;
61
+ font-size: 1.5rem;
62
+ box-shadow: 0 4px 15px rgba(212, 175, 55, 0.4);
63
+ }
64
+
65
+ .title-container {
66
+ display: flex;
67
+ flex-direction: column;
68
+ }
69
+
70
+ .title {
71
+ font-family: 'Orbitron', sans-serif;
72
+ font-size: 1.75rem;
73
+ font-weight: 900;
74
+ background: linear-gradient(135deg, #ffd700 0%, #d4af37 50%, #ffeeba 100%);
75
+ -webkit-background-clip: text;
76
+ -webkit-text-fill-color: transparent;
77
+ background-clip: text;
78
+ text-transform: uppercase;
79
+ letter-spacing: 2px;
80
+ }
81
+
82
+ .subtitle {
83
+ font-size: 0.75rem;
84
+ color: #6b7280;
85
+ text-transform: uppercase;
86
+ letter-spacing: 3px;
87
+ margin-top: 4px;
88
+ }
89
+
90
+ .prize-pool {
91
+ display: flex;
92
+ flex-direction: column;
93
+ align-items: flex-end;
94
+ gap: 4px;
95
+ }
96
+
97
+ .prize-label {
98
+ font-size: 0.7rem;
99
+ color: #6b7280;
100
+ text-transform: uppercase;
101
+ letter-spacing: 2px;
102
+ }
103
+
104
+ .prize-amount {
105
+ font-family: 'Orbitron', sans-serif;
106
+ font-size: 1.5rem;
107
+ font-weight: 700;
108
+ color: #10b981;
109
+ text-shadow: 0 0 20px rgba(16, 185, 129, 0.5);
110
+ }
111
+
112
+ .tabs {
113
+ display: flex;
114
+ gap: 0.5rem;
115
+ margin-bottom: 1.5rem;
116
+ background: rgba(0, 0, 0, 0.3);
117
+ padding: 6px;
118
+ border-radius: 12px;
119
+ width: fit-content;
120
+ }
121
+
122
+ .tab {
123
+ padding: 0.625rem 1.25rem;
124
+ font-size: 0.8rem;
125
+ font-weight: 600;
126
+ color: #6b7280;
127
+ background: transparent;
128
+ border: none;
129
+ border-radius: 8px;
130
+ cursor: pointer;
131
+ transition: all 0.3s ease;
132
+ text-transform: uppercase;
133
+ letter-spacing: 1px;
134
+ }
135
+
136
+ .tab:hover {
137
+ color: #9ca3af;
138
+ background: rgba(255, 255, 255, 0.05);
139
+ }
140
+
141
+ .tab.active {
142
+ background: linear-gradient(145deg, #d4af37, #b8962e);
143
+ color: #0a0a0f;
144
+ box-shadow: 0 4px 15px rgba(212, 175, 55, 0.3);
145
+ }
146
+
147
+ .table-header {
148
+ display: grid;
149
+ grid-template-columns: 60px 1fr 120px 140px 100px 80px;
150
+ padding: 0.75rem 1rem;
151
+ font-size: 0.7rem;
152
+ font-weight: 600;
153
+ color: #6b7280;
154
+ text-transform: uppercase;
155
+ letter-spacing: 1.5px;
156
+ border-bottom: 1px solid rgba(255, 255, 255, 0.05);
157
+ }
158
+
159
+ .player-list {
160
+ display: flex;
161
+ flex-direction: column;
162
+ gap: 4px;
163
+ }
164
+
165
+ .player-row {
166
+ display: grid;
167
+ grid-template-columns: 60px 1fr 120px 140px 100px 80px;
168
+ align-items: center;
169
+ padding: 1rem;
170
+ background: rgba(255, 255, 255, 0.02);
171
+ border-radius: 12px;
172
+ transition: all 0.3s ease;
173
+ cursor: pointer;
174
+ position: relative;
175
+ overflow: hidden;
176
+ }
177
+
178
+ .player-row::before {
179
+ content: '';
180
+ position: absolute;
181
+ left: 0;
182
+ top: 0;
183
+ bottom: 0;
184
+ width: 3px;
185
+ background: transparent;
186
+ transition: background 0.3s ease;
187
+ }
188
+
189
+ .player-row:hover {
190
+ background: rgba(212, 175, 55, 0.08);
191
+ transform: translateX(4px);
192
+ }
193
+
194
+ .player-row:hover::before {
195
+ background: linear-gradient(180deg, #d4af37, #ffd700);
196
+ }
197
+
198
+ .player-row.top-1 {
199
+ background: linear-gradient(
200
+ 90deg,
201
+ rgba(255, 215, 0, 0.15) 0%,
202
+ rgba(255, 215, 0, 0.02) 100%
203
+ );
204
+ border: 1px solid rgba(255, 215, 0, 0.2);
205
+ }
206
+
207
+ .player-row.top-2 {
208
+ background: linear-gradient(
209
+ 90deg,
210
+ rgba(192, 192, 192, 0.12) 0%,
211
+ rgba(192, 192, 192, 0.02) 100%
212
+ );
213
+ border: 1px solid rgba(192, 192, 192, 0.15);
214
+ }
215
+
216
+ .player-row.top-3 {
217
+ background: linear-gradient(
218
+ 90deg,
219
+ rgba(205, 127, 50, 0.12) 0%,
220
+ rgba(205, 127, 50, 0.02) 100%
221
+ );
222
+ border: 1px solid rgba(205, 127, 50, 0.15);
223
+ }
224
+
225
+ .rank {
226
+ display: flex;
227
+ align-items: center;
228
+ justify-content: center;
229
+ width: 40px;
230
+ height: 40px;
231
+ font-weight: 800;
232
+ font-size: 1rem;
233
+ border-radius: 10px;
234
+ position: relative;
235
+ }
236
+
237
+ .rank.gold {
238
+ background: linear-gradient(145deg, #ffd700, #d4af37);
239
+ color: #0a0a0f;
240
+ box-shadow: 0 4px 15px rgba(255, 215, 0, 0.4);
241
+ }
242
+
243
+ .rank.silver {
244
+ background: linear-gradient(145deg, #e8e8e8, #c0c0c0);
245
+ color: #0a0a0f;
246
+ box-shadow: 0 4px 15px rgba(192, 192, 192, 0.3);
247
+ }
248
+
249
+ .rank.bronze {
250
+ background: linear-gradient(145deg, #cd7f32, #a0522d);
251
+ color: #fff;
252
+ box-shadow: 0 4px 15px rgba(205, 127, 50, 0.3);
253
+ }
254
+
255
+ .rank.regular {
256
+ background: rgba(255, 255, 255, 0.08);
257
+ color: #9ca3af;
258
+ font-size: 0.9rem;
259
+ }
260
+
261
+ .player-info {
262
+ display: flex;
263
+ align-items: center;
264
+ gap: 1rem;
265
+ }
266
+
267
+ .avatar-container {
268
+ position: relative;
269
+ }
270
+
271
+ .avatar {
272
+ width: 44px;
273
+ height: 44px;
274
+ border-radius: 12px;
275
+ object-fit: cover;
276
+ border: 2px solid rgba(255, 255, 255, 0.1);
277
+ }
278
+
279
+ .online-indicator {
280
+ position: absolute;
281
+ bottom: -2px;
282
+ right: -2px;
283
+ width: 12px;
284
+ height: 12px;
285
+ background: #10b981;
286
+ border-radius: 50%;
287
+ border: 2px solid #12151a;
288
+ box-shadow: 0 0 8px rgba(16, 185, 129, 0.6);
289
+ }
290
+
291
+ .online-indicator.offline {
292
+ background: #6b7280;
293
+ box-shadow: none;
294
+ }
295
+
296
+ .player-details {
297
+ display: flex;
298
+ flex-direction: column;
299
+ gap: 4px;
300
+ }
301
+
302
+ .player-name {
303
+ font-weight: 700;
304
+ font-size: 0.95rem;
305
+ color: #f3f4f6;
306
+ }
307
+
308
+ .player-level {
309
+ display: flex;
310
+ align-items: center;
311
+ gap: 6px;
312
+ }
313
+
314
+ .level-badge {
315
+ font-size: 0.65rem;
316
+ font-weight: 700;
317
+ padding: 2px 8px;
318
+ border-radius: 4px;
319
+ text-transform: uppercase;
320
+ letter-spacing: 0.5px;
321
+ }
322
+
323
+ .level-badge.legendary {
324
+ background: linear-gradient(135deg, #8b5cf6, #6366f1);
325
+ color: #fff;
326
+ }
327
+
328
+ .level-badge.diamond {
329
+ background: linear-gradient(135deg, #06b6d4, #0891b2);
330
+ color: #fff;
331
+ }
332
+
333
+ .level-badge.platinum {
334
+ background: linear-gradient(135deg, #6b7280, #4b5563);
335
+ color: #fff;
336
+ }
337
+
338
+ .level-badge.gold {
339
+ background: linear-gradient(135deg, #d4af37, #b8962e);
340
+ color: #0a0a0f;
341
+ }
342
+
343
+ .score {
344
+ font-family: 'Orbitron', sans-serif;
345
+ font-weight: 700;
346
+ font-size: 1.1rem;
347
+ color: #f3f4f6;
348
+ }
349
+
350
+ .winnings {
351
+ display: flex;
352
+ align-items: center;
353
+ gap: 6px;
354
+ font-weight: 700;
355
+ font-size: 1rem;
356
+ color: #10b981;
357
+ }
358
+
359
+ .winnings-icon {
360
+ font-size: 1.1rem;
361
+ }
362
+
363
+ .streak {
364
+ display: flex;
365
+ align-items: center;
366
+ gap: 4px;
367
+ font-weight: 600;
368
+ font-size: 0.9rem;
369
+ }
370
+
371
+ .streak.hot {
372
+ color: #f97316;
373
+ }
374
+
375
+ .streak.cold {
376
+ color: #6b7280;
377
+ }
378
+
379
+ .streak-icon {
380
+ font-size: 1rem;
381
+ }
382
+
383
+ .change {
384
+ display: flex;
385
+ align-items: center;
386
+ justify-content: center;
387
+ gap: 4px;
388
+ font-weight: 700;
389
+ font-size: 0.85rem;
390
+ }
391
+
392
+ .change.up {
393
+ color: #10b981;
394
+ }
395
+
396
+ .change.down {
397
+ color: #ef4444;
398
+ }
399
+
400
+ .change.same {
401
+ color: #6b7280;
402
+ }
403
+
404
+ .change-arrow {
405
+ font-size: 0.75rem;
406
+ }
407
+
408
+ .footer {
409
+ margin-top: 1.5rem;
410
+ padding-top: 1.5rem;
411
+ border-top: 1px solid rgba(255, 255, 255, 0.05);
412
+ display: flex;
413
+ justify-content: space-between;
414
+ align-items: center;
415
+ }
416
+
417
+ .footer-stats {
418
+ display: flex;
419
+ gap: 2rem;
420
+ }
421
+
422
+ .stat {
423
+ display: flex;
424
+ flex-direction: column;
425
+ gap: 4px;
426
+ }
427
+
428
+ .stat-label {
429
+ font-size: 0.65rem;
430
+ color: #6b7280;
431
+ text-transform: uppercase;
432
+ letter-spacing: 1px;
433
+ }
434
+
435
+ .stat-value {
436
+ font-weight: 700;
437
+ font-size: 1rem;
438
+ color: #f3f4f6;
439
+ }
440
+
441
+ .refresh-btn {
442
+ display: flex;
443
+ align-items: center;
444
+ gap: 8px;
445
+ padding: 10px 20px;
446
+ background: rgba(212, 175, 55, 0.1);
447
+ border: 1px solid rgba(212, 175, 55, 0.3);
448
+ border-radius: 10px;
449
+ color: #d4af37;
450
+ font-weight: 600;
451
+ font-size: 0.8rem;
452
+ cursor: pointer;
453
+ transition: all 0.3s ease;
454
+ text-transform: uppercase;
455
+ letter-spacing: 1px;
456
+ }
457
+
458
+ .refresh-btn:hover {
459
+ background: rgba(212, 175, 55, 0.2);
460
+ box-shadow: 0 4px 15px rgba(212, 175, 55, 0.2);
461
+ }
462
+
463
+ .refresh-icon {
464
+ transition: transform 0.5s ease;
465
+ }
466
+
467
+ .refresh-btn:hover .refresh-icon {
468
+ transform: rotate(180deg);
469
+ }
470
+
471
+ @keyframes pulse {
472
+ 0%,
473
+ 100% {
474
+ opacity: 1;
475
+ }
476
+ 50% {
477
+ opacity: 0.5;
478
+ }
479
+ }
480
+
481
+ .live-indicator {
482
+ display: flex;
483
+ align-items: center;
484
+ gap: 8px;
485
+ font-size: 0.7rem;
486
+ color: #ef4444;
487
+ text-transform: uppercase;
488
+ letter-spacing: 1px;
489
+ font-weight: 600;
490
+ }
491
+
492
+ .live-dot {
493
+ width: 8px;
494
+ height: 8px;
495
+ background: #ef4444;
496
+ border-radius: 50%;
497
+ animation: pulse 1.5s ease-in-out infinite;
498
+ box-shadow: 0 0 10px rgba(239, 68, 68, 0.6);
499
+ }
500
+
501
+ @media (max-width: 768px) {
502
+ .leaderboard {
503
+ padding: 1.25rem;
504
+ }
505
+
506
+ .header {
507
+ flex-direction: column;
508
+ align-items: flex-start;
509
+ gap: 1rem;
510
+ }
511
+
512
+ .prize-pool {
513
+ align-items: flex-start;
514
+ }
515
+
516
+ .table-header {
517
+ display: none;
518
+ }
519
+
520
+ .player-row {
521
+ grid-template-columns: 40px 1fr auto;
522
+ gap: 0.75rem;
523
+ padding: 0.875rem;
524
+ }
525
+
526
+ .rank {
527
+ width: 32px;
528
+ height: 32px;
529
+ font-size: 0.85rem;
530
+ }
531
+
532
+ .avatar {
533
+ width: 36px;
534
+ height: 36px;
535
+ }
536
+
537
+ .score,
538
+ .winnings,
539
+ .streak,
540
+ .change {
541
+ display: none;
542
+ }
543
+
544
+ .player-name {
545
+ font-size: 0.85rem;
546
+ }
547
+
548
+ .mobile-stats {
549
+ display: flex;
550
+ flex-direction: column;
551
+ align-items: flex-end;
552
+ gap: 2px;
553
+ }
554
+
555
+ .mobile-score {
556
+ font-family: 'Orbitron', sans-serif;
557
+ font-weight: 700;
558
+ font-size: 0.9rem;
559
+ color: #f3f4f6;
560
+ }
561
+
562
+ .mobile-winnings {
563
+ font-size: 0.75rem;
564
+ color: #10b981;
565
+ font-weight: 600;
566
+ }
567
+
568
+ .footer {
569
+ flex-direction: column;
570
+ gap: 1rem;
571
+ }
572
+
573
+ .footer-stats {
574
+ width: 100%;
575
+ justify-content: space-between;
576
+ }
577
+
578
+ .title {
579
+ font-size: 1.25rem;
580
+ }
581
+
582
+ .prize-amount {
583
+ font-size: 1.25rem;
584
+ }
585
+ }
@@ -0,0 +1,136 @@
1
+ import { LitElement, html } from 'lit';
2
+ import { customElement, property, state } from 'lit/decorators.js';
3
+ import { scss } from '../../lib/lit/scss.js';
4
+ import { getPlayers, getState } from './data.js';
5
+ import renderTemplate from './casino-leaderboard.html?lit-html';
6
+ import styles from './casino-leaderboard.scss?inline';
7
+
8
+ @customElement('casino-leaderboard')
9
+ export class CasinoLeaderboard extends LitElement {
10
+ static styles = scss(styles);
11
+
12
+ @property({ type: Array })
13
+ players = getPlayers();
14
+
15
+ initialData = getState();
16
+
17
+ @state()
18
+ private activeTab: 'daily' | 'weekly' | 'alltime' = this.initialData.activeTab;
19
+
20
+ @state()
21
+ private prizePool = this.initialData.prizePool;
22
+
23
+ @state()
24
+ private totalPlayers = this.initialData.totalPlayers;
25
+
26
+ @state()
27
+ private activePlayers = this.initialData.activePlayers;
28
+
29
+ formatNumber(num: number): string {
30
+ if (num >= 1000000) {
31
+ return (num / 1000000).toFixed(1) + 'M';
32
+ }
33
+ if (num >= 1000) {
34
+ return (num / 1000).toFixed(1) + 'K';
35
+ }
36
+ return num.toLocaleString();
37
+ }
38
+
39
+ formatMoney(num: number): string {
40
+ return '$' + num.toLocaleString();
41
+ }
42
+
43
+ getRankClass(rank: number): string {
44
+ if (rank === 1) return 'gold';
45
+ if (rank === 2) return 'silver';
46
+ if (rank === 3) return 'bronze';
47
+ return 'regular';
48
+ }
49
+
50
+ getRowClass(rank: number): string {
51
+ if (rank === 1) return 'top-1';
52
+ if (rank === 2) return 'top-2';
53
+ if (rank === 3) return 'top-3';
54
+ return '';
55
+ }
56
+
57
+ getLevelBadge(level: number): { class: string; text: string } {
58
+ const levels = [
59
+ { class: 'gold', text: 'Gold' },
60
+ { class: 'platinum', text: 'Platinum' },
61
+ { class: 'diamond', text: 'Diamond' },
62
+ { class: 'legendary', text: 'Legendary' },
63
+ ];
64
+ return levels[level - 1] || levels[0];
65
+ }
66
+
67
+ handleTabClick(tab: 'daily' | 'weekly' | 'alltime') {
68
+ this.activeTab = tab;
69
+ }
70
+
71
+ handleRefresh() {
72
+ this.dispatchEvent(
73
+ new CustomEvent('refresh', { bubbles: true, composed: true }),
74
+ );
75
+ }
76
+
77
+ renderPlayerList() {
78
+ return this.players.map(
79
+ (player) => html`
80
+ <div class="player-row ${this.getRowClass(player.rank)}">
81
+ <div class="rank ${this.getRankClass(player.rank)}">${player.rank}</div>
82
+ <div class="player-info">
83
+ <div class="avatar-container">
84
+ <img class="avatar" src="${player.avatar}" alt="${player.name}" />
85
+ <div
86
+ class="online-indicator ${player.isOnline ? '' : 'offline'}"
87
+ ></div>
88
+ </div>
89
+ <div class="player-details">
90
+ <span class="player-name">${player.name}</span>
91
+ <div class="player-level">
92
+ <span
93
+ class="level-badge ${this.getLevelBadge(player.level).class}"
94
+ >
95
+ ${this.getLevelBadge(player.level).text}
96
+ </span>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ <div class="score">${this.formatNumber(player.score)}</div>
101
+ <div class="winnings">
102
+ <span class="winnings-icon">💰</span>
103
+ ${this.formatMoney(player.winnings)}
104
+ </div>
105
+ <div class="streak ${player.streak >= 5 ? 'hot' : 'cold'}">
106
+ <span class="streak-icon">${player.streak >= 5 ? '🔥' : '⚡'}</span>
107
+ ${player.streak} wins
108
+ </div>
109
+ <div class="change ${player.change}">
110
+ ${player.change === 'up'
111
+ ? html`<span class="change-arrow">â–²</span> +3`
112
+ : ''}
113
+ ${player.change === 'down'
114
+ ? html`<span class="change-arrow">â–¼</span> -2`
115
+ : ''}
116
+ ${player.change === 'same' ? '—' : ''}
117
+ </div>
118
+ <div class="mobile-stats">
119
+ <span class="mobile-score">${this.formatNumber(player.score)}</span>
120
+ <span class="mobile-winnings">${this.formatMoney(player.winnings)}</span>
121
+ </div>
122
+ </div>
123
+ `,
124
+ );
125
+ }
126
+
127
+ render() {
128
+ return renderTemplate(this);
129
+ }
130
+ }
131
+
132
+ declare global {
133
+ interface HTMLElementTagNameMap {
134
+ 'casino-leaderboard': CasinoLeaderboard;
135
+ }
136
+ }