add tooltips
All checks were successful
Deploy App / docker (ubuntu-latest) (push) Successful in 1m31s

This commit is contained in:
Lee 2024-04-17 18:08:13 +01:00
parent 1a347108c2
commit 347ee00c18
8 changed files with 454 additions and 21 deletions

@ -10,6 +10,7 @@
}, },
"dependencies": { "dependencies": {
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tooltip": "^1.0.7",
"axios": "^1.6.8", "axios": "^1.6.8",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.1.0", "clsx": "^2.1.0",

@ -8,6 +8,9 @@ dependencies:
'@radix-ui/react-slot': '@radix-ui/react-slot':
specifier: ^1.0.2 specifier: ^1.0.2
version: 1.0.2(@types/react@18.2.78)(react@18.2.0) version: 1.0.2(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-tooltip':
specifier: ^1.0.7
version: 1.0.7(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
axios: axios:
specifier: ^1.6.8 specifier: ^1.6.8
version: 1.6.8 version: 1.6.8
@ -473,6 +476,34 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
/@floating-ui/core@1.6.0:
resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==}
dependencies:
'@floating-ui/utils': 0.2.1
dev: false
/@floating-ui/dom@1.6.3:
resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==}
dependencies:
'@floating-ui/core': 1.6.0
'@floating-ui/utils': 0.2.1
dev: false
/@floating-ui/react-dom@2.0.8(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==}
peerDependencies:
react: '>=16.8.0'
react-dom: '>=16.8.0'
dependencies:
'@floating-ui/dom': 1.6.3
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@floating-ui/utils@0.2.1:
resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==}
dev: false
/@humanwhocodes/config-array@0.11.14: /@humanwhocodes/config-array@0.11.14:
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
engines: {node: '>=10.10.0'} engines: {node: '>=10.10.0'}
@ -881,6 +912,33 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/@radix-ui/primitive@1.0.1:
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
dependencies:
'@babel/runtime': 7.24.4
dev: false
/@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.78
'@types/react-dom': 18.2.25
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.78)(react@18.2.0): /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
peerDependencies: peerDependencies:
@ -895,6 +953,154 @@ packages:
react: 18.2.0 react: 18.2.0
dev: false dev: false
/@radix-ui/react-context@1.0.1(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@types/react': 18.2.78
react: 18.2.0
dev: false
/@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.78)(react@18.2.0)
'@types/react': 18.2.78
'@types/react-dom': 18.2.25
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-id@1.0.1(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@types/react': 18.2.78
react: 18.2.0
dev: false
/@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@floating-ui/react-dom': 2.0.8(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-context': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-use-size': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/rect': 1.0.1
'@types/react': 18.2.78
'@types/react-dom': 18.2.25
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.78
'@types/react-dom': 18.2.25
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@types/react': 18.2.78
'@types/react-dom': 18.2.25
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.78)(react@18.2.0)
'@types/react': 18.2.78
'@types/react-dom': 18.2.25
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-slot@1.0.2(@types/react@18.2.78)(react@18.2.0): /@radix-ui/react-slot@1.0.2(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
peerDependencies: peerDependencies:
@ -910,6 +1116,153 @@ packages:
react: 18.2.0 react: 18.2.0
dev: false dev: false
/@radix-ui/react-tooltip@1.0.7(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-context': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-id': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.78
'@types/react-dom': 18.2.25
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@types/react': 18.2.78
react: 18.2.0
dev: false
/@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@types/react': 18.2.78
react: 18.2.0
dev: false
/@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@types/react': 18.2.78
react: 18.2.0
dev: false
/@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@types/react': 18.2.78
react: 18.2.0
dev: false
/@radix-ui/react-use-rect@1.0.1(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/rect': 1.0.1
'@types/react': 18.2.78
react: 18.2.0
dev: false
/@radix-ui/react-use-size@1.0.1(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0)
'@types/react': 18.2.78
react: 18.2.0
dev: false
/@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.24.4
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.78
'@types/react-dom': 18.2.25
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/rect@1.0.1:
resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==}
dependencies:
'@babel/runtime': 7.24.4
dev: false
/@rushstack/eslint-patch@1.10.2: /@rushstack/eslint-patch@1.10.2:
resolution: {integrity: sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==} resolution: {integrity: sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==}
dev: true dev: true
@ -1024,7 +1377,6 @@ packages:
resolution: {integrity: sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==} resolution: {integrity: sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==}
dependencies: dependencies:
'@types/react': 18.2.78 '@types/react': 18.2.78
dev: true
/@types/react@18.2.78: /@types/react@18.2.78:
resolution: {integrity: sha512-qOwdPnnitQY4xKlKayt42q5W5UQrSHjgoXNVEtxeqdITJ99k4VXJOP3vt8Rkm9HmgJpH50UNU+rlqfkfWOqp0A==} resolution: {integrity: sha512-qOwdPnnitQY4xKlKayt42q5W5UQrSHjgoXNVEtxeqdITJ99k4VXJOP3vt8Rkm9HmgJpH50UNU+rlqfkfWOqp0A==}

@ -1,13 +1,22 @@
import Link from "next/link"; import Link from "next/link";
import { Button } from "../components/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "../components/ui/tooltip";
type Button = { type Button = {
title: string; title: string;
tooltip: string;
url: string; url: string;
openInNewTab?: boolean;
}; };
const buttons: Button[] = [ const buttons: Button[] = [
{ title: "Get Started", url: "/player" }, { title: "Get Started", tooltip: "Click to get open the player page", url: "/player" },
{ title: "Documentation", url: "https://api.mcutils.xyz/swagger-ui.html" }, {
title: "Documentation",
tooltip: "Click to open the documentation",
url: "https://api.mcutils.xyz/swagger-ui.html",
openInNewTab: true,
},
]; ];
export default function Home(): JSX.Element { export default function Home(): JSX.Element {
@ -22,14 +31,18 @@ export default function Home(): JSX.Element {
<div className="mt-6 flex flex-row gap-2 justify-center"> <div className="mt-6 flex flex-row gap-2 justify-center">
{buttons.map((button, index) => { {buttons.map((button, index) => {
return ( return (
<Link <Tooltip key={index}>
key={index} <TooltipTrigger>
href={button.url} <Button key={index}>
target="_blank" <Link href={button.url} target={button.openInNewTab ? "_blank" : ""}>
className="w-fit p-2 rounded-lg hover:text-primary transition-all cursor-pointer bg-secondary"
>
<p>{button.title}</p> <p>{button.title}</p>
</Link> </Link>
</Button>
</TooltipTrigger>
<TooltipContent>
<p>{button.tooltip}</p>
</TooltipContent>
</Tooltip>
); );
})} })}
</div> </div>

@ -2,6 +2,7 @@
import { Card } from "@/app/components/card"; import { Card } from "@/app/components/card";
import { ErrorCard } from "@/app/components/error-card"; import { ErrorCard } from "@/app/components/error-card";
import { LookupPlayer } from "@/app/components/player/lookup-player"; import { LookupPlayer } from "@/app/components/player/lookup-player";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/app/components/ui/tooltip";
import { generateEmbed } from "@/common/embed"; import { generateEmbed } from "@/common/embed";
import { CachedPlayer, McUtilsAPIError, SkinPart, getPlayer } from "mcutils-library"; import { CachedPlayer, McUtilsAPIError, SkinPart, getPlayer } from "mcutils-library";
import { Metadata } from "next"; import { Metadata } from "next";
@ -92,9 +93,18 @@ export default async function Page({ params: { id } }: Params): Promise<JSX.Elem
.filter(([part]) => part !== SkinPart.HEAD) // Don't show the head part again .filter(([part]) => part !== SkinPart.HEAD) // Don't show the head part again
.map(([part, url]) => { .map(([part, url]) => {
return ( return (
<Link key={part} href={url} target="_blank"> <Tooltip key={part}>
<TooltipTrigger>
<Link href={url} target="_blank">
<img className="h-[64px]" src={url} alt={`The player's ${part}`} loading="lazy" /> <img className="h-[64px]" src={url} alt={`The player's ${part}`} loading="lazy" />
</Link> </Link>
</TooltipTrigger>
<TooltipContent>
<p>
Click to view {player.username}&apos;s {part}
</p>
</TooltipContent>
</Tooltip>
); );
})} })}
</div> </div>

@ -4,6 +4,7 @@ import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { Input } from "../ui/input"; import { Input } from "../ui/input";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
export function LookupPlayer(): JSX.Element { export function LookupPlayer(): JSX.Element {
const router = useRouter(); const router = useRouter();
@ -31,9 +32,16 @@ export function LookupPlayer(): JSX.Element {
return ( return (
<form className="flex gap-2 justify-center mt-2"> <form className="flex gap-2 justify-center mt-2">
<Input className="w-fit" placeholder="Name / UUID" value={player} onChange={setPlayerValue} maxLength={36} /> <Input className="w-fit" placeholder="Name / UUID" value={player} onChange={setPlayerValue} maxLength={36} />
<Tooltip>
<TooltipTrigger asChild>
<Button type="submit" onClick={() => lookupPlayer()}> <Button type="submit" onClick={() => lookupPlayer()}>
Lookup Lookup
</Button> </Button>
</TooltipTrigger>
<TooltipContent>
<p>Click to lookup the player</p>
</TooltipContent>
</Tooltip>
</form> </form>
); );
} }

@ -1,10 +1,12 @@
"use client"; "use client";
import { capitalizeFirstLetter } from "@/common/string-utils";
import { ServerPlatform } from "mcutils-library"; import { ServerPlatform } from "mcutils-library";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { Input } from "../ui/input"; import { Input } from "../ui/input";
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
export function LookupServer(): JSX.Element { export function LookupServer(): JSX.Element {
const router = useRouter(); const router = useRouter();
@ -31,12 +33,26 @@ export function LookupServer(): JSX.Element {
router.push(`/server/${platform}/${hostname}`); router.push(`/server/${platform}/${hostname}`);
}; };
const LookupButton = ({ platform }: { platform: ServerPlatform }): JSX.Element => {
const name = capitalizeFirstLetter(platform);
return (
<Tooltip>
<TooltipTrigger asChild>
<Button type="submit">{name}</Button>
</TooltipTrigger>
<TooltipContent>
<p>Click to lookup the server as a {name} server</p>
</TooltipContent>
</Tooltip>
);
};
return ( return (
<form className="flex gap-2 justify-center items-center mt-2 flex-col xs:flex-row"> <form className="flex gap-2 justify-center items-center mt-2 flex-col xs:flex-row">
<Input className="w-fit" placeholder="Hostname" value={hostname} onChange={setHostnameValue} maxLength={128} /> <Input className="w-fit" placeholder="Hostname" value={hostname} onChange={setHostnameValue} maxLength={128} />
<div className="flex gap-2 justify-center"> <div className="flex gap-2 justify-center">
<Button onClick={() => lookupServer(ServerPlatform.Java)}>Java</Button> <LookupButton platform={ServerPlatform.Java} />
<Button onClick={() => lookupServer(ServerPlatform.Bedrock)}>Bedrock</Button> <LookupButton platform={ServerPlatform.Bedrock} />
</div> </div>
</form> </form>
); );

@ -0,0 +1,30 @@
"use client"
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import { cn } from "@/common/utils"
const TooltipProvider = TooltipPrimitive.Provider
const Tooltip = TooltipPrimitive.Root
const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }

@ -8,6 +8,7 @@ import "./globals.css";
import Config from "../../config.json"; import Config from "../../config.json";
import Container from "./components/container"; import Container from "./components/container";
import ThemeProvider from "./components/theme-provider"; import ThemeProvider from "./components/theme-provider";
import { TooltipProvider } from "./components/ui/tooltip";
export const viewport: Viewport = { export const viewport: Viewport = {
themeColor: "#3498DB", themeColor: "#3498DB",
@ -49,8 +50,10 @@ export default function RootLayout({
<head /> <head />
<body> <body>
<ThemeProvider attribute="class" defaultTheme="dark" enableSystem> <ThemeProvider attribute="class" defaultTheme="dark" enableSystem>
<TooltipProvider>
<ToastContainer theme="dark" pauseOnFocusLoss={false} /> <ToastContainer theme="dark" pauseOnFocusLoss={false} />
<Container>{children}</Container> <Container>{children}</Container>
</TooltipProvider>
</ThemeProvider> </ThemeProvider>
</body> </body>
</html> </html>