mirror of
https://github.com/skidoodle/budgetable.git
synced 2025-02-15 03:39:14 +01:00
refactor: update imports to use 'type' for TypeScript types and enhance tooltip functionality
This commit is contained in:
parent
8e37da9463
commit
3d082d3092
14 changed files with 367 additions and 101 deletions
|
@ -11,10 +11,12 @@
|
|||
"format": "biome format --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@number-flow/react": "^0.4.4",
|
||||
"@radix-ui/react-dialog": "^1.1.4",
|
||||
"@radix-ui/react-progress": "^1.1.1",
|
||||
"@radix-ui/react-slot": "^1.1.1",
|
||||
"@radix-ui/react-toast": "^1.2.4",
|
||||
"@radix-ui/react-tooltip": "^1.1.6",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.469.0",
|
||||
|
|
186
pnpm-lock.yaml
generated
186
pnpm-lock.yaml
generated
|
@ -8,6 +8,9 @@ importers:
|
|||
|
||||
.:
|
||||
dependencies:
|
||||
'@number-flow/react':
|
||||
specifier: ^0.4.4
|
||||
version: 0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-dialog':
|
||||
specifier: ^1.1.4
|
||||
version: 1.1.4(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
|
@ -20,6 +23,9 @@ importers:
|
|||
'@radix-ui/react-toast':
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-tooltip':
|
||||
specifier: ^1.1.6
|
||||
version: 1.1.6(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.1
|
||||
version: 0.7.1
|
||||
|
@ -181,6 +187,21 @@ packages:
|
|||
resolution: {integrity: sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@floating-ui/core@1.6.8':
|
||||
resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==}
|
||||
|
||||
'@floating-ui/dom@1.6.12':
|
||||
resolution: {integrity: sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==}
|
||||
|
||||
'@floating-ui/react-dom@2.1.2':
|
||||
resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
|
||||
'@floating-ui/utils@0.2.8':
|
||||
resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==}
|
||||
|
||||
'@humanfs/core@0.19.1':
|
||||
resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==}
|
||||
engines: {node: '>=18.18.0'}
|
||||
|
@ -398,6 +419,12 @@ packages:
|
|||
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
|
||||
engines: {node: '>=12.4.0'}
|
||||
|
||||
'@number-flow/react@0.4.4':
|
||||
resolution: {integrity: sha512-m2FW55jnWqiJzKNRETgyxgR7a8x0WYIZ1uyiIW8C5g6HyjIynryJJop1mEcmHG6OyNePkcb8OQIcjKlV5TfHAw==}
|
||||
peerDependencies:
|
||||
react: ^18 || ^19
|
||||
react-dom: ^18 || ^19
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
|
@ -405,6 +432,19 @@ packages:
|
|||
'@radix-ui/primitive@1.1.1':
|
||||
resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==}
|
||||
|
||||
'@radix-ui/react-arrow@1.1.1':
|
||||
resolution: {integrity: sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-collection@1.1.1':
|
||||
resolution: {integrity: sha512-LwT3pSho9Dljg+wY2KN2mrrh6y3qELfftINERIzBUO9e0N+t0oMTyn3k9iv+ZqgrwGkRnLpNJrsMv9BZlt2yuA==}
|
||||
peerDependencies:
|
||||
|
@ -493,6 +533,19 @@ packages:
|
|||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-popper@1.2.1':
|
||||
resolution: {integrity: sha512-3kn5Me69L+jv82EKRuQCXdYyf1DqHwD2U/sxoNgBGCB7K9TRc3bQamQ+5EPM9EvyPdli0W41sROd+ZU1dTCztw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-portal@1.1.3':
|
||||
resolution: {integrity: sha512-NciRqhXnGojhT93RPyDaMPfLH3ZSl4jjIFbZQ1b/vxvZEdHsBZ49wP9w8L3HzUQwep01LcWtkUvm0OVB5JAHTw==}
|
||||
peerDependencies:
|
||||
|
@ -567,6 +620,19 @@ packages:
|
|||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-tooltip@1.1.6':
|
||||
resolution: {integrity: sha512-TLB5D8QLExS1uDn7+wH/bjEmRurNMTzNrtq7IjaS4kjion9NtzsTGkvR5+i7yc9q01Pi2KMM2cN3f8UG4IvvXA==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
'@types/react-dom': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-callback-ref@1.1.0':
|
||||
resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==}
|
||||
peerDependencies:
|
||||
|
@ -603,6 +669,24 @@ packages:
|
|||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-rect@1.1.0':
|
||||
resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-use-size@1.1.0':
|
||||
resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==}
|
||||
peerDependencies:
|
||||
'@types/react': '*'
|
||||
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
peerDependenciesMeta:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/react-visually-hidden@1.1.1':
|
||||
resolution: {integrity: sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg==}
|
||||
peerDependencies:
|
||||
|
@ -616,6 +700,9 @@ packages:
|
|||
'@types/react-dom':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/rect@1.1.0':
|
||||
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
|
||||
|
||||
'@rtsao/scc@1.1.0':
|
||||
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
|
||||
|
||||
|
@ -1095,6 +1182,9 @@ packages:
|
|||
jiti:
|
||||
optional: true
|
||||
|
||||
esm-env@1.2.1:
|
||||
resolution: {integrity: sha512-U9JedYYjCnadUlXk7e1Kr+aENQhtUaoaV9+gZm1T8LC/YBAPJx3NSPIAurFOC0U5vrdSevnUJS2/wUVxGwPhng==}
|
||||
|
||||
espree@10.3.0:
|
||||
resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
@ -1526,6 +1616,9 @@ packages:
|
|||
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
number-flow@0.4.2:
|
||||
resolution: {integrity: sha512-YLN73/m8BUU4r/6mq9zqLdpFKt3LSPPRectOECheA9jtNWF4PP8EIz0+Z1giqu/x9nS86KnKwwouLXXiqnjhQQ==}
|
||||
|
||||
object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -2138,6 +2231,23 @@ snapshots:
|
|||
dependencies:
|
||||
levn: 0.4.1
|
||||
|
||||
'@floating-ui/core@1.6.8':
|
||||
dependencies:
|
||||
'@floating-ui/utils': 0.2.8
|
||||
|
||||
'@floating-ui/dom@1.6.12':
|
||||
dependencies:
|
||||
'@floating-ui/core': 1.6.8
|
||||
'@floating-ui/utils': 0.2.8
|
||||
|
||||
'@floating-ui/react-dom@2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.6.12
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
|
||||
'@floating-ui/utils@0.2.8': {}
|
||||
|
||||
'@humanfs/core@0.19.1': {}
|
||||
|
||||
'@humanfs/node@0.16.6':
|
||||
|
@ -2296,11 +2406,27 @@ snapshots:
|
|||
|
||||
'@nolyfill/is-core-module@1.0.39': {}
|
||||
|
||||
'@number-flow/react@0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
esm-env: 1.2.1
|
||||
number-flow: 0.4.2
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
'@radix-ui/primitive@1.1.1': {}
|
||||
|
||||
'@radix-ui/react-arrow@1.1.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.2
|
||||
'@types/react-dom': 19.0.2(@types/react@19.0.2)
|
||||
|
||||
'@radix-ui/react-collection@1.1.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.2)(react@19.0.0)
|
||||
|
@ -2384,6 +2510,24 @@ snapshots:
|
|||
optionalDependencies:
|
||||
'@types/react': 19.0.2
|
||||
|
||||
'@radix-ui/react-popper@1.2.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@floating-ui/react-dom': 2.1.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-arrow': 1.1.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-context': 1.1.1(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-use-rect': 1.1.0(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-use-size': 1.1.0(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/rect': 1.1.0
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.2
|
||||
'@types/react-dom': 19.0.2(@types/react@19.0.2)
|
||||
|
||||
'@radix-ui/react-portal@1.1.3(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
|
@ -2450,6 +2594,26 @@ snapshots:
|
|||
'@types/react': 19.0.2
|
||||
'@types/react-dom': 19.0.2(@types/react@19.0.2)
|
||||
|
||||
'@radix-ui/react-tooltip@1.1.6(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.1
|
||||
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-context': 1.1.1(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-dismissable-layer': 1.1.3(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-id': 1.1.0(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-popper': 1.2.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-portal': 1.1.3(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-presence': 1.1.2(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@radix-ui/react-slot': 1.1.1(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-use-controllable-state': 1.1.0(@types/react@19.0.2)(react@19.0.0)
|
||||
'@radix-ui/react-visually-hidden': 1.1.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.2
|
||||
'@types/react-dom': 19.0.2(@types/react@19.0.2)
|
||||
|
||||
'@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.0.2)(react@19.0.0)':
|
||||
dependencies:
|
||||
react: 19.0.0
|
||||
|
@ -2476,6 +2640,20 @@ snapshots:
|
|||
optionalDependencies:
|
||||
'@types/react': 19.0.2
|
||||
|
||||
'@radix-ui/react-use-rect@1.1.0(@types/react@19.0.2)(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/rect': 1.1.0
|
||||
react: 19.0.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.2
|
||||
|
||||
'@radix-ui/react-use-size@1.1.0(@types/react@19.0.2)(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.0.2)(react@19.0.0)
|
||||
react: 19.0.0
|
||||
optionalDependencies:
|
||||
'@types/react': 19.0.2
|
||||
|
||||
'@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
|
@ -2485,6 +2663,8 @@ snapshots:
|
|||
'@types/react': 19.0.2
|
||||
'@types/react-dom': 19.0.2(@types/react@19.0.2)
|
||||
|
||||
'@radix-ui/rect@1.1.0': {}
|
||||
|
||||
'@rtsao/scc@1.1.0': {}
|
||||
|
||||
'@rushstack/eslint-patch@1.10.4': {}
|
||||
|
@ -3151,6 +3331,8 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
esm-env@1.2.1: {}
|
||||
|
||||
espree@10.3.0:
|
||||
dependencies:
|
||||
acorn: 8.14.0
|
||||
|
@ -3587,6 +3769,10 @@ snapshots:
|
|||
|
||||
normalize-path@3.0.0: {}
|
||||
|
||||
number-flow@0.4.2:
|
||||
dependencies:
|
||||
esm-env: 1.2.1
|
||||
|
||||
object-assign@4.1.1: {}
|
||||
|
||||
object-hash@3.0.0: {}
|
||||
|
|
|
@ -5,7 +5,7 @@ import TableWrapper from "@/components/table-wrapper";
|
|||
import Header from "@/components/header";
|
||||
import TotalDisplay from "@/components/total-display";
|
||||
import { toast } from "sonner";
|
||||
import { Budgetable, areRowsEqual } from "@/lib/utils";
|
||||
import { type Budgetable, areRowsEqual } from "@/lib/utils";
|
||||
|
||||
export default function App() {
|
||||
const [data, setData] = useState<Budgetable[]>(() => []);
|
||||
|
@ -132,6 +132,7 @@ export default function App() {
|
|||
<main className="container mx-auto p-4 max-w-5xl">
|
||||
{loading}
|
||||
<Header isEditing={isEditing} setIsEditing={setIsEditing} />
|
||||
<TotalDisplay total={total} />
|
||||
<TableWrapper
|
||||
data={data}
|
||||
isEditing={isEditing}
|
||||
|
@ -144,7 +145,6 @@ export default function App() {
|
|||
handleDeleteRow={handleDeleteRow}
|
||||
toggleStatus={toggleStatus}
|
||||
/>
|
||||
<TotalDisplay total={total} />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -20,14 +20,17 @@ export async function GET(
|
|||
|
||||
const id = (await context.params)?.id;
|
||||
if (!id) {
|
||||
return Response.json({
|
||||
error: {
|
||||
message: "Missing ID in request",
|
||||
return Response.json(
|
||||
{
|
||||
error: {
|
||||
message: "Missing ID in request",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
{
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const record = await pb.collection("budgetable").getOne(id);
|
||||
|
@ -37,14 +40,17 @@ export async function GET(
|
|||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
return Response.json({
|
||||
error: {
|
||||
message: "Failed to fetch data",
|
||||
return Response.json(
|
||||
{
|
||||
error: {
|
||||
message: "Failed to fetch data",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
})
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,33 +63,42 @@ export async function DELETE(
|
|||
|
||||
const id = (await context.params)?.id;
|
||||
if (!id) {
|
||||
return Response.json({
|
||||
error: {
|
||||
message: "Missing ID in request",
|
||||
return Response.json(
|
||||
{
|
||||
error: {
|
||||
message: "Missing ID in request",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
{
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await pb.collection("budgetable").delete(id);
|
||||
return Response.json({
|
||||
success: true,
|
||||
}, {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
return Response.json(
|
||||
{
|
||||
success: true,
|
||||
},
|
||||
{
|
||||
status: 200,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error deleting data:", error);
|
||||
return Response.json({
|
||||
error: {
|
||||
message: "Failed to delete data",
|
||||
return Response.json(
|
||||
{
|
||||
error: {
|
||||
message: "Failed to delete data",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,26 +111,32 @@ export async function PUT(
|
|||
|
||||
const id = (await context.params)?.id;
|
||||
if (!id) {
|
||||
return Response.json({
|
||||
error: {
|
||||
message: "Missing ID in request",
|
||||
return Response.json(
|
||||
{
|
||||
error: {
|
||||
message: "Missing ID in request",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
{
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const body = await req.json();
|
||||
if (!body.title || typeof body.price !== "number") {
|
||||
return Response.json({
|
||||
error: {
|
||||
message: "Invalid data provided",
|
||||
return Response.json(
|
||||
{
|
||||
error: {
|
||||
message: "Invalid data provided",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
{
|
||||
status: 400,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const updatedRecord = await pb.collection("budgetable").update(id, body);
|
||||
|
@ -125,13 +146,16 @@ export async function PUT(
|
|||
});
|
||||
} catch (error) {
|
||||
console.error("Error updating data:", error);
|
||||
return Response.json({
|
||||
error: {
|
||||
message: "Failed to update data",
|
||||
return Response.json(
|
||||
{
|
||||
error: {
|
||||
message: "Failed to update data",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,14 +21,17 @@ export async function GET() {
|
|||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
return Response.json({
|
||||
error: {
|
||||
message: "Failed to fetch data",
|
||||
return Response.json(
|
||||
{
|
||||
error: {
|
||||
message: "Failed to fetch data",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,13 +46,16 @@ export async function POST(req: Request) {
|
|||
});
|
||||
} catch (error) {
|
||||
console.error("Error adding data:", error);
|
||||
return Response.json({
|
||||
error: {
|
||||
message: "Failed to add data",
|
||||
return Response.json(
|
||||
{
|
||||
error: {
|
||||
message: "Failed to add data",
|
||||
},
|
||||
},
|
||||
}, {
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
{
|
||||
status: 500,
|
||||
headers: { "Content-Type": "application/json" },
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,9 @@ const DeleteDialog = ({ onConfirm }: DeleteDialogProps) => (
|
|||
<DialogTitle>Delete Row</DialogTitle>
|
||||
<DialogHeader>Are you sure you want to delete this row?</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button onClick={onConfirm}>Yes, delete</Button>
|
||||
<Button onClick={onConfirm} variant="destructive">
|
||||
Yes, delete
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
|
|
@ -13,7 +13,7 @@ const Header = ({ isEditing, setIsEditing }: AppHeaderProps) => (
|
|||
href="/"
|
||||
className="text-blue-500 hover:text-blue-600 transition-colors"
|
||||
onClick={() => setIsEditing(false)}
|
||||
>
|
||||
>
|
||||
Budgetable
|
||||
</Link>
|
||||
</h1>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { TableRow, TableCell } from "@/components/ui/table";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Budgetable } from '@/lib/utils';
|
||||
import type { Budgetable } from "@/lib/utils";
|
||||
|
||||
interface TNewRowProps {
|
||||
newRow: Budgetable;
|
||||
|
|
|
@ -3,8 +3,14 @@ import { TableRow, TableCell } from "@/components/ui/table";
|
|||
import Link from "next/link";
|
||||
import StatusBadge from "@/components/status-badge";
|
||||
import DeleteDialog from "@/components/delete-dialog";
|
||||
import { useState } from 'react';
|
||||
import { Budgetable } from '@/lib/utils';
|
||||
import { useState } from "react";
|
||||
import type { Budgetable } from "@/lib/utils";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
|
||||
interface TRowProps {
|
||||
row: Budgetable;
|
||||
|
@ -31,7 +37,7 @@ const TRow = ({
|
|||
const [originalRow, setOriginalRow] = useState<Budgetable>(row);
|
||||
|
||||
const handleInputFocus = () => {
|
||||
setOriginalRow({...row});
|
||||
setOriginalRow({ ...row });
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -48,7 +54,9 @@ const TRow = ({
|
|||
onChange={(e) =>
|
||||
setData((prev) =>
|
||||
prev.map((item) =>
|
||||
item.id === row.id ? { ...item, title: e.target.value } : item,
|
||||
item.id === row.id
|
||||
? { ...item, title: e.target.value }
|
||||
: item,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -94,14 +102,18 @@ const TRow = ({
|
|||
onBlur={() => handleSave(row, originalRow)}
|
||||
/>
|
||||
) : row.link ? (
|
||||
<Link
|
||||
href={row.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-500 underline"
|
||||
>
|
||||
Visit
|
||||
</Link>
|
||||
<TooltipProvider delayDuration={150}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger className="text-blue-500 underline">
|
||||
<Link href={row.link} target="_blank" rel="noopener noreferrer">
|
||||
Visit
|
||||
</Link>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="text-white bg-black">
|
||||
{row.link.replace(/^https?:\/\//, "")}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
) : (
|
||||
<span className="text-gray-400 italic">No link</span>
|
||||
)}
|
||||
|
@ -125,7 +137,10 @@ const TRow = ({
|
|||
)}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<StatusBadge status={row.status} toggleStatus={() => toggleStatus(row)} />
|
||||
<StatusBadge
|
||||
status={row.status}
|
||||
toggleStatus={() => toggleStatus(row)}
|
||||
/>
|
||||
</TableCell>
|
||||
{isEditing && (
|
||||
<TableCell>
|
||||
|
|
|
@ -7,7 +7,7 @@ import {
|
|||
} from "@/components/ui/table";
|
||||
import TRow from "@/components/table-row";
|
||||
import TNewRow from "@/components/table-new-row";
|
||||
import { Budgetable } from '@/lib/utils';
|
||||
import type { Budgetable } from "@/lib/utils";
|
||||
|
||||
interface TWrapperProps {
|
||||
data: Budgetable[];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { ComponentProps } from "react";
|
||||
import type { ComponentProps } from "react";
|
||||
import { ThemeProvider as NextThemesProvider } from "next-themes";
|
||||
|
||||
export function ThemeProvider({
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import NumberFlow from "@number-flow/react";
|
||||
|
||||
interface TotalDisplayProps {
|
||||
total: number;
|
||||
}
|
||||
|
||||
const TotalDisplay = ({ total }: TotalDisplayProps) => (
|
||||
<div className="mt-4 text-right font-bold text-lg">
|
||||
Total: {total.toLocaleString()}
|
||||
<p className="text-xs ml-1">
|
||||
({Math.round(total * 1.27).toLocaleString()})
|
||||
</p>
|
||||
<div className="mx-2 text-left font-bold text-lg">
|
||||
Total: <NumberFlow value={total} />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
32
src/components/ui/tooltip.tsx
Normal file
32
src/components/ui/tooltip.tsx
Normal file
|
@ -0,0 +1,32 @@
|
|||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
||||
|
||||
import { cn } from "@/lib/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.Portal>
|
||||
<TooltipPrimitive.Content
|
||||
ref={ref}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground 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}
|
||||
/>
|
||||
</TooltipPrimitive.Portal>
|
||||
));
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
|
@ -16,14 +16,14 @@ export interface Budgetable {
|
|||
|
||||
export const areRowsEqual = (row1: Budgetable, row2: Budgetable): boolean => {
|
||||
const normalize = (value: string | number | undefined) =>
|
||||
String(value ?? "").trim();
|
||||
String(value ?? "").trim();
|
||||
|
||||
const areEqual = (field: keyof Budgetable) =>
|
||||
field === "price"
|
||||
? Number(row1[field]) === Number(row2[field])
|
||||
: normalize(row1[field]) === normalize(row2[field]);
|
||||
field === "price"
|
||||
? Number(row1[field]) === Number(row2[field])
|
||||
: normalize(row1[field]) === normalize(row2[field]);
|
||||
|
||||
return ["title", "price", "link", "note", "status"].every(field =>
|
||||
areEqual(field as keyof Budgetable)
|
||||
return ["title", "price", "link", "note", "status"].every((field) =>
|
||||
areEqual(field as keyof Budgetable),
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue