Added keybinds + command palette + more stuff

main
Elias Almqvist 8 months ago
parent 569c557382
commit 2445e07411
No known key found for this signature in database
GPG Key ID: E31A99CE3E75A158
  1. 2
      next.config.js
  2. 6
      package.json
  3. 435
      pnpm-lock.yaml
  4. 5
      src/app/layout.tsx
  5. 58
      src/app/page.tsx
  6. 33
      src/components/binds/binds.tsx
  7. 38
      src/components/binds/index.tsx
  8. 41
      src/components/binds/navbinds.tsx
  9. 17
      src/components/layout/header.tsx
  10. 14
      src/components/layout/index.tsx
  11. 119
      src/components/layout/nav.tsx
  12. 31
      src/components/logo.tsx
  13. 26
      src/components/ui/button.tsx
  14. 155
      src/components/ui/command.tsx
  15. 122
      src/components/ui/dialog.tsx
  16. 31
      src/components/ui/separator.tsx
  17. 11
      src/hooks/useActionCommand.ts

@ -1,4 +1,4 @@
const withMDX = require('@next/mdx')()
const withMDX = require("@next/mdx")();
/** @type {import('next').NextConfig} */
const nextConfig = {

@ -14,18 +14,22 @@
"@mdx-js/loader": "^3.0.1",
"@mdx-js/react": "^3.0.1",
"@next/mdx": "^14.1.4",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@tailwindcss/typography": "^0.5.12",
"@types/mdx": "^2.0.12",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cmdk": "^1.0.0",
"lucide-react": "^0.363.0",
"next": "14.1.4",
"next-themes": "^0.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"zustand": "^4.5.2"
},
"devDependencies": {
"@types/node": "^20.11.30",

@ -14,6 +14,12 @@ dependencies:
'@next/mdx':
specifier: ^14.1.4
version: 14.1.4(@mdx-js/loader@3.0.1)(@mdx-js/react@3.0.1)
'@radix-ui/react-dialog':
specifier: ^1.0.5
version: 1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-separator':
specifier: ^1.0.3
version: 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-slot':
specifier: ^1.0.2
version: 1.0.2(@types/react@18.2.73)(react@18.2.0)
@ -29,6 +35,9 @@ dependencies:
clsx:
specifier: ^2.1.0
version: 2.1.0
cmdk:
specifier: ^1.0.0
version: 1.0.0(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
lucide-react:
specifier: ^0.363.0
version: 0.363.0(react@18.2.0)
@ -50,6 +59,9 @@ dependencies:
tailwindcss-animate:
specifier: ^1.0.7
version: 1.0.7(tailwindcss@3.4.3)
zustand:
specifier: ^4.5.2
version: 4.5.2(@types/react@18.2.73)(react@18.2.0)
devDependencies:
'@types/node':
@ -381,6 +393,12 @@ packages:
requiresBuild: true
optional: true
/@radix-ui/primitive@1.0.1:
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
dependencies:
'@babel/runtime': 7.24.1
dev: false
/@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.73)(react@18.2.0):
resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
peerDependencies:
@ -395,6 +413,216 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-context@1.0.1(@types/react@18.2.73)(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.1
'@types/react': 18.2.73
react: 18.2.0
dev: false
/@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==}
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.1
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@radix-ui/react-context': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-id': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.73)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@types/react': 18.2.73
'@types/react-dom': 18.2.23
aria-hidden: 1.2.4
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-remove-scroll: 2.5.5(@types/react@18.2.73)(react@18.2.0)
dev: false
/@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.73)(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.1
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.73)(react@18.2.0)
'@types/react': 18.2.73
'@types/react-dom': 18.2.23
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.73)(react@18.2.0):
resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.24.1
'@types/react': 18.2.73
react: 18.2.0
dev: false
/@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==}
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.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@types/react': 18.2.73
'@types/react-dom': 18.2.23
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.73)(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.1
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@types/react': 18.2.73
react: 18.2.0
dev: false
/@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.23)(@types/react@18.2.73)(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.1
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.73
'@types/react-dom': 18.2.23
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.23)(@types/react@18.2.73)(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.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@types/react': 18.2.73
'@types/react-dom': 18.2.23
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.23)(@types/react@18.2.73)(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.1
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.73)(react@18.2.0)
'@types/react': 18.2.73
'@types/react-dom': 18.2.23
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-separator@1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==}
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.1
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.73
'@types/react-dom': 18.2.23
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.73)(react@18.2.0):
resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==}
peerDependencies:
@ -410,6 +638,64 @@ packages:
react: 18.2.0
dev: false
/@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.73)(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.1
'@types/react': 18.2.73
react: 18.2.0
dev: false
/@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.73)(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.1
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@types/react': 18.2.73
react: 18.2.0
dev: false
/@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.73)(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.1
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.73)(react@18.2.0)
'@types/react': 18.2.73
react: 18.2.0
dev: false
/@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.73)(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.1
'@types/react': 18.2.73
react: 18.2.0
dev: false
/@rushstack/eslint-patch@1.10.1:
resolution: {integrity: sha512-S3Kq8e7LqxkA9s7HKLqXGTGck1uwis5vAXan3FnU5yw1Ec5hsSGnq4s/UCaSqABPOnOTg7zASLyst7+ohgWexg==}
dev: true
@ -508,7 +794,6 @@ packages:
resolution: {integrity: sha512-ZQ71wgGOTmDYpnav2knkjr3qXdAFu0vsk8Ci5w3pGAIdj7/kKAyn+VsQDhXsmzzzepAiI9leWMmubXz690AI/A==}
dependencies:
'@types/react': 18.2.73
dev: true
/@types/react@18.2.73:
resolution: {integrity: sha512-XcGdod0Jjv84HOC7N5ziY3x+qL0AfmubvKOZ9hJjJ2yd5EE+KYjWhdOjt387e9HPheHkdggF9atTifMRtyAaRA==}
@ -776,6 +1061,13 @@ packages:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
/aria-hidden@1.2.4:
resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==}
engines: {node: '>=10'}
dependencies:
tslib: 2.6.2
dev: false
/aria-query@5.3.0:
resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
dependencies:
@ -1067,6 +1359,21 @@ packages:
engines: {node: '>=6'}
dev: false
/cmdk@1.0.0(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
dependencies:
'@radix-ui/react-dialog': 1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
transitivePeerDependencies:
- '@types/react'
- '@types/react-dom'
dev: false
/collapse-white-space@2.1.0:
resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==}
dev: false
@ -1197,6 +1504,10 @@ packages:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
/detect-node-es@1.1.0:
resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==}
dev: false
/devlop@1.1.0:
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
dependencies:
@ -1829,6 +2140,11 @@ packages:
hasown: 2.0.2
dev: true
/get-nonce@1.0.1:
resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==}
engines: {node: '>=6'}
dev: false
/get-symbol-description@1.0.2:
resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==}
engines: {node: '>= 0.4'}
@ -2067,6 +2383,12 @@ packages:
side-channel: 1.0.6
dev: true
/invariant@2.2.4:
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
dependencies:
loose-envify: 1.4.0
dev: false
/is-alphabetical@2.0.1:
resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==}
dev: false
@ -3269,6 +3591,58 @@ packages:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
dev: true
/react-remove-scroll-bar@2.3.6(@types/react@18.2.73)(react@18.2.0):
resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==}
engines: {node: '>=10'}
peerDependencies:
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@types/react': 18.2.73
react: 18.2.0
react-style-singleton: 2.2.1(@types/react@18.2.73)(react@18.2.0)
tslib: 2.6.2
dev: false
/react-remove-scroll@2.5.5(@types/react@18.2.73)(react@18.2.0):
resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==}
engines: {node: '>=10'}
peerDependencies:
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@types/react': 18.2.73
react: 18.2.0
react-remove-scroll-bar: 2.3.6(@types/react@18.2.73)(react@18.2.0)
react-style-singleton: 2.2.1(@types/react@18.2.73)(react@18.2.0)
tslib: 2.6.2
use-callback-ref: 1.3.2(@types/react@18.2.73)(react@18.2.0)
use-sidecar: 1.1.2(@types/react@18.2.73)(react@18.2.0)
dev: false
/react-style-singleton@2.2.1(@types/react@18.2.73)(react@18.2.0):
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
engines: {node: '>=10'}
peerDependencies:
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@types/react': 18.2.73
get-nonce: 1.0.1
invariant: 2.2.4
react: 18.2.0
tslib: 2.6.2
dev: false
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
@ -3957,6 +4331,45 @@ packages:
dependencies:
punycode: 2.3.1
/use-callback-ref@1.3.2(@types/react@18.2.73)(react@18.2.0):
resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==}
engines: {node: '>=10'}
peerDependencies:
'@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@types/react': 18.2.73
react: 18.2.0
tslib: 2.6.2
dev: false
/use-sidecar@1.1.2(@types/react@18.2.73)(react@18.2.0):
resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==}
engines: {node: '>=10'}
peerDependencies:
'@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0
peerDependenciesMeta:
'@types/react':
optional: true
dependencies:
'@types/react': 18.2.73
detect-node-es: 1.1.0
react: 18.2.0
tslib: 2.6.2
dev: false
/use-sync-external-store@1.2.0(react@18.2.0):
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
dependencies:
react: 18.2.0
dev: false
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@ -4118,6 +4531,26 @@ packages:
engines: {node: '>=10'}
dev: true
/zustand@4.5.2(@types/react@18.2.73)(react@18.2.0):
resolution: {integrity: sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==}
engines: {node: '>=12.7.0'}
peerDependencies:
'@types/react': '>=16.8'
immer: '>=9.0.6'
react: '>=16.8'
peerDependenciesMeta:
'@types/react':
optional: true
immer:
optional: true
react:
optional: true
dependencies:
'@types/react': 18.2.73
react: 18.2.0
use-sync-external-store: 1.2.0(react@18.2.0)
dev: false
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
dev: false

@ -9,6 +9,7 @@ export const metadata: Metadata = {
import { cn } from "@/lib/utils";
import { ThemeProvider } from "@/components/theme-provider";
import Layout from "@/components/layout";
const fontSans = FontSans({
subsets: ["latin"],
@ -34,9 +35,7 @@ export default function RootLayout({
enableSystem
disableTransitionOnChange
>
<main className="w-full flex flex-col justify-center">
{children}
</main>
<Layout>{children}</Layout>
</ThemeProvider>
</body>
</html>

@ -1,62 +1,8 @@
"use client";
import { useTheme } from "next-themes";
export default function Home() {
const theme = useTheme();
return (
<>
<section>
<h2 id="about">/almqv</h2>
<p>
I am a 100201-year-old <em>engineer</em> with a passion for{" "}
<em>CS</em>, <em>physics</em>, and <em>mathematics</em>.
</p>
<p>
I am also a startup founder. Currently working on{" "}
<a
href="https://www.linkedin.com/company/ingenuityai/"
target="_blank"
rel="noreferrer"
>
ingenuity
</a>
.
</p>
{/*TODO: Add GitHub code frequency/contrib here*/}
<p className="topmargin">
Most of my projects are open-source, and if you are interested, you
can find all of my projects on my{" "}
<a href="https://git.wych.dev/elal" target="_blank" rel="noreferrer">
git-server
</a>{" "}
or{" "}
<a href="https://github.com/almqv" target="_blank" rel="noreferrer">
GitHub
</a>
.
</p>
</section>
<section>
<h2 id="contact">Contact</h2>
<p>
You can contact me through email. And if you prefer it, you can
contact me using PGP.
</p>
<ul>
<li>
PGP fingerprint:{" "}
<code>68B2 9768 49F0 3C72 38AE B081 E31A 99CE 3E75 A158</code>
</li>
<li>Email: elalmqvist@gmail.com</li>
<li>
GitHub:{" "}
<a href="https://github.com/almqv" target="_blank" rel="noreferrer">
github.com/almqv
</a>
</li>
</ul>
<section id="about">
<p>TEST</p>
</section>
</>
);

@ -0,0 +1,33 @@
"use client";
import { useRouter } from "next/navigation";
import Keybinds from "@/components/binds";
import { useActionCommand } from "@/hooks/useActionCommand";
import { useTheme } from "next-themes";
const NavBinds = () => {
const router = useRouter();
const { open: actionOpen, setOpen: setActionOpen } = useActionCommand();
const { theme, setTheme } = useTheme();
return (
<Keybinds
keybinds={{
h: () => {
router.push("/");
},
p: () => {
router.push("/posts");
},
k: () => {
setActionOpen(!actionOpen);
},
l: () => {
setTheme(theme === "light" ? "dark" : "light");
},
}}
/>
);
};
export default NavBinds;

@ -0,0 +1,38 @@
"use client";
import React, { useEffect } from "react";
export type KeybindActionProps = () => void;
export type Keybinds = { [key: string]: KeybindActionProps };
type KeybindsProps = {
keybinds: Keybinds;
};
const Keybinds: React.FC<KeybindsProps> = ({ keybinds }) => {
const keyDownHandler = async (event: KeyboardEvent) => {
try {
if (event.metaKey || event.ctrlKey) {
// Iterate over other keybinds and do them
for (const [key, bind] of Object.entries(keybinds ?? {})) {
if (event.key === key) {
event.preventDefault();
bind();
return;
}
}
}
} catch (error) {
console.error("Error in key down handler:", error);
}
};
useEffect(() => {
document.addEventListener("keydown", keyDownHandler);
return () => document.removeEventListener("keydown", keyDownHandler);
});
return <div className="" id="keybinds_handler" />;
};
export default Keybinds;

@ -0,0 +1,41 @@
"use client";
import { useRouter } from "next/navigation";
import Keybinds from "@/components/inputs/keybinds";
import { useActionCommand } from "@/hooks/useActionCommand";
import { useSidebar } from "@/hooks/useSidebar";
import { useTheme } from "next-themes";
const NavBinds = () => {
const router = useRouter();
const { open: actionOpen, setOpen: setActionOpen } = useActionCommand();
const { open: sidebarOpen, setOpen: setSidebarOpen } = useSidebar();
const { theme, setTheme } = useTheme();
return (
<Keybinds
keybinds={{
f: () => {
router.push("/");
},
s: () => {
router.push("/settings");
},
h: () => {
router.push("/history");
},
k: () => {
setActionOpen(!actionOpen);
},
g: () => {
setSidebarOpen(!sidebarOpen);
},
l: () => {
setTheme(theme === "light" ? "dark" : "light");
},
}}
/>
);
};
export default NavBinds;

@ -0,0 +1,17 @@
import Logo from "@/components/logo";
import { Separator } from "@/components/ui/separator";
import Nav from "./nav";
const Header = () => (
<header className="w-full h-16 flex flex-col justify-center items-center mb-4">
<div className="py-4 flex flex-row justify-between w-full max-w-screen-lg">
<div className="flex flex-row items-center gap-x-2">
<Logo className="h-8 w-8" />
<span className="font-mono text-2xl">wych.dev</span>
</div>
<Nav />
</div>
<Separator />
</header>
);
export default Header;

@ -0,0 +1,14 @@
import NavBinds from "@/components/binds/navbinds";
import Header from "./header";
const Layout = ({ children }: { children: React.ReactNode }) => {
return (
<>
<Header />
<div className="max-w-screen-lg md:px-8">{children}</div>
<NavBinds />
</>
);
};
export default Layout;

@ -0,0 +1,119 @@
"use client";
import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import {
CommandDialog,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
CommandShortcut,
} from "@/components/ui/command";
import {
GalleryHorizontalEnd,
Home,
PanelRightClose,
Scroll,
Search,
Settings,
SunMoon,
} from "lucide-react";
import { useRouter } from "next/navigation";
import { useActionCommand } from "@/hooks/useActionCommand";
import { useTheme } from "next-themes";
type ActionCommandProps = {
className?: string;
};
const ActionCommand: React.FC<ActionCommandProps> = ({
className,
...props
}) => {
const [value, setValue] = useState("");
const router = useRouter();
const { open: actionOpen, setOpen: setActionOpen } = useActionCommand();
const { theme, setTheme } = useTheme();
const action = (
callback: ((value: string) => Promise<void>) | ((value: string) => void),
) => {
return async (value: string) => {
setActionOpen(false);
await callback(value);
};
};
return (
<>
<Button
variant="outline"
className={cn(
"relative h-8 w-full justify-start rounded-[0.5rem] bg-background text-sm font-normal text-muted-foreground shadow-none sm:pr-12 md:w-40 lg:w-64",
className,
)}
onClick={() => setActionOpen(true)}
{...props}
>
<span className="hidden lg:inline-flex">Navigation...</span>
<span className="inline-flex lg:hidden">Search...</span>
<kbd className="pointer-events-none absolute right-[0.3rem] top-[0.3rem] hidden h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium opacity-100 sm:flex">
<span className="text-xs"></span>K
</kbd>
</Button>
<CommandDialog open={actionOpen} onOpenChange={setActionOpen}>
<CommandInput
placeholder="Type a command or search..."
onValueChange={(search) => {
setValue(search);
}}
/>
<CommandList>
<CommandGroup heading="Navigation">
<CommandItem
onSelect={action(() => {
router.push("/");
})}
>
<Home className="mr-2 w-4 h-4" />
<span>Home</span>
<CommandShortcut>H</CommandShortcut>
</CommandItem>
<CommandItem
onSelect={action(() => {
router.push("/posts");
})}
>
<GalleryHorizontalEnd className="mr-2 w-4 h-4" />
<span>Posts</span>
<CommandShortcut>P</CommandShortcut>
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Appearance">
<CommandItem
onSelect={action(() => {
setTheme(theme === "light" ? "dark" : "light");
})}
>
<SunMoon className="mr-2 w-4 h-4" />
<span>
Switch to {theme === "light" ? "Dark" : "Light"} Theme
</span>
<CommandShortcut>L</CommandShortcut>
</CommandItem>
</CommandGroup>
</CommandList>
</CommandDialog>
</>
);
};
export default ActionCommand;

@ -0,0 +1,31 @@
import * as React from "react";
import { SVGProps } from "react";
type LogoProps = { className?: string } & SVGProps<SVGSVGElement>;
const Logo: React.FC<LogoProps> = (props: SVGProps<SVGSVGElement>) => (
<svg
xmlns="http://www.w3.org/2000/svg"
// width={92}
// height={129}
viewBox="0 0 92 129"
fill="none"
{...props}
>
<path
fill="currentColor"
d="m40.915 4.102 8.244-.876-5.315 11.358-1.313 3.512a43.993 43.993 0 0 0-2.784 15.01l-.004.493a38.5 38.5 0 0 0 .555 6.872l.349 2.029c.16.935.406 1.854.732 2.746l.455 1.242a9.208 9.208 0 0 0 4.235 4.918l.339.185c.964.526 1.997.913 3.07 1.148l1.127.247a8.05 8.05 0 0 0 5.944-1.008l2.78-1.712a66.103 66.103 0 0 0 10.82-10.624l4.146-5.132 7.378-11.35a.825.825 0 0 0 .129-.536.825.825 0 0 1 .733-.908l.16-.017a.984.984 0 0 1 .261.007l2.387.387 1.519.245a7.548 7.548 0 0 0 2.003.055l1.188-.126a.185.185 0 0 0 .058-.016c.173-.079.34.12.232.277l-1.954 2.839-4.382 7.436-3.388 6.207L75.48 49.9l-3.62 8.255-1.228 3.283a12.15 12.15 0 0 0-.353 7.409l.647 2.41c.085.315.122.64.11.966l-.013.357a2.198 2.198 0 0 1-1.858 2.093l-5.397.84a16.353 16.353 0 0 1-5.649-.107l-.17-.033-3.922-.932-7.493-2.802-5.914-2.745-5.913-2.744-6.557-2.452-1.036 2.771a22.716 22.716 0 0 0-1.21 11.159l.508 3.57 1.3 12.23 2.826 18.138.463 1.574a6.011 6.011 0 0 0 3.054 3.671l1.356.686c.81.41 1.666.723 2.55.933l1.042.248c1.031.245 2.08.411 3.137.495l2.041.163 1.58.057-3.685 1.291-2.752.808a13.13 13.13 0 0 1-6.218.29l-.44-.087a18.752 18.752 0 0 1-2.995-.845l-1.495-.559a11.916 11.916 0 0 1-1.53-.699l-.681-.372a8.453 8.453 0 0 1-4.177-5.487l-.849-3.621-2.065-17.32L17.4 81.031l-.105-7.968a16.35 16.35 0 0 1 .301-3.345l.164-.838c.063-.326.154-.647.27-.958l.628-1.68c.159-.424.48-.768.891-.955l1.287-.587a10.336 10.336 0 0 1 4.051-.928l.572-.013 2.691-.06.588-.377a10.525 10.525 0 0 1 3.273-1.383l1.257-.134a8.856 8.856 0 0 1 4.036.511l6.472 2.42 6.089 2.277 7.2 2.158 4.858 1.282a8.716 8.716 0 0 1-.736-2.693l-.027-.261a10.335 10.335 0 0 1 .182-3.306l.167-.763c.154-.7.357-1.39.608-2.06l1.55-4.144 2.043-4.04-5.029 3.458-.544.3a14.398 14.398 0 0 1-12 .881l-2.964-1.107-3.278-1.226-2.518-1.317a14.213 14.213 0 0 1-6.665-7.467l-.095-.246a15.136 15.136 0 0 1-.866-3.322l-.28-1.968a32.551 32.551 0 0 1-.323-5.073l.072-4.883a67.58 67.58 0 0 1 3.554-13.787l1.345-3.598 3.165-8.464a1.964 1.964 0 0 1 1.631-1.265Z"
/>
<path
stroke="currentColor"
strokeLinecap="round"
d="m28.15 63.698 6.557 2.452 5.913 2.744 5.914 2.745 7.493 2.802 3.922.932.17.033c1.862.364 3.774.4 5.649.108l5.397-.841a2.198 2.198 0 0 0 1.371-.79v0c.3-.37.47-.828.487-1.303l.013-.357a3.271 3.271 0 0 0-.11-.966l-.647-2.41a12.154 12.154 0 0 1-.403-2.581v0a12.15 12.15 0 0 1 .756-4.828l1.228-3.284 3.62-8.255 5.14-10.89 3.387-6.206 4.382-7.436 1.954-2.84c.108-.156-.06-.355-.232-.276v0a.185.185 0 0 1-.058.016l-1.188.126a7.548 7.548 0 0 1-2.003-.055l-1.52-.245-2.386-.387a.984.984 0 0 0-.261-.007l-.16.017a.825.825 0 0 0-.733.908v0a.825.825 0 0 1-.13.537L74.296 34.51l-4.147 5.132a66.103 66.103 0 0 1-10.82 10.624v0l-2.779 1.712a8.048 8.048 0 0 1-4.51 1.19v0a8.05 8.05 0 0 1-1.434-.182l-1.127-.247a11.587 11.587 0 0 1-3.07-1.148l-.339-.185a9.21 9.21 0 0 1-2.33-1.81v0a9.208 9.208 0 0 1-1.905-3.108l-.455-1.242a15.76 15.76 0 0 1-.732-2.746l-.35-2.03a38.5 38.5 0 0 1-.554-6.87l.004-.494a43.993 43.993 0 0 1 2.784-15.01l1.313-3.512L49.16 3.226l-8.244.876a1.963 1.963 0 0 0-1.13.515v0a1.964 1.964 0 0 0-.501.75l-3.165 8.464-1.345 3.598a67.58 67.58 0 0 0-3.554 13.787v0l-.072 4.883a32.551 32.551 0 0 0 .322 5.074l.28 1.967c.163 1.137.453 2.251.867 3.322l.095.246a14.21 14.21 0 0 0 4.663 6.195v0c.631.479 1.3.904 2.002 1.272l2.518 1.317 3.278 1.226 2.963 1.107a14.4 14.4 0 0 0 4.524.903v0a14.398 14.398 0 0 0 7.477-1.784l.544-.3 5.03-3.458M28.15 63.698l-1.037 2.771a22.716 22.716 0 0 0-1.343 5.878v0a22.716 22.716 0 0 0 .132 5.28l.509 3.57 1.3 12.23 2.826 18.139.463 1.574c.16.547.398 1.068.705 1.548v0a6.012 6.012 0 0 0 2.349 2.123l1.356.686c.81.41 1.666.723 2.55.933l1.042.248c1.031.245 2.08.411 3.137.495l2.041.163 1.58.057-3.685 1.291-2.752.808a13.13 13.13 0 0 1-4.176.524v0a13.212 13.212 0 0 1-2.042-.234l-.44-.087a18.752 18.752 0 0 1-2.995-.845l-1.495-.559a11.916 11.916 0 0 1-1.53-.699l-.681-.372a8.453 8.453 0 0 1-2.803-2.472v0a8.448 8.448 0 0 1-1.374-3.015l-.849-3.621-2.065-17.32L17.4 81.031l-.105-7.968a16.35 16.35 0 0 1 .301-3.345l.164-.838c.063-.326.154-.647.27-.958l.628-1.68c.159-.424.48-.768.891-.955v0l1.287-.587v0a10.336 10.336 0 0 1 4.051-.928l.572-.013 2.691-.06Zm0 0 .587-.376a10.525 10.525 0 0 1 3.273-1.383v0l1.257-.134a8.856 8.856 0 0 1 1.932.007v0c.72.081 1.426.25 2.104.504l6.472 2.42 6.089 2.277 7.2 2.158 4.858 1.282v0a8.716 8.716 0 0 1-.736-2.693l-.027-.261a10.335 10.335 0 0 1 .182-3.306l.167-.763c.154-.7.357-1.39.608-2.06l1.55-4.144 2.043-4.04m0 0 1.52-2.635"
/>
<path
fill="currentColor"
stroke="currentColor"
d="m57 101 7.368-7.273L71 93l-3.684 5.09L57 101Z"
/>
</svg>
);
export default Logo;

@ -1,8 +1,8 @@
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
@ -30,27 +30,27 @@ const buttonVariants = cva(
variant: "default",
size: "default",
},
}
)
},
);
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
asChild?: boolean
asChild?: boolean;
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, size, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
);
},
);
Button.displayName = "Button";
export { Button, buttonVariants }
export { Button, buttonVariants };

@ -0,0 +1,155 @@
"use client";
import * as React from "react";
import { type DialogProps } from "@radix-ui/react-dialog";
import { Command as CommandPrimitive } from "cmdk";
import { Search } from "lucide-react";
import { cn } from "@/lib/utils";
import { Dialog, DialogContent } from "@/components/ui/dialog";
const Command = React.forwardRef<
React.ElementRef<typeof CommandPrimitive>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
>(({ className, ...props }, ref) => (
<CommandPrimitive
ref={ref}
className={cn(
"flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground",
className,
)}
{...props}
/>
));
Command.displayName = CommandPrimitive.displayName;
interface CommandDialogProps extends DialogProps {}
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
return (
<Dialog {...props}>
<DialogContent className="overflow-hidden p-0 shadow-lg">
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
{children}
</Command>
</DialogContent>
</Dialog>
);
};
const CommandInput = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Input>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => (
<div className="flex items-center border-b px-3" cmdk-input-wrapper="">
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
ref={ref}
className={cn(
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
/>
</div>
));
CommandInput.displayName = CommandPrimitive.Input.displayName;
const CommandList = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.List>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, ...props }, ref) => (
<CommandPrimitive.List
ref={ref}
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
{...props}
/>
));
CommandList.displayName = CommandPrimitive.List.displayName;
const CommandEmpty = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Empty>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
>((props, ref) => (
<CommandPrimitive.Empty
ref={ref}
className="py-6 text-center text-sm"
{...props}
/>
));
CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
const CommandGroup = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Group
ref={ref}
className={cn(
"overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
className,
)}
{...props}
/>
));
CommandGroup.displayName = CommandPrimitive.Group.displayName;
const CommandSeparator = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Separator
ref={ref}
className={cn("-mx-1 h-px bg-border", className)}
{...props}
/>
));
CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
const CommandItem = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
/>
));
CommandItem.displayName = CommandPrimitive.Item.displayName;
const CommandShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className,
)}
{...props}
/>
);
};
CommandShortcut.displayName = "CommandShortcut";
export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
};

@ -0,0 +1,122 @@
"use client";
import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import { cn } from "@/lib/utils";
const Dialog = DialogPrimitive.Root;
const DialogTrigger = DialogPrimitive.Trigger;
const DialogPortal = DialogPrimitive.Portal;
const DialogClose = DialogPrimitive.Close;
const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
/>
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
className,
)}
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
const DialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className,
)}
{...props}
/>
);
DialogHeader.displayName = "DialogHeader";
const DialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
DialogFooter.displayName = "DialogFooter";
const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className,
)}
{...props}
/>
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;
const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;
export {
Dialog,
DialogPortal,
DialogOverlay,
DialogClose,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
};

@ -0,0 +1,31 @@
"use client";
import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import { cn } from "@/lib/utils";
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(
(
{ className, orientation = "horizontal", decorative = true, ...props },
ref,
) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className,
)}
{...props}
/>
),
);
Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator };

@ -0,0 +1,11 @@
import { create } from "zustand";
interface ActionCommandStore {
open: boolean;
setOpen: (open: boolean) => void;
}
export const useActionCommand = create<ActionCommandStore>((set) => ({
open: false,
setOpen: (open) => set({ open }),
}));
Loading…
Cancel
Save