@gameap/ui 1.1.1 → 1.3.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.
package/README.md ADDED
@@ -0,0 +1,899 @@
1
+ # @gameap/ui
2
+
3
+ A Vue 3 component library providing GameAP-styled UI components. Built as a wrapper around [Naive UI](https://www.naiveui.com/) with sensible defaults and additional custom components.
4
+
5
+ ## Features
6
+
7
+ - 19 reusable Vue 3 components
8
+ - Wrapper components for Naive UI with GameAP defaults
9
+ - Flexible icon system with 150+ predefined icons
10
+ - Custom menu system with keyboard navigation
11
+ - Tailwind CSS integration
12
+ - Full TypeScript-friendly props
13
+ - Accessibility support (ARIA attributes, keyboard navigation)
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @gameap/ui
19
+ ```
20
+
21
+ ## Setup
22
+
23
+ Register the plugin in your Vue application:
24
+
25
+ ```javascript
26
+ import { createApp } from 'vue'
27
+ import gameapUI from '@gameap/ui'
28
+ import '@gameap/ui/style.css'
29
+
30
+ const app = createApp(App)
31
+ app.use(gameapUI)
32
+ app.mount('#app')
33
+ ```
34
+
35
+ Or import components individually:
36
+
37
+ ```javascript
38
+ import { GCard, GModal, GIcon } from '@gameap/ui'
39
+ ```
40
+
41
+ ## Components
42
+
43
+ ### GCard
44
+
45
+ Card container component wrapping Naive UI's NCard.
46
+
47
+ **Props:**
48
+
49
+ | Prop | Type | Default | Description |
50
+ |------|------|---------|-------------|
51
+ | title | string | `''` | Card title |
52
+ | size | string | `'small'` | Card size |
53
+ | bordered | boolean | `true` | Show border |
54
+ | segmented | boolean \| object | `{ content: true, footer: 'soft' }` | Content segmentation |
55
+ | headerClass | string | `'g-card-header'` | Header CSS class |
56
+
57
+ Supports all [Naive UI NCard props](https://www.naiveui.com/en-US/os-theme/components/card).
58
+
59
+ **Example:**
60
+
61
+ ```vue
62
+ <template>
63
+ <GCard title="Server Status">
64
+ <p>Server is running normally.</p>
65
+
66
+ <template #footer>
67
+ <button>Restart Server</button>
68
+ </template>
69
+ </GCard>
70
+ </template>
71
+ ```
72
+
73
+ ---
74
+
75
+ ### GDataTable
76
+
77
+ Data table component wrapping Naive UI's NDataTable.
78
+
79
+ **Props:**
80
+
81
+ | Prop | Type | Default | Description |
82
+ |------|------|---------|-------------|
83
+ | bordered | boolean | `false` | Show border |
84
+ | singleLine | boolean | `true` | Single line rows |
85
+ | columns | array | `[]` | Column definitions |
86
+ | data | array | `[]` | Table data |
87
+ | loading | boolean | `false` | Loading state |
88
+ | pagination | object \| boolean | `false` | Pagination config |
89
+ | remote | boolean | `false` | Remote data mode |
90
+
91
+ Supports all [Naive UI NDataTable props](https://www.naiveui.com/en-US/os-theme/components/data-table).
92
+
93
+ **Example:**
94
+
95
+ ```vue
96
+ <script setup>
97
+ const columns = [
98
+ { title: 'Name', key: 'name' },
99
+ { title: 'Status', key: 'status' },
100
+ { title: 'Players', key: 'players' }
101
+ ]
102
+
103
+ const data = [
104
+ { name: 'Server 1', status: 'Online', players: 12 },
105
+ { name: 'Server 2', status: 'Offline', players: 0 }
106
+ ]
107
+ </script>
108
+
109
+ <template>
110
+ <GDataTable :columns="columns" :data="data" />
111
+ </template>
112
+ ```
113
+
114
+ **With Pagination:**
115
+
116
+ ```vue
117
+ <script setup>
118
+ import { ref } from 'vue'
119
+
120
+ const pagination = ref({
121
+ page: 1,
122
+ pageSize: 10,
123
+ itemCount: 100,
124
+ showSizePicker: true,
125
+ pageSizes: [10, 20, 50]
126
+ })
127
+
128
+ function handlePageChange(page) {
129
+ pagination.value.page = page
130
+ fetchData()
131
+ }
132
+ </script>
133
+
134
+ <template>
135
+ <GDataTable
136
+ :columns="columns"
137
+ :data="data"
138
+ :pagination="pagination"
139
+ :remote="true"
140
+ @update:page="handlePageChange"
141
+ />
142
+ </template>
143
+ ```
144
+
145
+ ---
146
+
147
+ ### GTable
148
+
149
+ Simple table component wrapping Naive UI's NTable.
150
+
151
+ **Props:**
152
+
153
+ | Prop | Type | Default | Description |
154
+ |------|------|---------|-------------|
155
+ | bordered | boolean | `false` | Show border |
156
+ | singleLine | boolean | `true` | Single line rows |
157
+ | size | string | - | Table size |
158
+
159
+ **Example:**
160
+
161
+ ```vue
162
+ <template>
163
+ <GTable>
164
+ <thead>
165
+ <tr>
166
+ <th>Name</th>
167
+ <th>Value</th>
168
+ </tr>
169
+ </thead>
170
+ <tbody>
171
+ <tr>
172
+ <td>CPU Usage</td>
173
+ <td>45%</td>
174
+ </tr>
175
+ <tr>
176
+ <td>Memory</td>
177
+ <td>2.4 GB</td>
178
+ </tr>
179
+ </tbody>
180
+ </GTable>
181
+ </template>
182
+ ```
183
+
184
+ ---
185
+
186
+ ### GModal
187
+
188
+ Modal dialog component wrapping Naive UI's NModal.
189
+
190
+ **Props:**
191
+
192
+ | Prop | Type | Default | Description |
193
+ |------|------|---------|-------------|
194
+ | show | boolean | `false` | Modal visibility |
195
+ | preset | string | `'card'` | Modal preset |
196
+ | bordered | boolean | `false` | Show border |
197
+ | title | string | `''` | Modal title |
198
+ | segmented | object | `{ content: 'soft', footer: 'soft' }` | Content segmentation |
199
+
200
+ **Emits:**
201
+
202
+ | Event | Payload | Description |
203
+ |-------|---------|-------------|
204
+ | update:show | boolean | Emitted when modal should close |
205
+
206
+ Supports all [Naive UI NModal props](https://www.naiveui.com/en-US/os-theme/components/modal).
207
+
208
+ **Example:**
209
+
210
+ ```vue
211
+ <script setup>
212
+ import { ref } from 'vue'
213
+
214
+ const showModal = ref(false)
215
+ </script>
216
+
217
+ <template>
218
+ <button @click="showModal = true">Open Modal</button>
219
+
220
+ <GModal
221
+ v-model:show="showModal"
222
+ title="Confirm Action"
223
+ >
224
+ <p>Are you sure you want to proceed?</p>
225
+
226
+ <template #footer>
227
+ <button @click="showModal = false">Cancel</button>
228
+ <button @click="confirmAction">Confirm</button>
229
+ </template>
230
+ </GModal>
231
+ </template>
232
+ ```
233
+
234
+ ---
235
+
236
+ ### GInput
237
+
238
+ Input field component wrapping Naive UI's NInput.
239
+
240
+ **Props:**
241
+
242
+ | Prop | Type | Default | Description |
243
+ |------|------|---------|-------------|
244
+ | value | string \| array | - | Input value |
245
+ | type | string | `'text'` | Input type |
246
+ | placeholder | string | `''` | Placeholder text |
247
+ | disabled | boolean | `false` | Disabled state |
248
+ | readonly | boolean | `false` | Read-only state |
249
+ | clearable | boolean | `false` | Show clear button |
250
+ | size | string | - | Input size |
251
+
252
+ **Emits:**
253
+
254
+ | Event | Payload | Description |
255
+ |-------|---------|-------------|
256
+ | update:value | string | Emitted when value changes |
257
+
258
+ Supports all [Naive UI NInput props](https://www.naiveui.com/en-US/os-theme/components/input).
259
+
260
+ **Example:**
261
+
262
+ ```vue
263
+ <script setup>
264
+ import { ref } from 'vue'
265
+
266
+ const serverName = ref('')
267
+ </script>
268
+
269
+ <template>
270
+ <GInput
271
+ v-model:value="serverName"
272
+ placeholder="Enter server name"
273
+ clearable
274
+ />
275
+ </template>
276
+ ```
277
+
278
+ **Password Input:**
279
+
280
+ ```vue
281
+ <template>
282
+ <GInput
283
+ v-model:value="password"
284
+ type="password"
285
+ placeholder="Enter password"
286
+ show-password-on="click"
287
+ />
288
+ </template>
289
+ ```
290
+
291
+ ---
292
+
293
+ ### GSwitch
294
+
295
+ Toggle switch component wrapping Naive UI's NSwitch.
296
+
297
+ **Props:**
298
+
299
+ | Prop | Type | Default | Description |
300
+ |------|------|---------|-------------|
301
+ | value | boolean | `false` | Switch state |
302
+ | disabled | boolean | `false` | Disabled state |
303
+ | size | string | - | Switch size |
304
+
305
+ **Emits:**
306
+
307
+ | Event | Payload | Description |
308
+ |-------|---------|-------------|
309
+ | update:value | boolean | Emitted when state changes |
310
+
311
+ **Example:**
312
+
313
+ ```vue
314
+ <script setup>
315
+ import { ref } from 'vue'
316
+
317
+ const autoStart = ref(true)
318
+ </script>
319
+
320
+ <template>
321
+ <label>
322
+ Auto-start server
323
+ <GSwitch v-model:value="autoStart" />
324
+ </label>
325
+ </template>
326
+ ```
327
+
328
+ ---
329
+
330
+ ### GEmpty
331
+
332
+ Empty state component wrapping Naive UI's NEmpty.
333
+
334
+ **Props:**
335
+
336
+ | Prop | Type | Default | Description |
337
+ |------|------|---------|-------------|
338
+ | description | string | - | Description text |
339
+ | size | string | - | Component size |
340
+
341
+ **Example:**
342
+
343
+ ```vue
344
+ <template>
345
+ <GEmpty description="No servers found">
346
+ <template #extra>
347
+ <button>Add Server</button>
348
+ </template>
349
+ </GEmpty>
350
+ </template>
351
+ ```
352
+
353
+ ---
354
+
355
+ ### GDivider
356
+
357
+ Visual divider component wrapping Naive UI's NDivider.
358
+
359
+ **Example:**
360
+
361
+ ```vue
362
+ <template>
363
+ <div>Section 1</div>
364
+ <GDivider />
365
+ <div>Section 2</div>
366
+
367
+ <!-- With label -->
368
+ <GDivider>Or</GDivider>
369
+ </template>
370
+ ```
371
+
372
+ ---
373
+
374
+ ### GIcon
375
+
376
+ Flexible icon component supporting Font Awesome classes and Vue components.
377
+
378
+ **Props:**
379
+
380
+ | Prop | Type | Default | Description |
381
+ |------|------|---------|-------------|
382
+ | name | string | *required* | Icon name from registry |
383
+ | size | string | `'md'` | Size: `'sm'`, `'md'`, `'lg'`, `'xl'` |
384
+ | class | string | `''` | Additional CSS classes |
385
+
386
+ **Size Mappings:**
387
+
388
+ | Size | Font Awesome | Component |
389
+ |------|--------------|-----------|
390
+ | sm | fa-sm | 0.875em |
391
+ | md | (default) | 1em |
392
+ | lg | fa-lg | 1.25em |
393
+ | xl | fa-2x | 2em |
394
+
395
+ **Example:**
396
+
397
+ ```vue
398
+ <template>
399
+ <!-- Basic usage -->
400
+ <GIcon name="server" />
401
+
402
+ <!-- With size -->
403
+ <GIcon name="warning" size="lg" />
404
+
405
+ <!-- With custom class -->
406
+ <GIcon name="delete" class="text-red-500" />
407
+ </template>
408
+ ```
409
+
410
+ ---
411
+
412
+ ### GGameIcon
413
+
414
+ Game-specific icon component that displays icons based on game codes.
415
+
416
+ **Props:**
417
+
418
+ | Prop | Type | Default | Description |
419
+ |------|------|---------|-------------|
420
+ | game | string | `'minecraft'` | Game code identifier |
421
+
422
+ **Supported Games:**
423
+
424
+ The component includes built-in icon mappings for popular games:
425
+ - Counter-Strike series: `cs2`, `csgo`, `css`, `cstrike`, `cs15`, `czero`
426
+ - Valve games: `halflife`, `tf2`, `l4d`, `l4d2`, `dod`, `dods`, `garrysmod`
427
+ - Other popular games: `minecraft`, `rust`, `ark`, `arma2`, `arma3`, `7d2d`, `dst`, `fivem`, `gta`, `hurtworld`, `quake`, `quake2`, `quake3`, `samp`, `teamspeak`
428
+
429
+ For unknown game codes, the component automatically assigns a consistent fallback icon from a set of common gaming icons.
430
+
431
+ **Example:**
432
+
433
+ ```vue
434
+ <template>
435
+ <!-- Basic usage -->
436
+ <GGameIcon game="minecraft" />
437
+
438
+ <!-- In a table -->
439
+ <GDataTable :columns="columns" :data="servers">
440
+ <template #game="{ row }">
441
+ <GGameIcon :game="row.gameCode" class="mr-2" />
442
+ {{ row.gameName }}
443
+ </template>
444
+ </GDataTable>
445
+ </template>
446
+ ```
447
+
448
+ **With render function:**
449
+
450
+ ```vue
451
+ <script setup>
452
+ import { h } from 'vue'
453
+ import { GGameIcon } from '@gameap/ui'
454
+
455
+ const renderGameLabel = (option) => {
456
+ return [
457
+ h(GGameIcon, { game: option.value, class: 'mr-2' }),
458
+ option.label
459
+ ]
460
+ }
461
+ </script>
462
+ ```
463
+
464
+ ---
465
+
466
+ ### GBreadcrumbs
467
+
468
+ Breadcrumb navigation component with support for links, router links, and icons.
469
+
470
+ **Props:**
471
+
472
+ | Prop | Type | Default | Description |
473
+ |------|------|---------|-------------|
474
+ | items | array | *required* | Breadcrumb items |
475
+
476
+ **Item Structure:**
477
+
478
+ ```typescript
479
+ interface BreadcrumbItem {
480
+ text: string // Display text
481
+ link?: string // External URL
482
+ route?: string // Vue Router route
483
+ icon?: string // Icon class name
484
+ render?: () => VNode // Custom render function
485
+ }
486
+ ```
487
+
488
+ **Example:**
489
+
490
+ ```vue
491
+ <script setup>
492
+ const breadcrumbs = [
493
+ { text: 'Home', route: '/', icon: 'fa-solid fa-home' },
494
+ { text: 'Servers', route: '/servers' },
495
+ { text: 'Server 1' }
496
+ ]
497
+ </script>
498
+
499
+ <template>
500
+ <GBreadcrumbs :items="breadcrumbs" />
501
+ </template>
502
+ ```
503
+
504
+ **With Custom Render:**
505
+
506
+ ```vue
507
+ <script setup>
508
+ import { h } from 'vue'
509
+
510
+ const breadcrumbs = [
511
+ { text: 'Home', route: '/' },
512
+ {
513
+ text: 'Status',
514
+ render: () => h('span', { class: 'text-green-500' }, 'Online')
515
+ }
516
+ ]
517
+ </script>
518
+
519
+ <template>
520
+ <GBreadcrumbs :items="breadcrumbs" />
521
+ </template>
522
+ ```
523
+
524
+ ---
525
+
526
+ ### GStatusBadge
527
+
528
+ Status indicator badge with predefined color schemes.
529
+
530
+ **Props:**
531
+
532
+ | Prop | Type | Default | Description |
533
+ |------|------|---------|-------------|
534
+ | status | string | *required* | Status type |
535
+ | text | string | - | Override default text |
536
+
537
+ **Available Statuses:**
538
+
539
+ | Status | Color | Default Text |
540
+ |--------|-------|--------------|
541
+ | waiting | Stone (light) | waiting |
542
+ | working | Blue | working |
543
+ | error | Red | error |
544
+ | success | Green | success |
545
+ | canceled | Stone | canceled |
546
+
547
+ **Example:**
548
+
549
+ ```vue
550
+ <template>
551
+ <GStatusBadge status="success" />
552
+
553
+ <!-- With custom text -->
554
+ <GStatusBadge status="working" text="Installing..." />
555
+
556
+ <!-- In a table -->
557
+ <GDataTable :columns="columns" :data="data">
558
+ <template #status="{ row }">
559
+ <GStatusBadge :status="row.status" />
560
+ </template>
561
+ </GDataTable>
562
+ </template>
563
+ ```
564
+
565
+ ---
566
+
567
+ ### GDeletableList
568
+
569
+ List component with delete buttons for each item.
570
+
571
+ **Props:**
572
+
573
+ | Prop | Type | Default | Description |
574
+ |------|------|---------|-------------|
575
+ | items | array | *required* | List items |
576
+ | clickCallback | function | - | Called on item click: `(gameCode, id) => void` |
577
+ | deleteCallback | function | - | Called on delete click: `(id) => void` |
578
+
579
+ **Item Structure:**
580
+
581
+ ```typescript
582
+ interface ListItem {
583
+ id: any // Unique identifier
584
+ name: string // Display name
585
+ gameCode: string // Game code identifier
586
+ }
587
+ ```
588
+
589
+ **Example:**
590
+
591
+ ```vue
592
+ <script setup>
593
+ const games = [
594
+ { id: 1, name: 'Counter-Strike 2', gameCode: 'cs2' },
595
+ { id: 2, name: 'Minecraft', gameCode: 'minecraft' },
596
+ { id: 3, name: 'Rust', gameCode: 'rust' }
597
+ ]
598
+
599
+ function handleClick(gameCode, id) {
600
+ console.log(`Clicked ${gameCode} with id ${id}`)
601
+ }
602
+
603
+ function handleDelete(id) {
604
+ console.log(`Delete item ${id}`)
605
+ }
606
+ </script>
607
+
608
+ <template>
609
+ <GDeletableList
610
+ :items="games"
611
+ :click-callback="handleClick"
612
+ :delete-callback="handleDelete"
613
+ />
614
+ </template>
615
+ ```
616
+
617
+ ---
618
+
619
+ ### Menu System
620
+
621
+ A set of components for building accessible dropdown menus with keyboard navigation.
622
+
623
+ #### GMenu
624
+
625
+ Container component that provides menu context to children.
626
+
627
+ **Props:**
628
+
629
+ | Prop | Type | Default | Description |
630
+ |------|------|---------|-------------|
631
+ | as | string | `'div'` | HTML element tag |
632
+
633
+ #### GMenuButton
634
+
635
+ Button to toggle menu visibility.
636
+
637
+ #### GMenuItems
638
+
639
+ Container for menu items with visibility control.
640
+
641
+ **Props:**
642
+
643
+ | Prop | Type | Default | Description |
644
+ |------|------|---------|-------------|
645
+ | unmount | boolean | `true` | Unmount when closed (false uses v-show) |
646
+
647
+ #### GMenuItem
648
+
649
+ Individual menu item with slot props.
650
+
651
+ **Slot Props:**
652
+
653
+ | Prop | Type | Description |
654
+ |------|------|-------------|
655
+ | active | boolean | Item is currently focused |
656
+ | close | function | Close the menu |
657
+
658
+ **Features:**
659
+ - Click-outside detection
660
+ - ESC key closes menu
661
+ - Enter/Space/ArrowDown opens menu
662
+ - Hover state tracking
663
+ - ARIA attributes for accessibility
664
+
665
+ **Example:**
666
+
667
+ ```vue
668
+ <template>
669
+ <GMenu>
670
+ <GMenuButton class="btn btn-primary">
671
+ Actions
672
+ <GIcon name="chevron-down" size="sm" />
673
+ </GMenuButton>
674
+
675
+ <GMenuItems class="dropdown-menu">
676
+ <GMenuItem v-slot="{ active, close }">
677
+ <button
678
+ :class="{ 'bg-blue-100': active }"
679
+ @click="startServer(); close()"
680
+ >
681
+ <GIcon name="play" /> Start
682
+ </button>
683
+ </GMenuItem>
684
+
685
+ <GMenuItem v-slot="{ active, close }">
686
+ <button
687
+ :class="{ 'bg-blue-100': active }"
688
+ @click="stopServer(); close()"
689
+ >
690
+ <GIcon name="stop" /> Stop
691
+ </button>
692
+ </GMenuItem>
693
+
694
+ <GMenuItem v-slot="{ active, close }">
695
+ <button
696
+ :class="{ 'bg-red-100': active }"
697
+ @click="deleteServer(); close()"
698
+ >
699
+ <GIcon name="delete" /> Delete
700
+ </button>
701
+ </GMenuItem>
702
+ </GMenuItems>
703
+ </GMenu>
704
+ </template>
705
+ ```
706
+
707
+ ---
708
+
709
+ ### Loading
710
+
711
+ Animated loading spinner component.
712
+
713
+ **Example:**
714
+
715
+ ```vue
716
+ <template>
717
+ <Loading v-if="isLoading" />
718
+ <div v-else>
719
+ Content loaded
720
+ </div>
721
+ </template>
722
+ ```
723
+
724
+ ---
725
+
726
+ ### Progressbar
727
+
728
+ Linear progress bar with percentage display.
729
+
730
+ **Props:**
731
+
732
+ | Prop | Type | Default | Description |
733
+ |------|------|---------|-------------|
734
+ | progress | number | `0` | Progress percentage (0-100) |
735
+
736
+ **Example:**
737
+
738
+ ```vue
739
+ <script setup>
740
+ import { ref } from 'vue'
741
+
742
+ const downloadProgress = ref(45)
743
+ </script>
744
+
745
+ <template>
746
+ <Progressbar :progress="downloadProgress" />
747
+ </template>
748
+ ```
749
+
750
+ ---
751
+
752
+ ## Icon System
753
+
754
+ The package includes a flexible icon registry system.
755
+
756
+ ### Icon Registry API
757
+
758
+ ```javascript
759
+ import {
760
+ registerIcons,
761
+ getIcon,
762
+ hasIcon,
763
+ iconRegistry,
764
+ defaultIconMap
765
+ } from '@gameap/ui'
766
+
767
+ // Register custom icons
768
+ registerIcons({
769
+ 'my-icon': 'fa-solid fa-star',
770
+ 'custom-component': MyIconComponent
771
+ })
772
+
773
+ // Check if icon exists
774
+ if (hasIcon('server')) {
775
+ const icon = getIcon('server')
776
+ }
777
+
778
+ // Access all icons
779
+ console.log(iconRegistry)
780
+ ```
781
+
782
+ ### Default Icon Categories
783
+
784
+ The package includes 150+ predefined icon mappings:
785
+
786
+ **Action Icons:**
787
+ `delete`, `edit`, `save`, `add`, `close`, `copy`, `paste`, `cut`, `refresh`, `download`, `upload`, `search`, `view`, `clear`, `eraser`, `ban`, `move`
788
+
789
+ **Navigation Icons:**
790
+ `chevron-left`, `chevron-right`, `chevron-up`, `chevron-down`, `arrow-up`, `arrow-down`, `sort-asc`, `sort-desc`, `external-link`
791
+
792
+ **Status Icons:**
793
+ `check`, `warning`, `error`, `info`, `question`, `online`, `offline`, `certificate`, `heart-pulse`, `power-off`
794
+
795
+ **UI/State Icons:**
796
+ `loading`, `spinner`, `play`, `pause`, `stop`, `restart`
797
+
798
+ **Server/Infrastructure Icons:**
799
+ `server`, `node`, `hard-drive`, `terminal`, `console`, `gamepad`, `tasks`, `plug`, `memory`, `cpu`
800
+
801
+ **User/Auth Icons:**
802
+ `user`, `users`, `user-edit`, `login`, `logout`, `key`, `lock`, `address-card`, `profile`
803
+
804
+ **File Icons:**
805
+ `file`, `file-code`, `file-text`, `file-pdf`, `file-word`, `file-excel`, `folder`, `folder-open`, `clipboard`, `ftp`
806
+
807
+ **Brand Icons:**
808
+ `linux`, `windows`, `apple`, `telegram`, `discord`, `vk`, `reddit`, `patreon`, `teamspeak`
809
+
810
+ **Game Icons:**
811
+ `dice`, `dice-one` through `dice-six`, `cat`, `mods`
812
+
813
+ **Theme Icons:**
814
+ `sun`, `moon`
815
+
816
+ ### Custom Icon Registration
817
+
818
+ Register custom icons at app initialization:
819
+
820
+ ```javascript
821
+ import { registerIcons } from '@gameap/ui'
822
+ import CustomIcon from './components/CustomIcon.vue'
823
+
824
+ // Register Font Awesome classes
825
+ registerIcons({
826
+ 'rocket': 'fa-solid fa-rocket',
827
+ 'database': 'fa-solid fa-database'
828
+ })
829
+
830
+ // Register Vue components
831
+ registerIcons({
832
+ 'custom-logo': CustomIcon
833
+ })
834
+ ```
835
+
836
+ ---
837
+
838
+ ## CSS Utilities
839
+
840
+ The package provides Tailwind CSS utility classes in `style.css`.
841
+
842
+ ### Badge Classes
843
+
844
+ ```html
845
+ <span class="badge-red">Error</span>
846
+ <span class="badge-green">Success</span>
847
+ <span class="badge-orange">Warning</span>
848
+ <span class="badge-blue">Info</span>
849
+ <span class="badge-stone">Neutral</span>
850
+ <span class="badge-light">Light</span>
851
+ ```
852
+
853
+ All badge classes include dark mode support.
854
+
855
+ ### Progress Classes
856
+
857
+ ```html
858
+ <div class="progress">
859
+ <div class="progress-bar progress-bar-info" style="width: 50%">
860
+ 50%
861
+ </div>
862
+ </div>
863
+ ```
864
+
865
+ ---
866
+
867
+ ## Dependencies
868
+
869
+ ### Peer Dependencies
870
+
871
+ | Package | Version | Required |
872
+ |---------|---------|----------|
873
+ | vue | ^3.5.0 | Yes |
874
+ | vue-router | ^4.0.0 | Optional |
875
+
876
+ ### Runtime Dependencies
877
+
878
+ - **naive-ui** - Base UI component library
879
+
880
+ ### Styling Requirements
881
+
882
+ - **Tailwind CSS** - Must be configured in the consuming application
883
+ - **Font Awesome** - Required for default icon mappings
884
+
885
+ ---
886
+
887
+ ## Browser Support
888
+
889
+ Supports all modern browsers that support Vue 3:
890
+ - Chrome (latest)
891
+ - Firefox (latest)
892
+ - Safari (latest)
893
+ - Edge (latest)
894
+
895
+ ---
896
+
897
+ ## License
898
+
899
+ Part of the GameAP project.
@@ -0,0 +1,53 @@
1
+ <template>
2
+ <n-card
3
+ v-bind="mergedProps"
4
+ v-on="$attrs"
5
+ >
6
+ <template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
7
+ <slot :name="slotName" v-bind="slotProps || {}" />
8
+ </template>
9
+ </n-card>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { computed, useAttrs } from 'vue'
14
+ import { NCard } from 'naive-ui'
15
+
16
+ const props = defineProps({
17
+ title: {
18
+ type: String,
19
+ default: ''
20
+ },
21
+ size: {
22
+ type: String,
23
+ default: 'small'
24
+ },
25
+ bordered: {
26
+ type: Boolean,
27
+ default: true
28
+ },
29
+ segmented: {
30
+ type: [Boolean, Object],
31
+ default: () => ({ content: true, footer: 'soft' })
32
+ },
33
+ headerClass: {
34
+ type: String,
35
+ default: 'g-card-header'
36
+ }
37
+ })
38
+
39
+ defineOptions({
40
+ inheritAttrs: false
41
+ })
42
+
43
+ const attrs = useAttrs()
44
+
45
+ const mergedProps = computed(() => ({
46
+ title: props.title,
47
+ size: props.size,
48
+ bordered: props.bordered,
49
+ segmented: props.segmented,
50
+ headerClass: props.headerClass,
51
+ ...attrs
52
+ }))
53
+ </script>
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <n-data-table
3
+ v-bind="mergedProps"
4
+ v-on="$attrs"
5
+ >
6
+ <template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
7
+ <slot :name="slotName" v-bind="slotProps || {}" />
8
+ </template>
9
+ </n-data-table>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { computed, useAttrs } from 'vue'
14
+ import { NDataTable } from 'naive-ui'
15
+
16
+ const props = defineProps({
17
+ bordered: {
18
+ type: Boolean,
19
+ default: false
20
+ },
21
+ singleLine: {
22
+ type: Boolean,
23
+ default: true
24
+ },
25
+ columns: {
26
+ type: Array,
27
+ default: () => []
28
+ },
29
+ data: {
30
+ type: Array,
31
+ default: () => []
32
+ },
33
+ loading: {
34
+ type: Boolean,
35
+ default: false
36
+ },
37
+ pagination: {
38
+ type: [Object, Boolean],
39
+ default: false
40
+ },
41
+ remote: {
42
+ type: Boolean,
43
+ default: false
44
+ }
45
+ })
46
+
47
+ defineOptions({
48
+ inheritAttrs: false
49
+ })
50
+
51
+ const attrs = useAttrs()
52
+
53
+ const mergedProps = computed(() => ({
54
+ bordered: props.bordered,
55
+ singleLine: props.singleLine,
56
+ columns: props.columns,
57
+ data: props.data,
58
+ loading: props.loading,
59
+ pagination: props.pagination,
60
+ remote: props.remote,
61
+ ...attrs
62
+ }))
63
+ </script>
@@ -0,0 +1,9 @@
1
+ <template>
2
+ <n-divider v-bind="$attrs">
3
+ <slot />
4
+ </n-divider>
5
+ </template>
6
+
7
+ <script setup>
8
+ import { NDivider } from 'naive-ui'
9
+ </script>
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <n-empty
3
+ v-bind="mergedProps"
4
+ v-on="$attrs"
5
+ >
6
+ <template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
7
+ <slot :name="slotName" v-bind="slotProps || {}" />
8
+ </template>
9
+ </n-empty>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { computed, useAttrs } from 'vue'
14
+ import { NEmpty } from 'naive-ui'
15
+
16
+ const props = defineProps({
17
+ description: {
18
+ type: String,
19
+ default: undefined
20
+ },
21
+ size: {
22
+ type: String,
23
+ default: undefined
24
+ }
25
+ })
26
+
27
+ defineOptions({
28
+ inheritAttrs: false
29
+ })
30
+
31
+ const attrs = useAttrs()
32
+
33
+ const mergedProps = computed(() => ({
34
+ ...(props.description && { description: props.description }),
35
+ ...(props.size && { size: props.size }),
36
+ ...attrs
37
+ }))
38
+ </script>
@@ -0,0 +1,98 @@
1
+ <template>
2
+ <i :class="[gameIconClass, $attrs.class]"></i>
3
+ </template>
4
+
5
+ <script setup>
6
+ import { computed } from 'vue'
7
+
8
+ const icons = {
9
+ '7d2d': 'fa-solid fa-7',
10
+ '7days2die': 'fa-solid fa-7',
11
+ ark: 'gicon gicon-ark-survival-evolved',
12
+ arma2: 'gicon gicon-arma-2',
13
+ arma2oa: 'gicon gicon-arma-2',
14
+ arma3: 'gicon gicon-arma-3',
15
+ blackmesasource: 'gicon gicon-black-mesa',
16
+ bms: 'gicon gicon-black-mesa',
17
+ counterstrike: 'gicon gicon-counter-strike1',
18
+ cs15: 'gicon gicon-counter-strike1',
19
+ cs2: 'gicon gicon-counter-strike',
20
+ csgo: 'gicon gicon-counter-strike',
21
+ css: 'gicon gicon-counter-strike-source',
22
+ cssource: 'gicon gicon-counter-strike-source',
23
+ cssv34: 'gicon gicon-counter-strike-source',
24
+ cstrike: 'gicon gicon-counter-strike1',
25
+ czero: 'gicon gicon-counter-strike1',
26
+ dod: 'gicon gicon-day-of-defeat',
27
+ dods: 'gicon gicon-day-of-defeat',
28
+ dontstarve: 'gicon gicon-dont-starve',
29
+ dontstarvetogether: 'gicon gicon-dont-starve',
30
+ dst: 'gicon gicon-dont-starve',
31
+ fivem: 'gicon gicon-fivem',
32
+ garrysmod: 'gicon gicon-garrys-mod',
33
+ grandtheftauto: 'gicon gicon-grand-theft-auto',
34
+ gta: 'gicon gicon-grand-theft-auto',
35
+ halflife: 'gicon gicon-half-life',
36
+ hurtworld: 'gicon gicon-hurtworld',
37
+ l4d2: 'gicon gicon-left-4-dead',
38
+ l4d: 'gicon gicon-left-4-dead',
39
+ minecraft: 'gicon gicon-minecraft',
40
+ mta: 'gicon gicon-grand-theft-auto',
41
+ op4: 'gicon gicon-half-life',
42
+ pmmp: 'gicon gicon-minecraft-creeper',
43
+ qw: 'gicon gicon-quake',
44
+ q1: 'gicon gicon-quake',
45
+ quake: 'gicon gicon-quake',
46
+ q2: 'gicon gicon-quake-2',
47
+ quake2: 'gicon gicon-quake-2',
48
+ q3: 'gicon gicon-quake-3',
49
+ quake3: 'gicon gicon-quake-3',
50
+ q4: 'gicon gicon-quake',
51
+ quake4: 'gicon gicon-quake',
52
+ rust: 'gicon gicon-rust',
53
+ samp: 'gicon gicon-rockstar',
54
+ teamfortress2: 'gicon gicon-team-fortress-2',
55
+ teamspeak3: 'fa-brands fa-teamspeak',
56
+ teamspeak: 'fa-brands fa-teamspeak',
57
+ tf2: 'gicon gicon-team-fortress-2',
58
+ valve: 'gicon gicon-half-life',
59
+ }
60
+
61
+ const commonIcons = [
62
+ "fa-solid fa-gamepad",
63
+ "fa-solid fa-dice-one",
64
+ "fa-solid fa-dice-two",
65
+ "fa-solid fa-dice-three",
66
+ "fa-solid fa-dice-four",
67
+ "fa-solid fa-dice-five",
68
+ "fa-solid fa-dice-six",
69
+ "fa-solid fa-dice",
70
+ "fa-solid fa-puzzle-piece",
71
+ ]
72
+
73
+ const props = defineProps({
74
+ game: {
75
+ type: String,
76
+ default: 'minecraft',
77
+ },
78
+ })
79
+
80
+ const gameIconClass = computed(() => {
81
+ if (icons[props.game] !== undefined) {
82
+ return icons[props.game]
83
+ }
84
+ return defineCommonIcon(props.game)
85
+ })
86
+
87
+ function defineCommonIcon(game) {
88
+ return commonIcons[checksum(game)]
89
+ }
90
+
91
+ function checksum(data) {
92
+ let c = 0
93
+ for (let i = 0; i < data.length; i++) {
94
+ c += data.charCodeAt(i)
95
+ }
96
+ return c % commonIcons.length
97
+ }
98
+ </script>
@@ -0,0 +1,66 @@
1
+ <template>
2
+ <n-input
3
+ v-bind="mergedProps"
4
+ v-on="$attrs"
5
+ >
6
+ <template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
7
+ <slot :name="slotName" v-bind="slotProps || {}" />
8
+ </template>
9
+ </n-input>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { computed, useAttrs } from 'vue'
14
+ import { NInput } from 'naive-ui'
15
+
16
+ const props = defineProps({
17
+ value: {
18
+ type: [String, Array],
19
+ default: undefined
20
+ },
21
+ type: {
22
+ type: String,
23
+ default: 'text'
24
+ },
25
+ placeholder: {
26
+ type: String,
27
+ default: ''
28
+ },
29
+ disabled: {
30
+ type: Boolean,
31
+ default: false
32
+ },
33
+ readonly: {
34
+ type: Boolean,
35
+ default: false
36
+ },
37
+ clearable: {
38
+ type: Boolean,
39
+ default: false
40
+ },
41
+ size: {
42
+ type: String,
43
+ default: undefined
44
+ }
45
+ })
46
+
47
+ defineOptions({
48
+ inheritAttrs: false
49
+ })
50
+
51
+ const emit = defineEmits(['update:value'])
52
+
53
+ const attrs = useAttrs()
54
+
55
+ const mergedProps = computed(() => ({
56
+ value: props.value,
57
+ 'onUpdate:value': (val) => emit('update:value', val),
58
+ type: props.type,
59
+ placeholder: props.placeholder,
60
+ disabled: props.disabled,
61
+ readonly: props.readonly,
62
+ clearable: props.clearable,
63
+ ...(props.size && { size: props.size }),
64
+ ...attrs
65
+ }))
66
+ </script>
@@ -0,0 +1,56 @@
1
+ <template>
2
+ <n-modal
3
+ v-bind="mergedProps"
4
+ >
5
+ <template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
6
+ <slot :name="slotName" v-bind="slotProps || {}" />
7
+ </template>
8
+ </n-modal>
9
+ </template>
10
+
11
+ <script setup>
12
+ import { computed, useAttrs } from 'vue'
13
+ import { NModal } from 'naive-ui'
14
+
15
+ const props = defineProps({
16
+ show: {
17
+ type: Boolean,
18
+ default: false
19
+ },
20
+ preset: {
21
+ type: String,
22
+ default: 'card'
23
+ },
24
+ bordered: {
25
+ type: Boolean,
26
+ default: false
27
+ },
28
+ title: {
29
+ type: String,
30
+ default: ''
31
+ },
32
+ segmented: {
33
+ type: Object,
34
+ default: () => ({ content: 'soft', footer: 'soft' })
35
+ }
36
+ })
37
+
38
+ defineOptions({
39
+ inheritAttrs: false
40
+ })
41
+
42
+ const emit = defineEmits(['update:show'])
43
+
44
+ const attrs = useAttrs()
45
+
46
+ const mergedProps = computed(() => ({
47
+ show: props.show,
48
+ 'onUpdate:show': (value) => emit('update:show', value),
49
+ preset: props.preset,
50
+ bordered: props.bordered,
51
+ title: props.title,
52
+ segmented: props.segmented,
53
+ class: 'custom-card',
54
+ ...attrs
55
+ }))
56
+ </script>
@@ -0,0 +1,46 @@
1
+ <template>
2
+ <n-switch
3
+ v-bind="mergedProps"
4
+ v-on="$attrs"
5
+ >
6
+ <template v-for="(_, slotName) in $slots" :key="slotName" #[slotName]="slotProps">
7
+ <slot :name="slotName" v-bind="slotProps || {}" />
8
+ </template>
9
+ </n-switch>
10
+ </template>
11
+
12
+ <script setup>
13
+ import { computed, useAttrs } from 'vue'
14
+ import { NSwitch } from 'naive-ui'
15
+
16
+ const props = defineProps({
17
+ value: {
18
+ type: Boolean,
19
+ default: false
20
+ },
21
+ disabled: {
22
+ type: Boolean,
23
+ default: false
24
+ },
25
+ size: {
26
+ type: String,
27
+ default: undefined
28
+ }
29
+ })
30
+
31
+ defineOptions({
32
+ inheritAttrs: false
33
+ })
34
+
35
+ const emit = defineEmits(['update:value'])
36
+
37
+ const attrs = useAttrs()
38
+
39
+ const mergedProps = computed(() => ({
40
+ value: props.value,
41
+ 'onUpdate:value': (val) => emit('update:value', val),
42
+ disabled: props.disabled,
43
+ ...(props.size && { size: props.size }),
44
+ ...attrs
45
+ }))
46
+ </script>
@@ -0,0 +1,41 @@
1
+ <template>
2
+ <n-table
3
+ v-bind="mergedProps"
4
+ v-on="$attrs"
5
+ >
6
+ <slot />
7
+ </n-table>
8
+ </template>
9
+
10
+ <script setup>
11
+ import { computed, useAttrs } from 'vue'
12
+ import { NTable } from 'naive-ui'
13
+
14
+ const props = defineProps({
15
+ bordered: {
16
+ type: Boolean,
17
+ default: false
18
+ },
19
+ singleLine: {
20
+ type: Boolean,
21
+ default: true
22
+ },
23
+ size: {
24
+ type: String,
25
+ default: undefined
26
+ }
27
+ })
28
+
29
+ defineOptions({
30
+ inheritAttrs: false
31
+ })
32
+
33
+ const attrs = useAttrs()
34
+
35
+ const mergedProps = computed(() => ({
36
+ bordered: props.bordered,
37
+ singleLine: props.singleLine,
38
+ ...(props.size && { size: props.size }),
39
+ ...attrs
40
+ }))
41
+ </script>
package/index.js CHANGED
@@ -8,6 +8,15 @@ export { default as GMenuButton } from './components/GMenuButton.vue'
8
8
  export { default as GMenuItems } from './components/GMenuItems.vue'
9
9
  export { default as GMenuItem } from './components/GMenuItem.vue'
10
10
  export { default as GIcon } from './components/GIcon.vue'
11
+ export { default as GDataTable } from './components/GDataTable.vue'
12
+ export { default as GModal } from './components/GModal.vue'
13
+ export { default as GInput } from './components/GInput.vue'
14
+ export { default as GCard } from './components/GCard.vue'
15
+ export { default as GTable } from './components/GTable.vue'
16
+ export { default as GEmpty } from './components/GEmpty.vue'
17
+ export { default as GSwitch } from './components/GSwitch.vue'
18
+ export { default as GDivider } from './components/GDivider.vue'
19
+ export { default as GGameIcon } from './components/GGameIcon.vue'
11
20
 
12
21
  export { registerIcons, iconRegistry, getIcon, hasIcon } from './icons/registry.js'
13
22
  export { defaultIconMap } from './icons/iconMap.js'
@@ -22,6 +31,15 @@ import GMenuButton from './components/GMenuButton.vue'
22
31
  import GMenuItems from './components/GMenuItems.vue'
23
32
  import GMenuItem from './components/GMenuItem.vue'
24
33
  import GIcon from './components/GIcon.vue'
34
+ import GDataTable from './components/GDataTable.vue'
35
+ import GModal from './components/GModal.vue'
36
+ import GInput from './components/GInput.vue'
37
+ import GCard from './components/GCard.vue'
38
+ import GTable from './components/GTable.vue'
39
+ import GEmpty from './components/GEmpty.vue'
40
+ import GSwitch from './components/GSwitch.vue'
41
+ import GDivider from './components/GDivider.vue'
42
+ import GGameIcon from './components/GGameIcon.vue'
25
43
 
26
44
  export function install(app) {
27
45
  app.component('GBreadcrumbs', GBreadcrumbs)
@@ -34,6 +52,15 @@ export function install(app) {
34
52
  app.component('GMenuItems', GMenuItems)
35
53
  app.component('GMenuItem', GMenuItem)
36
54
  app.component('GIcon', GIcon)
55
+ app.component('GDataTable', GDataTable)
56
+ app.component('GModal', GModal)
57
+ app.component('GInput', GInput)
58
+ app.component('GCard', GCard)
59
+ app.component('GTable', GTable)
60
+ app.component('GEmpty', GEmpty)
61
+ app.component('GSwitch', GSwitch)
62
+ app.component('GDivider', GDivider)
63
+ app.component('GGameIcon', GGameIcon)
37
64
  }
38
65
 
39
66
  export default { install }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gameap/ui",
3
- "version": "1.1.1",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "module": "./index.js",