├── .eslintignore
├── .eslintrc.cjs
├── .gitattributes
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── custom.md
│ └── feature_request.md
├── .gitignore
├── .npmrc
├── .prettierignore
├── .prettierrc
├── LICENSE
├── README.md
├── components.json
├── package-lock.json
├── package.json
├── postcss.config.cjs
├── src
├── app.d.ts
├── app.html
├── app.pcss
├── lib
│ ├── assets
│ │ ├── ss.jpg
│ │ ├── tzezar-logo-black.png
│ │ └── tzezar-logo-white.png
│ ├── components
│ │ ├── table
│ │ │ ├── Table.svelte
│ │ │ ├── cells
│ │ │ │ ├── HeaderSelectCheckbox.svelte
│ │ │ │ ├── InlineRowEditingToggleCell.svelte
│ │ │ │ ├── LinkDetailsCell.svelte
│ │ │ │ ├── NumberInputEditableCell.svelte
│ │ │ │ ├── RowExpandToggle.svelte
│ │ │ │ ├── RowSelectCheckbox.svelte
│ │ │ │ └── TextInputEditableCell.svelte
│ │ │ ├── components
│ │ │ │ ├── CellEditableTemplate.svelte
│ │ │ │ ├── CellTemplate.svelte
│ │ │ │ ├── ColumnOrderDraggableChanger.svelte
│ │ │ │ ├── ColumnVisibilitySelect.svelte
│ │ │ │ ├── FullscreenModeToggle.svelte
│ │ │ │ ├── Pagination.svelte
│ │ │ │ └── SortingToggle.svelte
│ │ │ ├── index.ts
│ │ │ ├── stores
│ │ │ │ ├── columnSizesStore.ts
│ │ │ │ ├── expandedRowsStore.ts
│ │ │ │ ├── fullscreenModeStore.ts
│ │ │ │ ├── hiddenColumnsStore.ts
│ │ │ │ ├── inlineEditingStore.ts
│ │ │ │ ├── selectedRowsStore.ts
│ │ │ │ ├── sortingStore.ts
│ │ │ │ └── visibleRowsStore.ts
│ │ │ ├── table
│ │ │ │ ├── index.ts
│ │ │ │ ├── table-body.svelte
│ │ │ │ ├── table-caption.svelte
│ │ │ │ ├── table-cell.svelte
│ │ │ │ ├── table-footer.svelte
│ │ │ │ ├── table-head.svelte
│ │ │ │ ├── table-header.svelte
│ │ │ │ ├── table-row.svelte
│ │ │ │ └── table.svelte
│ │ │ └── utils
│ │ │ │ ├── clientMode.ts
│ │ │ │ ├── getNestedValue.ts
│ │ │ │ └── throttle.ts
│ │ └── ui
│ │ │ ├── button
│ │ │ ├── button.svelte
│ │ │ └── index.ts
│ │ │ ├── checkbox
│ │ │ ├── checkbox.svelte
│ │ │ └── index.ts
│ │ │ ├── collapsible
│ │ │ ├── collapsible-content.svelte
│ │ │ └── index.ts
│ │ │ ├── dropdown-menu
│ │ │ ├── dropdown-menu-checkbox-item.svelte
│ │ │ ├── dropdown-menu-content.svelte
│ │ │ ├── dropdown-menu-item.svelte
│ │ │ ├── dropdown-menu-label.svelte
│ │ │ ├── dropdown-menu-radio-group.svelte
│ │ │ ├── dropdown-menu-radio-item.svelte
│ │ │ ├── dropdown-menu-separator.svelte
│ │ │ ├── dropdown-menu-shortcut.svelte
│ │ │ ├── dropdown-menu-sub-content.svelte
│ │ │ ├── dropdown-menu-sub-trigger.svelte
│ │ │ └── index.ts
│ │ │ ├── input
│ │ │ ├── index.ts
│ │ │ └── input.svelte
│ │ │ ├── pagination
│ │ │ ├── index.ts
│ │ │ ├── pagination-content.svelte
│ │ │ ├── pagination-ellipsis.svelte
│ │ │ ├── pagination-item.svelte
│ │ │ ├── pagination-link.svelte
│ │ │ ├── pagination-next-button.svelte
│ │ │ ├── pagination-prev-button.svelte
│ │ │ └── pagination.svelte
│ │ │ ├── popover
│ │ │ ├── index.ts
│ │ │ └── popover-content.svelte
│ │ │ ├── select
│ │ │ ├── index.ts
│ │ │ ├── select-content.svelte
│ │ │ ├── select-item.svelte
│ │ │ ├── select-label.svelte
│ │ │ ├── select-separator.svelte
│ │ │ └── select-trigger.svelte
│ │ │ ├── separator
│ │ │ ├── index.ts
│ │ │ └── separator.svelte
│ │ │ ├── sheet
│ │ │ ├── index.ts
│ │ │ ├── sheet-content.svelte
│ │ │ ├── sheet-description.svelte
│ │ │ ├── sheet-footer.svelte
│ │ │ ├── sheet-header.svelte
│ │ │ ├── sheet-overlay.svelte
│ │ │ ├── sheet-portal.svelte
│ │ │ └── sheet-title.svelte
│ │ │ ├── sonner
│ │ │ ├── index.ts
│ │ │ └── sonner.svelte
│ │ │ └── tabs
│ │ │ ├── index.ts
│ │ │ ├── tabs-content.svelte
│ │ │ ├── tabs-list.svelte
│ │ │ └── tabs-trigger.svelte
│ ├── index.ts
│ └── utils.ts
└── routes
│ ├── (examples)
│ ├── +layout.svelte
│ ├── basic
│ │ └── +page.svelte
│ ├── client-mode
│ │ ├── +page.svelte
│ │ └── data.ts
│ ├── column-filtering
│ │ ├── +page.svelte
│ │ └── _components
│ │ │ ├── ExpandableRow.svelte
│ │ │ ├── RatingCell.svelte
│ │ │ └── TitleHeaderCell.svelte
│ ├── column-hiding
│ │ └── +page.svelte
│ ├── column-ordering
│ │ └── +page.svelte
│ ├── column-resizing
│ │ └── +page.svelte
│ ├── conditional-styling
│ │ └── +page.svelte
│ ├── content-align
│ │ └── +page.svelte
│ ├── custom-cells
│ │ ├── +page.svelte
│ │ ├── BrandCell.svelte
│ │ ├── DescriptionCell.svelte
│ │ ├── IdCellHeader.svelte
│ │ └── RatingCell.svelte
│ ├── pagination
│ │ └── +page.svelte
│ ├── row-expanding
│ │ ├── +page.svelte
│ │ └── ExpandableRow.svelte
│ ├── row-inline-editing-save-on-click
│ │ ├── +page.svelte
│ │ └── _components
│ │ │ ├── InlineEditing.svelte
│ │ │ ├── SelectBrand.svelte
│ │ │ └── ValueCellEdit.svelte
│ ├── row-inline-editing
│ │ └── +page.svelte
│ ├── row-modal-editing
│ │ ├── +page.svelte
│ │ └── EditModal.svelte
│ ├── row-selection
│ │ └── +page.svelte
│ └── sorting
│ │ └── +page.svelte
│ ├── +layout.svelte
│ ├── +page.svelte
│ ├── _components
│ ├── RatingCell.svelte
│ ├── Sidebar.svelte
│ ├── TitleHeaderCell.svelte
│ └── custom-row-expand
│ │ └── CustomRowExpandToggle.svelte
│ ├── installation
│ └── +page.svelte
│ └── planned
│ └── +page.svelte
├── static
└── favicon.png
├── svelte.config.js
├── tailwind.config.js
├── tsconfig.json
└── vite.config.ts
/.eslintignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 |
10 | # Ignore files for PNPM, NPM and YARN
11 | pnpm-lock.yaml
12 | package-lock.json
13 | yarn.lock
14 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /** @type { import("eslint").Linter.Config } */
2 | module.exports = {
3 | root: true,
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:@typescript-eslint/recommended',
7 | 'plugin:svelte/recommended',
8 | 'prettier'
9 | ],
10 | parser: '@typescript-eslint/parser',
11 | plugins: ['@typescript-eslint'],
12 | parserOptions: {
13 | sourceType: 'module',
14 | ecmaVersion: 2020,
15 | extraFileExtensions: ['.svelte']
16 | },
17 | env: {
18 | browser: true,
19 | es2017: true,
20 | node: true
21 | },
22 | overrides: [
23 | {
24 | files: ['*.svelte'],
25 | parser: 'svelte-eslint-parser',
26 | parserOptions: {
27 | parser: '@typescript-eslint/parser'
28 | }
29 | }
30 | ]
31 | };
32 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Custom issue template
3 | about: Describe this issue template's purpose here.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .svelte-kit
2 | .dist
3 |
4 | # Logs
5 | logs
6 | *.log
7 | npm-debug.log*
8 | yarn-debug.log*
9 | yarn-error.log*
10 | lerna-debug.log*
11 | .pnpm-debug.log*
12 |
13 | # Diagnostic reports (https://nodejs.org/api/report.html)
14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
15 |
16 | # Runtime data
17 | pids
18 | *.pid
19 | *.seed
20 | *.pid.lock
21 |
22 | # Directory for instrumented libs generated by jscoverage/JSCover
23 | lib-cov
24 |
25 | # Coverage directory used by tools like istanbul
26 | coverage
27 | *.lcov
28 |
29 | # nyc test coverage
30 | .nyc_output
31 |
32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
33 | .grunt
34 |
35 | # Bower dependency directory (https://bower.io/)
36 | bower_components
37 |
38 | # node-waf configuration
39 | .lock-wscript
40 |
41 | # Compiled binary addons (https://nodejs.org/api/addons.html)
42 | build/Release
43 |
44 | # Dependency directories
45 | node_modules/
46 | jspm_packages/
47 |
48 | # Snowpack dependency directory (https://snowpack.dev/)
49 | web_modules/
50 |
51 | # TypeScript cache
52 | *.tsbuildinfo
53 |
54 | # Optional npm cache directory
55 | .npm
56 |
57 | # Optional eslint cache
58 | .eslintcache
59 |
60 | # Optional stylelint cache
61 | .stylelintcache
62 |
63 | # Microbundle cache
64 | .rpt2_cache/
65 | .rts2_cache_cjs/
66 | .rts2_cache_es/
67 | .rts2_cache_umd/
68 |
69 | # Optional REPL history
70 | .node_repl_history
71 |
72 | # Output of 'npm pack'
73 | *.tgz
74 |
75 | # Yarn Integrity file
76 | .yarn-integrity
77 |
78 | # dotenv environment variable files
79 | .env
80 | .env.development.local
81 | .env.test.local
82 | .env.production.local
83 | .env.local
84 |
85 | # parcel-bundler cache (https://parceljs.org/)
86 | .cache
87 | .parcel-cache
88 |
89 | # Next.js build output
90 | .next
91 | out
92 |
93 | # Nuxt.js build / generate output
94 | .nuxt
95 | dist
96 |
97 | # Gatsby files
98 | .cache/
99 | # Comment in the public line in if your project uses Gatsby and not Next.js
100 | # https://nextjs.org/blog/next-9-1#public-directory-support
101 | # public
102 |
103 | # vuepress build output
104 | .vuepress/dist
105 |
106 | # vuepress v2.x temp and cache directory
107 | .temp
108 | .cache
109 |
110 | # Serverless directories
111 | .serverless/
112 |
113 | # FuseBox cache
114 | .fusebox/
115 |
116 | # DynamoDB Local files
117 | .dynamodb/
118 |
119 | # TernJS port file
120 | .tern-port
121 |
122 | # Stores VSCode versions used for testing VSCode extensions
123 | .vscode-test
124 |
125 | # yarn v2
126 | .yarn/cache
127 | .yarn/unplugged
128 | .yarn/build-state.yml
129 | .yarn/install-state.gz
130 | .pnp.*
131 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # Ignore files for PNPM, NPM and YARN
2 | pnpm-lock.yaml
3 | package-lock.json
4 | yarn.lock
5 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": true,
3 | "singleQuote": true,
4 | "trailingComma": "none",
5 | "printWidth": 100,
6 | "plugins": [
7 | "prettier-plugin-svelte",
8 | "prettier-plugin-tailwindcss"
9 | ],
10 | "overrides": [
11 | {
12 | "files": "*.svelte",
13 | "options": {
14 | "parser": "svelte"
15 | }
16 | }
17 | ]
18 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Sebastian Drozd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TZEZAR's TABLE
2 |
3 | > **Archived and No Longer Maintained**
4 |
5 | This project has been archived and is no longer actively maintained. It is provided as-is, and no further updates, bug fixes, or new features will be added.
6 |
7 | ## Status
8 |
9 | - **Archived**: The repository is in an archived state and is no longer actively developed or supported.
10 | - **No active support**: No further issues will be addressed, and pull requests will not be merged.
11 |
12 | ## Usage
13 |
14 | You are welcome to fork or clone the repository if you wish to continue using or contributing to it. However, please be aware that there will be no official updates or support from the maintainers.
15 |
16 | ## Alternatives
17 |
18 | If you're looking for actively maintained alternatives, you might consider [Tzezar's Datagrid](https://datagrid.tzezar.pl/) built with svelte 5.
19 |
20 | \
21 | \
22 | \
23 | \
24 | \
25 | \
26 | \
27 | \
28 | \
29 | \
30 | \
31 | \
32 | \
33 | \
34 | \
35 | \
36 | \
37 | \
38 | ...\
39 | ---
40 |
41 |
42 |
43 | Table component built in svelte based on shadcn-svelte components.
44 |
45 | [documentation, examples and live demo](https://tzezar-table.vercel.app/)
46 |
47 | ## What is this?
48 | Table component for easy display of tables based on remote data (planned support for client-side functionality).
49 | Based on the excellent [shadcn-svelte](https://github.com/huntabyte/shadcn-svelte) component library.
50 |
51 | ## For whom?
52 | You copy the [component](https://github.com/tzezar/table/tree/main/src/lib/components/table) directly into your project and can edit it as you wish. It is something between a ready-made data-grid and a headless table.
53 |
54 | ## Supported Functions
55 | - Virtualization
56 | - Column hiding
57 | - Column reordering
58 | - Column resizing
59 | - Conditional styling
60 | - Content alignment
61 | - Custom content
62 | - Pagination
63 | - Inline row editing
64 | - Modal row editing
65 | - Row editing
66 | - Row expanding
67 | - Single column sorting
68 |
69 | ## Shortcuts
70 | [live examples](https://tzezar-table.vercel.app/)
71 | [installation](https://tzezar-table.vercel.app/installation)
72 | [component code](https://github.com/tzezar/table/tree/main/src/lib/components/table)
73 | [examples code](https://github.com/tzezar/table/tree/main/src/routes/(examples))
74 |
75 | ## MIT License
76 |
77 | Copyright (c) 2024 Sebastian Drozd
78 |
79 | Permission is hereby granted, free of charge, to any person obtaining a copy
80 | of this software and associated documentation files (the "Software"), to deal
81 | in the Software without restriction, including without limitation the rights
82 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
83 | copies of the Software, and to permit persons to whom the Software is
84 | furnished to do so, subject to the following conditions:
85 |
86 | The above copyright notice and this permission notice shall be included in all
87 | copies or substantial portions of the Software.
88 |
89 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
91 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
92 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
94 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
95 | SOFTWARE.
96 |
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://shadcn-svelte.com/schema.json",
3 | "style": "default",
4 | "tailwind": {
5 | "config": "tailwind.config.js",
6 | "css": "src/app.pcss",
7 | "baseColor": "stone"
8 | },
9 | "aliases": {
10 | "components": "$lib/components",
11 | "utils": "$lib/utils"
12 | },
13 | "typescript": true
14 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "530rge-table",
3 | "version": "1.0.0",
4 | "scripts": {
5 | "dev": "vite dev",
6 | "build": "vite build && npm run package",
7 | "preview": "vite preview",
8 | "package": "svelte-kit sync && svelte-package && publint",
9 | "prepublishOnly": "npm run package",
10 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
11 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
12 | "lint": "prettier --check . && eslint .",
13 | "format": "prettier --write ."
14 | },
15 | "exports": {
16 | ".": {
17 | "types": "./dist/index.d.ts",
18 | "svelte": "./dist/index.js"
19 | }
20 | },
21 | "files": [
22 | "dist",
23 | "!dist/**/*.test.*",
24 | "!dist/**/*.spec.*"
25 | ],
26 | "peerDependencies": {
27 | "svelte": "^4.0.0"
28 | },
29 | "devDependencies": {
30 | "@sveltejs/adapter-auto": "^3.0.0",
31 | "@sveltejs/adapter-vercel": "^5.1.1",
32 | "@sveltejs/kit": "^2.0.0",
33 | "@sveltejs/package": "^2.0.0",
34 | "@sveltejs/vite-plugin-svelte": "^3.0.0",
35 | "@tailwindcss/typography": "^0.5.10",
36 | "@types/eslint": "^8.56.0",
37 | "@typescript-eslint/eslint-plugin": "^7.0.0",
38 | "@typescript-eslint/parser": "^7.0.0",
39 | "autoprefixer": "^10.4.16",
40 | "eslint": "^8.56.0",
41 | "eslint-config-prettier": "^9.1.0",
42 | "eslint-plugin-svelte": "^2.35.1",
43 | "postcss": "^8.4.32",
44 | "postcss-load-config": "^5.0.2",
45 | "prettier": "^3.1.1",
46 | "prettier-plugin-svelte": "^3.1.2",
47 | "prettier-plugin-tailwindcss": "^0.5.9",
48 | "publint": "^0.1.9",
49 | "svelte": "^4.2.7",
50 | "svelte-check": "^3.6.0",
51 | "tailwindcss": "^3.3.6",
52 | "tslib": "^2.4.1",
53 | "typescript": "^5.0.0",
54 | "vite": "^5.0.11"
55 | },
56 | "svelte": "./dist/index.js",
57 | "types": "./dist/index.d.ts",
58 | "type": "module",
59 | "dependencies": {
60 | "@tanstack/svelte-query": "^5.28.4",
61 | "@tanstack/svelte-query-devtools": "^5.28.4",
62 | "@tanstack/svelte-virtual": "^3.2.0",
63 | "bits-ui": "^0.19.7",
64 | "clsx": "^2.1.0",
65 | "lucide-svelte": "^0.358.0",
66 | "mode-watcher": "^0.3.0",
67 | "svelte-dnd-action": "^0.9.40",
68 | "svelte-legos": "^0.2.2",
69 | "svelte-sonner": "^0.3.19",
70 | "tailwind-merge": "^2.2.2",
71 | "tailwind-variants": "^0.2.1"
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | const tailwindcss = require("tailwindcss");
2 | const autoprefixer = require("autoprefixer");
3 |
4 | const config = {
5 | plugins: [
6 | //Some plugins, like tailwindcss/nesting, need to run before Tailwind,
7 | tailwindcss(),
8 | //But others, like autoprefixer, need to run after,
9 | autoprefixer
10 | ]
11 | };
12 |
13 | module.exports = config;
--------------------------------------------------------------------------------
/src/app.d.ts:
--------------------------------------------------------------------------------
1 | // See https://kit.svelte.dev/docs/types#app
2 | // for information about these interfaces
3 | declare global {
4 | namespace App {
5 | // interface Error {}
6 | // interface Locals {}
7 | // interface PageData {}
8 | // interface PageState {}
9 | // interface Platform {}
10 | }
11 | }
12 |
13 | export {};
14 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %sveltekit.head%
8 |
9 |
10 | %sveltekit.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/app.pcss:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 |
6 |
7 |
8 | @layer base {
9 | :root {
10 | --background: 0 0% 100%;
11 | --foreground: 20 14.3% 4.1%;
12 |
13 | --muted: 60 4.8% 95.9%;
14 | --muted-foreground: 25 5.3% 44.7%;
15 |
16 | --popover: 0 0% 100%;
17 | --popover-foreground: 20 14.3% 4.1%;
18 |
19 | --card: 0 0% 100%;
20 | --card-foreground: 20 14.3% 4.1%;
21 |
22 | --border: 20 5.9% 90%;
23 | --input: 20 5.9% 90%;
24 |
25 | --primary: 24 9.8% 10%;
26 | --primary-foreground: 60 9.1% 97.8%;
27 |
28 | --secondary: 60 4.8% 95.9%;
29 | --secondary-foreground: 24 9.8% 10%;
30 |
31 | --accent: 60 4.8% 95.9%;
32 | --accent-foreground: 24 9.8% 10%;
33 |
34 | --destructive: 0 72.2% 50.6%;
35 | --destructive-foreground: 60 9.1% 97.8%;
36 |
37 | --ring: 20 14.3% 4.1%;
38 |
39 | --radius: 0.5rem;
40 | }
41 |
42 | .dark {
43 | --background: 20 14.3% 4.1%;
44 | --foreground: 60 9.1% 97.8%;
45 |
46 | --muted: 12 6.5% 15.1%;
47 | --muted-foreground: 24 5.4% 63.9%;
48 |
49 | --popover: 20 14.3% 4.1%;
50 | --popover-foreground: 60 9.1% 97.8%;
51 |
52 | --card: 20 14.3% 4.1%;
53 | --card-foreground: 60 9.1% 97.8%;
54 |
55 | --border: 12 6.5% 15.1%;
56 | --input: 12 6.5% 15.1%;
57 |
58 | --primary: 60 9.1% 97.8%;
59 | --primary-foreground: 24 9.8% 10%;
60 |
61 | --secondary: 12 6.5% 15.1%;
62 | --secondary-foreground: 60 9.1% 97.8%;
63 |
64 | --accent: 12 6.5% 15.1%;
65 | --accent-foreground: 60 9.1% 97.8%;
66 |
67 | --destructive: 0 62.8% 30.6%;
68 | --destructive-foreground: 60 9.1% 97.8%;
69 |
70 | --ring: 24 5.7% 82.9%;
71 | }
72 | }
73 |
74 |
75 |
76 |
77 | @layer base {
78 | * {
79 | @apply border-border;
80 | }
81 | body {
82 | @apply bg-background text-foreground;
83 | }
84 | }
85 |
86 |
87 |
88 |
89 | /* width */
90 | ::-webkit-scrollbar {
91 | width: 10px;
92 | height: 10px;
93 | }
94 |
95 | /* Track */
96 | ::-webkit-scrollbar-track {
97 | background: #f1f1f1;
98 | }
99 |
100 | /* Handle */
101 | ::-webkit-scrollbar-thumb {
102 | background: #888;
103 | }
104 |
105 | /* Handle on hover */
106 | ::-webkit-scrollbar-thumb:hover {
107 | background: #555;
108 | }
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/src/lib/assets/ss.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzezar/table/67a908b769c7c7cf05f1adf4b102e0b69d9ce0e7/src/lib/assets/ss.jpg
--------------------------------------------------------------------------------
/src/lib/assets/tzezar-logo-black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzezar/table/67a908b769c7c7cf05f1adf4b102e0b69d9ce0e7/src/lib/assets/tzezar-logo-black.png
--------------------------------------------------------------------------------
/src/lib/assets/tzezar-logo-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzezar/table/67a908b769c7c7cf05f1adf4b102e0b69d9ce0e7/src/lib/assets/tzezar-logo-white.png
--------------------------------------------------------------------------------
/src/lib/components/table/Table.svelte:
--------------------------------------------------------------------------------
1 |
190 |
191 |
192 |
193 |
194 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 | {#if enableColumnReordering}
209 |
210 | {/if}
211 | {#if enableColumnVisiblitySelect}
212 |
213 | {/if}
214 | {#if enableFullscreenMode}
215 |
216 | {/if}
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
230 |
231 |
234 | {#each $columnsStore.filter((c) => !$hiddenColumns.includes(c.accessor)) as column, columnIndex}
235 |
239 | {#if typeof column?.head?.component === 'string' || typeof column.head?.component === 'number'}
240 |
241 | {column.head.component}
242 |
243 | {:else if column.head?.component}
244 |
250 | {:else if column.header}
251 |
252 | {column.header}
253 |
254 | {/if}
255 |
256 | {#if column && column?.config?.sortable !== false && enableSorting}
257 |
258 | {/if}
259 | {#if column.config?.resizable != false && enableResizing}
260 |
264 | {/if}
265 |
266 |
267 | {/each}
268 |
269 |
270 | {#if enableVirtualization}
271 |
272 |
273 |
278 | {#each items as row, idx (row.index)}
279 | {@const dataRow = data[row.index]}
280 | {@const dataIndex = row.index}
281 |
282 |
290 | {#each $columnsStore.filter((c) => !$hiddenColumns.includes(c.accessor)) as column, columnIndex}
291 |
305 | {#if $inlineEditing.includes(dataRow.id)}
306 |
307 | {:else}
308 |
309 | {/if}
310 |
311 | {/each}
312 |
313 | {#if $expandedRows.includes(dataRow.id)}
314 |
315 |
322 |
323 | {/if}
324 |
325 | {/each}
326 |
327 |
328 |
329 | {:else if !enableVirtualization}
330 |
331 | {#if !loading && data.length < 1}
332 |
333 |
334 |
335 |
336 |
No data found
337 |
338 |
339 |
340 | {/if}
341 |
342 | {#each $visibleRows as row, rowIndex}
343 |
351 | {#each $columnsStore.filter((c) => !$hiddenColumns.includes(c.accessor)) as column, columnIndex}
352 |
365 | {#if $inlineEditing.includes(row.id)}
366 |
367 | {:else}
368 |
369 | {/if}
370 |
371 | {/each}
372 |
373 | {#if $expandedRows.includes(row.id)}
374 |
375 |
382 |
383 | {/if}
384 | {/each}
385 |
386 | {/if}
387 |
388 |
389 | {#if enablePagination}
390 |
391 | {/if}
392 |
393 |
394 |
395 |
--------------------------------------------------------------------------------
/src/lib/components/table/cells/HeaderSelectCheckbox.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | Rows
35 |
36 | selectedRows.selectAllOnPage($visibleRows)}
37 | >Select all on page
39 | selectedRows.deselectAllOnPage($visibleRows)}
40 | >Deselect all on page
42 | selectedRows.deselectAll()}
43 | >Deselec all
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/lib/components/table/cells/InlineRowEditingToggleCell.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 | {#if $inlineEditing.includes(rowId)}
16 | {
19 | inlineEditing.update((s) => s.filter((i) => i != rowId));
20 | }}>SAVE
22 | {:else}
23 | {
26 | inlineEditing.update((s) => [...s, rowId]);
27 | }}>EDIT
29 | {/if}
30 |
31 |
--------------------------------------------------------------------------------
/src/lib/components/table/cells/LinkDetailsCell.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {props.value}
8 |
--------------------------------------------------------------------------------
/src/lib/components/table/cells/NumberInputEditableCell.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 | props.column.extra.onChange({
14 | value: +e.target.value,
15 | id: props.row.id,
16 | accessor: props.column.accessor
17 | })}
18 | />
19 |
--------------------------------------------------------------------------------
/src/lib/components/table/cells/RowExpandToggle.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 | {#if $expandedRows.includes(rowId)}
18 |
expandedRows.collapse(rowId)}>
19 |
20 |
21 | {:else}
22 |
expandedRows.expand(rowId)}
23 | >
25 | {/if}
26 |
27 |
--------------------------------------------------------------------------------
/src/lib/components/table/cells/RowSelectCheckbox.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 | selectRow({ rowId })} class="" />
22 |
23 |
--------------------------------------------------------------------------------
/src/lib/components/table/cells/TextInputEditableCell.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
12 | props.column.extra.onChange({
13 | value: e.target.value,
14 | id: props.row.id,
15 | accessor: props.column.accessor
16 | })}
17 | />
18 |
--------------------------------------------------------------------------------
/src/lib/components/table/components/CellEditableTemplate.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 | {#if !column.cell?.componentEditable}
21 | {#if getNestedValue(row, column.accessor) !== undefined}
22 | {getNestedValue(row, column.accessor)}
23 | {:else}
24 | {row[column.accessor]}
25 | {/if}
26 | {:else if column.cell?.componentEditable}
27 |
36 | {:else if column?.cell?.simplified}
37 | {@html column.cell.simplified({ column, row, rowIndex, value })}
38 | {/if}
39 |
--------------------------------------------------------------------------------
/src/lib/components/table/components/CellTemplate.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 | {#if !column.cell?.component}
21 | {#if column?.cell?.simplified}
22 | {@html column.cell.simplified({ column, row, rowIndex, value })}
23 |
24 | {:else if getNestedValue(row, column.accessor) !== undefined}
25 | {getNestedValue(row, column.accessor)}
26 | {:else}
27 | {row[column.accessor]}
28 | {/if}
29 |
30 | {:else if column.cell?.component}
31 |
40 | {/if}
41 |
--------------------------------------------------------------------------------
/src/lib/components/table/components/ColumnOrderDraggableChanger.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 |
24 |
25 | Order
26 |
27 |
28 |
29 |
39 | {#each $columns as item (item.id)}
40 |
41 |
45 | {#if item?.config?.moveable != false}
46 | {item.header}
47 |
48 | {#if item[SHADOW_ITEM_MARKER_PROPERTY_NAME]}
49 |
50 | {item.header}
51 |
52 | {/if}
53 | {/if}
54 |
55 | {/each}
56 |
57 | To change column order, click and hold one. Then move to the desired location and release.
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/lib/components/table/components/ColumnVisibilitySelect.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 | Visibility
17 |
18 |
19 |
20 | {#each columns
21 | .filter((c) => c.header != '')
22 | .map( (c) => ({ accessor: c.accessor, header: c.header, disabled: c.config?.disableHiding }) ) as col}
23 | {
27 | if (checked == false) {
28 | let newHidden = [...$hidden, col.accessor];
29 | hidden.set(newHidden);
30 | } else if (checked == true) {
31 | let newHidden = $hidden.filter((h) => h !== col.accessor);
32 | hidden.set(newHidden);
33 | }
34 | }}
35 | >
36 |
37 | {col.header}
38 |
39 | {/each}
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/lib/components/table/components/FullscreenModeToggle.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 | {
15 | fullscreenMode.toggle();
16 | if ($target == 'body') {
17 | $target = '#tableContent';
18 | } else {
19 | $target = 'body';
20 | }
21 | }}
22 | >
23 | {#if $fullscreenMode}
24 |
25 | {:else}
26 |
27 | {/if}
28 |
29 |
--------------------------------------------------------------------------------
/src/lib/components/table/components/Pagination.svelte:
--------------------------------------------------------------------------------
1 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Previous
34 |
35 |
36 | {#each pages as page (page.key)}
37 | {#if page.type === 'ellipsis'}
38 |
39 |
40 |
41 | {:else}
42 |
43 |
44 | {page.value}
45 |
46 |
47 | {/if}
48 | {/each}
49 |
50 |
51 | Next
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | {
63 | if (!v) {
64 | throw new Error();
65 | }
66 | perPage = v?.value;
67 | if (page * perPage - perPage >= count) {
68 | page = Math.ceil(count / perPage);
69 | }
70 | }}
71 | selected={limits.find((p) => p.value == perPage)}
72 | >
73 |
74 |
75 |
76 |
77 | {#each limits as limit}
78 | {limit.label}
79 | {/each}
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/src/lib/components/table/components/SortingToggle.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 | {#if $sorting.accessor == column.accessor}
12 | {#if $sorting.direction == 'asc'}
13 | {
18 | sorting.set({ accessor: column.accessor, direction: 'desc' });
19 | }}
20 | >
21 |
22 |
23 | {:else if $sorting.direction == 'desc'}
24 | {
29 | sorting.set({ accessor: '', direction: '' });
30 | }}
31 | >
32 |
33 |
34 | {/if}
35 | {:else}
36 | {
41 | sorting.set({ accessor: column.accessor, direction: 'asc' });
42 | }}
43 | >
44 |
45 |
46 | {/if}
47 |
--------------------------------------------------------------------------------
/src/lib/components/table/index.ts:
--------------------------------------------------------------------------------
1 | type ClassFunction = (props: { row: any; column: Column }) => string;
2 |
3 |
4 | export type Column = {
5 | accessor: string;
6 | header?: string,
7 | head?: {
8 | component?: any,
9 | class?: string
10 | },
11 | cell?: {
12 | component?: any,
13 | componentEditable?: any,
14 | simplified?: (props: { row: any; column: Column, value: string | number | any, rowIndex: number }) => string,
15 | class?: string | ClassFunction
16 | },
17 | config?: {
18 | visible?: boolean,
19 | sortable?: boolean,
20 | disableHiding?: boolean,
21 | resizable?: boolean,
22 | moveable?: boolean,
23 | size?: {
24 | w?: number,
25 | minW?: number,
26 | maxW?: number,
27 | },
28 | align?: "left" | "right" | "center",
29 |
30 | },
31 | extra?: any
32 | };
33 |
34 | export type Columns = Column[];
35 |
36 | export type CellProps = {
37 | value: unknown,
38 | column: Column,
39 | row: any,
40 | rowIndex: number
41 | }
42 |
43 | export type HeaderCellProps = {
44 | column: Column
45 | }
46 |
47 |
48 |
49 | export type SortingElement = {
50 | accessor: string,
51 | direction: 'ASC' | 'DESC' | ""
52 | }
53 |
54 |
55 | export type ColumnClassNames = {
56 | table: () => string;
57 | th: () => string;
58 | row: (row: any) => string;
59 | cell: (row: any, column: Column) => string;
60 | };
61 |
62 |
63 |
64 |
65 | export type Filter = {
66 | column: string,
67 | operator: 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'notBetween' | 'like' | 'ilike' | 'notIlike' | 'not' | 'inArray' | "",
68 | value: string | number
69 | }
70 |
--------------------------------------------------------------------------------
/src/lib/components/table/stores/columnSizesStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | export function createColumnSizesStore(arr: Array<{ accessor: string; w: number; minW: number; maxW: number }> = []) {
4 | const { set, subscribe, update } = writable(arr);
5 |
6 | return {
7 | subscribe,
8 | set,
9 | update,
10 | };
11 | }
12 |
13 | export const columnSizes = createColumnSizesStore();
14 | export type ColumnSizes = typeof columnSizes
--------------------------------------------------------------------------------
/src/lib/components/table/stores/expandedRowsStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | export function createExpandedRowsStore(arr: Array = []) {
4 | const { set, subscribe, update } = writable(arr);
5 |
6 | return {
7 | subscribe,
8 | set,
9 | update,
10 | expand: (rowId: number) =>
11 | update((state) => {
12 | if (!state.includes(rowId)) {
13 | return [...state, rowId];
14 | }
15 | return state;
16 | }),
17 | collapse: (rowId: number) =>
18 | update((state) => {
19 | let newState = state.filter((e) => e != rowId);
20 | return newState;
21 | })
22 | };
23 | }
24 |
25 | export const expandedRows = createExpandedRowsStore();
26 |
27 | export type ExpandedRows = typeof expandedRows
--------------------------------------------------------------------------------
/src/lib/components/table/stores/fullscreenModeStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | export function createFullscreenModeStore(open: boolean = false) {
4 | const { set, subscribe, update } = writable(open);
5 |
6 | return {
7 | subscribe,
8 | set,
9 | update,
10 | on: () =>
11 | update(() => {
12 | return true;
13 | }),
14 | off: () =>
15 | update(() => {
16 | return false;
17 | }),
18 | toggle: () => {
19 | update((store) => {
20 | return !store
21 | })
22 | }
23 | };
24 | }
25 |
26 | export const fullscreenMode = createFullscreenModeStore();
27 | export type FullscreenMode = typeof fullscreenMode
--------------------------------------------------------------------------------
/src/lib/components/table/stores/hiddenColumnsStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | export function createHiddenColumnsStore(arr: Array = []) {
4 | const { set, subscribe, update } = writable(arr);
5 |
6 | return {
7 | subscribe,
8 | set,
9 | update,
10 | };
11 | }
12 |
13 | export const hiddenColumns = createHiddenColumnsStore();
14 | export type HiddenColumns = typeof hiddenColumns
--------------------------------------------------------------------------------
/src/lib/components/table/stores/inlineEditingStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | export function createInlineEditingStore(arr: Array = []) {
4 | const { set, subscribe, update } = writable(arr);
5 |
6 | return {
7 | subscribe,
8 | set,
9 | update,
10 | };
11 | }
12 |
13 | export const inlineEditing = createInlineEditingStore();
14 | export type InlineEditing = typeof inlineEditing
--------------------------------------------------------------------------------
/src/lib/components/table/stores/selectedRowsStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 |
4 |
5 |
6 | type Rows = { id: number }[]
7 |
8 |
9 | export function createSelectedRowsStore(arr: Array = []) {
10 | const { set, subscribe, update } = writable(arr);
11 |
12 | const toggle = (rowId: number) => {
13 | update(state => {
14 | if (state.includes(rowId)) {
15 | return state.filter(id => id !== rowId);
16 | } else {
17 | return [...state, rowId];
18 | }
19 | });
20 | };
21 |
22 | const select = (rowId: number) => {
23 | update(state => {
24 | if (!state.includes(rowId)) {
25 | return [...state, rowId];
26 | }
27 | return state;
28 | });
29 | };
30 |
31 | const deselect = (rowId: number) => {
32 | update(state => state.filter(id => id !== rowId));
33 | };
34 |
35 | const deselectAll = () => {
36 | set([]);
37 | };
38 |
39 | const deselectAllOnPage = (rows: any) => {
40 | update(state => {
41 | const rowIds = rows.map(row => row.id);
42 | return state.filter(selectedRowId => !rowIds.includes(selectedRowId));
43 | });
44 | };
45 |
46 | const selectAllOnPage = (rows: any) => {
47 | update(state => {
48 | const rowIds = rows.map(row => row.id);
49 | return [...new Set([...state, ...rowIds])];
50 | });
51 | };
52 |
53 |
54 | return {
55 | subscribe,
56 | set,
57 | update,
58 | toggle,
59 | select,
60 | deselect,
61 | deselectAll,
62 | deselectAllOnPage,
63 | selectAllOnPage
64 | };
65 | }
66 |
67 | export const selectedRows = createSelectedRowsStore();
68 |
69 | export type SelectedRows = typeof selectedRows
--------------------------------------------------------------------------------
/src/lib/components/table/stores/sortingStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 | import type { SortingElement } from '..';
3 |
4 | export function createSortingStore(sorting: SortingElement) {
5 | const { set, subscribe, update } = writable(sorting);
6 |
7 | return {
8 | subscribe,
9 | set,
10 | update,
11 | };
12 | }
13 |
14 | export const sorting = createSortingStore({ accessor: "", direction: "" });
15 | export type Sorting = typeof sorting
--------------------------------------------------------------------------------
/src/lib/components/table/stores/visibleRowsStore.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | export function createVisibleRowsStore(arr: Array = []) {
4 | const { set, subscribe, update } = writable(arr);
5 |
6 | return {
7 | subscribe,
8 | set,
9 | update,
10 | };
11 | }
12 |
13 | export const visibleRows = createVisibleRowsStore();
14 | export type VisibleRows = typeof visibleRows
--------------------------------------------------------------------------------
/src/lib/components/table/table/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./table.svelte";
2 | import Body from "./table-body.svelte";
3 | import Caption from "./table-caption.svelte";
4 | import Cell from "./table-cell.svelte";
5 | import Footer from "./table-footer.svelte";
6 | import Head from "./table-head.svelte";
7 | import Header from "./table-header.svelte";
8 | import Row from "./table-row.svelte";
9 |
10 | export {
11 | Root,
12 | Body,
13 | Caption,
14 | Cell,
15 | Footer,
16 | Head,
17 | Header,
18 | Row,
19 | //
20 | Root as Table,
21 | Body as TableBody,
22 | Caption as TableCaption,
23 | Cell as TableCell,
24 | Footer as TableFooter,
25 | Head as TableHead,
26 | Header as TableHeader,
27 | Row as TableRow,
28 | };
29 |
--------------------------------------------------------------------------------
/src/lib/components/table/table/table-body.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/table/table/table-caption.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/table/table/table-cell.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/table/table/table-footer.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/table/table/table-head.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/table/table/table-header.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/components/table/table/table-row.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/lib/components/table/table/table.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
16 |
--------------------------------------------------------------------------------
/src/lib/components/table/utils/clientMode.ts:
--------------------------------------------------------------------------------
1 | import type { SortingElement } from "../index.js";
2 |
3 | export function getPropertyValue(obj: any, path: string): any {
4 | if (!obj || !path) return ''; // Add this check
5 |
6 | const properties = path.split('.');
7 | return properties.reduce((prev, curr) => prev && prev[curr], obj) || '';
8 | }
9 |
10 | export function sortByPropertyName(array: any[], propertyName: string, sortingElement: SortingElement): any[] {
11 | if (propertyName === '' || sortingElement.direction === '') {
12 | return array;
13 | }
14 |
15 | return array.slice().sort((a, b) => {
16 | const valueA = getPropertyValue(a, propertyName);
17 | const valueB = getPropertyValue(b, propertyName);
18 |
19 | if (typeof valueA === 'number' && typeof valueB === 'number') {
20 | // Compare numbers directly
21 | return sortingElement.direction === 'ASC' ? valueA - valueB : valueB - valueA;
22 | }
23 |
24 | // If not numbers, treat them as strings
25 | const stringA = String(valueA).toUpperCase();
26 | const stringB = String(valueB).toUpperCase();
27 |
28 | return sortingElement.direction === 'ASC'
29 | ? stringA.localeCompare(stringB)
30 | : stringB.localeCompare(stringA);
31 | });
32 | }
--------------------------------------------------------------------------------
/src/lib/components/table/utils/getNestedValue.ts:
--------------------------------------------------------------------------------
1 | export function getNestedValue(obj, path) {
2 | const properties = path.split('.');
3 | return properties.reduce((accumulator, currentProperty) => {
4 | if (accumulator && accumulator[currentProperty]) {
5 | return accumulator[currentProperty];
6 | }
7 | return undefined;
8 | }, obj);
9 | }
10 |
--------------------------------------------------------------------------------
/src/lib/components/table/utils/throttle.ts:
--------------------------------------------------------------------------------
1 |
2 | export function throttle(func: Function, limit: number) {
3 | let inThrottle: boolean;
4 | return function (...args: any[]) {
5 | if (!inThrottle) {
6 | func(...args);
7 | inThrottle = true;
8 | setTimeout(() => (inThrottle = false), limit);
9 | }
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/src/lib/components/ui/button/button.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/lib/components/ui/button/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./button.svelte";
2 | import { tv, type VariantProps } from "tailwind-variants";
3 | import type { Button as ButtonPrimitive } from "bits-ui";
4 |
5 | const buttonVariants = tv({
6 | base: "inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap 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",
7 | variants: {
8 | variant: {
9 | default: "bg-primary text-primary-foreground hover:bg-primary/90",
10 | destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
11 | outline:
12 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
13 | secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
14 | ghost: "hover:bg-accent hover:text-accent-foreground",
15 | link: "text-primary underline-offset-4 hover:underline",
16 | },
17 | size: {
18 | default: "h-10 px-4 py-2",
19 | sm: "h-9 rounded-md px-3",
20 | lg: "h-11 rounded-md px-8",
21 | icon: "h-10 w-10",
22 | },
23 | },
24 | defaultVariants: {
25 | variant: "default",
26 | size: "default",
27 | },
28 | });
29 |
30 | type Variant = VariantProps["variant"];
31 | type Size = VariantProps["size"];
32 |
33 | type Props = ButtonPrimitive.Props & {
34 | variant?: Variant;
35 | size?: Size;
36 | };
37 |
38 | type Events = ButtonPrimitive.Events;
39 |
40 | export {
41 | Root,
42 | type Props,
43 | type Events,
44 | //
45 | Root as Button,
46 | type Props as ButtonProps,
47 | type Events as ButtonEvents,
48 | buttonVariants,
49 | };
50 |
--------------------------------------------------------------------------------
/src/lib/components/ui/checkbox/checkbox.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
24 |
29 | {#if isChecked}
30 |
31 | {:else if isIndeterminate}
32 |
33 | {/if}
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/lib/components/ui/checkbox/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./checkbox.svelte";
2 | export {
3 | Root,
4 | //
5 | Root as Checkbox,
6 | };
7 |
--------------------------------------------------------------------------------
/src/lib/components/ui/collapsible/collapsible-content.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/lib/components/ui/collapsible/index.ts:
--------------------------------------------------------------------------------
1 | import { Collapsible as CollapsiblePrimitive } from "bits-ui";
2 | import Content from "./collapsible-content.svelte";
3 |
4 | const Root = CollapsiblePrimitive.Root;
5 | const Trigger = CollapsiblePrimitive.Trigger;
6 |
7 | export {
8 | Root,
9 | Content,
10 | Trigger,
11 | //
12 | Root as Collapsible,
13 | Content as CollapsibleContent,
14 | Trigger as CollapsibleTrigger,
15 | };
16 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dropdown-menu/index.ts:
--------------------------------------------------------------------------------
1 | import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
2 | import Item from "./dropdown-menu-item.svelte";
3 | import Label from "./dropdown-menu-label.svelte";
4 | import Content from "./dropdown-menu-content.svelte";
5 | import Shortcut from "./dropdown-menu-shortcut.svelte";
6 | import RadioItem from "./dropdown-menu-radio-item.svelte";
7 | import Separator from "./dropdown-menu-separator.svelte";
8 | import RadioGroup from "./dropdown-menu-radio-group.svelte";
9 | import SubContent from "./dropdown-menu-sub-content.svelte";
10 | import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
11 | import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
12 |
13 | const Sub = DropdownMenuPrimitive.Sub;
14 | const Root = DropdownMenuPrimitive.Root;
15 | const Trigger = DropdownMenuPrimitive.Trigger;
16 | const Group = DropdownMenuPrimitive.Group;
17 |
18 | export {
19 | Sub,
20 | Root,
21 | Item,
22 | Label,
23 | Group,
24 | Trigger,
25 | Content,
26 | Shortcut,
27 | Separator,
28 | RadioItem,
29 | SubContent,
30 | SubTrigger,
31 | RadioGroup,
32 | CheckboxItem,
33 | //
34 | Root as DropdownMenu,
35 | Sub as DropdownMenuSub,
36 | Item as DropdownMenuItem,
37 | Label as DropdownMenuLabel,
38 | Group as DropdownMenuGroup,
39 | Content as DropdownMenuContent,
40 | Trigger as DropdownMenuTrigger,
41 | Shortcut as DropdownMenuShortcut,
42 | RadioItem as DropdownMenuRadioItem,
43 | Separator as DropdownMenuSeparator,
44 | RadioGroup as DropdownMenuRadioGroup,
45 | SubContent as DropdownMenuSubContent,
46 | SubTrigger as DropdownMenuSubTrigger,
47 | CheckboxItem as DropdownMenuCheckboxItem,
48 | };
49 |
--------------------------------------------------------------------------------
/src/lib/components/ui/input/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./input.svelte";
2 |
3 | export type FormInputEvent = T & {
4 | currentTarget: EventTarget & HTMLInputElement;
5 | };
6 | export type InputEvents = {
7 | blur: FormInputEvent;
8 | change: FormInputEvent;
9 | click: FormInputEvent;
10 | focus: FormInputEvent;
11 | focusin: FormInputEvent;
12 | focusout: FormInputEvent;
13 | keydown: FormInputEvent;
14 | keypress: FormInputEvent;
15 | keyup: FormInputEvent;
16 | mouseover: FormInputEvent;
17 | mouseenter: FormInputEvent;
18 | mouseleave: FormInputEvent;
19 | paste: FormInputEvent;
20 | input: FormInputEvent;
21 | };
22 |
23 | export {
24 | Root,
25 | //
26 | Root as Input,
27 | };
28 |
--------------------------------------------------------------------------------
/src/lib/components/ui/input/input.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
36 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./pagination.svelte";
2 | import Content from "./pagination-content.svelte";
3 | import Item from "./pagination-item.svelte";
4 | import Link from "./pagination-link.svelte";
5 | import PrevButton from "./pagination-prev-button.svelte";
6 | import NextButton from "./pagination-next-button.svelte";
7 | import Ellipsis from "./pagination-ellipsis.svelte";
8 | export {
9 | Root,
10 | Content,
11 | Item,
12 | Link,
13 | PrevButton,
14 | NextButton,
15 | Ellipsis,
16 | //
17 | Root as Pagination,
18 | Content as PaginationContent,
19 | Item as PaginationItem,
20 | Link as PaginationLink,
21 | PrevButton as PaginationPrevButton,
22 | NextButton as PaginationNextButton,
23 | Ellipsis as PaginationEllipsis,
24 | };
25 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-content.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-ellipsis.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
18 | More pages
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-item.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-link.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
33 | {page.value}
34 |
35 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-next-button.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
22 |
23 | Next
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination-prev-button.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
22 |
23 |
24 | Previous
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/lib/components/ui/pagination/pagination.svelte:
--------------------------------------------------------------------------------
1 |
19 |
20 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/src/lib/components/ui/popover/index.ts:
--------------------------------------------------------------------------------
1 | import { Popover as PopoverPrimitive } from "bits-ui";
2 | import Content from "./popover-content.svelte";
3 | const Root = PopoverPrimitive.Root;
4 | const Trigger = PopoverPrimitive.Trigger;
5 | const Close = PopoverPrimitive.Close;
6 |
7 | export {
8 | Root,
9 | Content,
10 | Trigger,
11 | Close,
12 | //
13 | Root as Popover,
14 | Content as PopoverContent,
15 | Trigger as PopoverTrigger,
16 | Close as PopoverClose,
17 | };
18 |
--------------------------------------------------------------------------------
/src/lib/components/ui/popover/popover-content.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/index.ts:
--------------------------------------------------------------------------------
1 | import { Select as SelectPrimitive } from "bits-ui";
2 |
3 | import Label from "./select-label.svelte";
4 | import Item from "./select-item.svelte";
5 | import Content from "./select-content.svelte";
6 | import Trigger from "./select-trigger.svelte";
7 | import Separator from "./select-separator.svelte";
8 |
9 | const Root = SelectPrimitive.Root;
10 | const Group = SelectPrimitive.Group;
11 | const Input = SelectPrimitive.Input;
12 | const Value = SelectPrimitive.Value;
13 |
14 | export {
15 | Root,
16 | Group,
17 | Input,
18 | Label,
19 | Item,
20 | Value,
21 | Content,
22 | Trigger,
23 | Separator,
24 | //
25 | Root as Select,
26 | Group as SelectGroup,
27 | Input as SelectInput,
28 | Label as SelectLabel,
29 | Item as SelectItem,
30 | Value as SelectValue,
31 | Content as SelectContent,
32 | Trigger as SelectTrigger,
33 | Separator as SelectSeparator,
34 | };
35 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-content.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-item.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | {label ? label : value}
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-label.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-separator.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-trigger.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 | span]:line-clamp-1",
16 | className
17 | )}
18 | {...$$restProps}
19 | let:builder
20 | on:click
21 | on:keydown
22 | >
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/lib/components/ui/separator/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./separator.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Separator,
7 | };
8 |
--------------------------------------------------------------------------------
/src/lib/components/ui/separator/separator.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
23 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sheet/index.ts:
--------------------------------------------------------------------------------
1 | import { Dialog as SheetPrimitive } from "bits-ui";
2 | import { tv, type VariantProps } from "tailwind-variants";
3 |
4 | import Portal from "./sheet-portal.svelte";
5 | import Overlay from "./sheet-overlay.svelte";
6 | import Content from "./sheet-content.svelte";
7 | import Header from "./sheet-header.svelte";
8 | import Footer from "./sheet-footer.svelte";
9 | import Title from "./sheet-title.svelte";
10 | import Description from "./sheet-description.svelte";
11 |
12 | const Root = SheetPrimitive.Root;
13 | const Close = SheetPrimitive.Close;
14 | const Trigger = SheetPrimitive.Trigger;
15 |
16 | export {
17 | Root,
18 | Close,
19 | Trigger,
20 | Portal,
21 | Overlay,
22 | Content,
23 | Header,
24 | Footer,
25 | Title,
26 | Description,
27 | //
28 | Root as Sheet,
29 | Close as SheetClose,
30 | Trigger as SheetTrigger,
31 | Portal as SheetPortal,
32 | Overlay as SheetOverlay,
33 | Content as SheetContent,
34 | Header as SheetHeader,
35 | Footer as SheetFooter,
36 | Title as SheetTitle,
37 | Description as SheetDescription,
38 | };
39 |
40 | export const sheetVariants = tv({
41 | base: "fixed z-50 gap-4 bg-background p-6 shadow-lg",
42 | variants: {
43 | side: {
44 | top: "inset-x-0 top-0 border-b",
45 | bottom: "inset-x-0 bottom-0 border-t",
46 | left: "inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
47 | right: "inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
48 | },
49 | },
50 | defaultVariants: {
51 | side: "right",
52 | },
53 | });
54 |
55 | export const sheetTransitions = {
56 | top: {
57 | in: {
58 | y: "-100%",
59 | duration: 500,
60 | opacity: 1,
61 | },
62 | out: {
63 | y: "-100%",
64 | duration: 300,
65 | opacity: 1,
66 | },
67 | },
68 | bottom: {
69 | in: {
70 | y: "100%",
71 | duration: 500,
72 | opacity: 1,
73 | },
74 | out: {
75 | y: "100%",
76 | duration: 300,
77 | opacity: 1,
78 | },
79 | },
80 | left: {
81 | in: {
82 | x: "-100%",
83 | duration: 500,
84 | opacity: 1,
85 | },
86 | out: {
87 | x: "-100%",
88 | duration: 300,
89 | opacity: 1,
90 | },
91 | },
92 | right: {
93 | in: {
94 | x: "100%",
95 | duration: 500,
96 | opacity: 1,
97 | },
98 | out: {
99 | x: "100%",
100 | duration: 300,
101 | opacity: 1,
102 | },
103 | },
104 | };
105 |
106 | export type Side = VariantProps["side"];
107 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sheet/sheet-content.svelte:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
31 |
39 |
40 |
43 |
44 | Close
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sheet/sheet-description.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sheet/sheet-footer.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sheet/sheet-header.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sheet/sheet-overlay.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sheet/sheet-portal.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sheet/sheet-title.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sonner/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Toaster } from "./sonner.svelte";
2 |
--------------------------------------------------------------------------------
/src/lib/components/ui/sonner/sonner.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
21 |
--------------------------------------------------------------------------------
/src/lib/components/ui/tabs/index.ts:
--------------------------------------------------------------------------------
1 | import { Tabs as TabsPrimitive } from "bits-ui";
2 | import Content from "./tabs-content.svelte";
3 | import List from "./tabs-list.svelte";
4 | import Trigger from "./tabs-trigger.svelte";
5 |
6 | const Root = TabsPrimitive.Root;
7 |
8 | export {
9 | Root,
10 | Content,
11 | List,
12 | Trigger,
13 | //
14 | Root as Tabs,
15 | Content as TabsContent,
16 | List as TabsList,
17 | Trigger as TabsTrigger,
18 | };
19 |
--------------------------------------------------------------------------------
/src/lib/components/ui/tabs/tabs-content.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/lib/components/ui/tabs/tabs-list.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/lib/components/ui/tabs/tabs-trigger.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | // Reexport your entry components here
2 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 | import { cubicOut } from "svelte/easing";
4 | import type { TransitionConfig } from "svelte/transition";
5 |
6 | export function cn(...inputs: ClassValue[]) {
7 | return twMerge(clsx(inputs));
8 | }
9 |
10 | type FlyAndScaleParams = {
11 | y?: number;
12 | x?: number;
13 | start?: number;
14 | duration?: number;
15 | };
16 |
17 | export const flyAndScale = (
18 | node: Element,
19 | params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
20 | ): TransitionConfig => {
21 | const style = getComputedStyle(node);
22 | const transform = style.transform === "none" ? "" : style.transform;
23 |
24 | const scaleConversion = (
25 | valueA: number,
26 | scaleA: [number, number],
27 | scaleB: [number, number]
28 | ) => {
29 | const [minA, maxA] = scaleA;
30 | const [minB, maxB] = scaleB;
31 |
32 | const percentage = (valueA - minA) / (maxA - minA);
33 | const valueB = percentage * (maxB - minB) + minB;
34 |
35 | return valueB;
36 | };
37 |
38 | const styleToString = (
39 | style: Record
40 | ): string => {
41 | return Object.keys(style).reduce((str, key) => {
42 | if (style[key] === undefined) return str;
43 | return str + `${key}:${style[key]};`;
44 | }, "");
45 | };
46 |
47 | return {
48 | duration: params.duration ?? 200,
49 | delay: 0,
50 | css: (t) => {
51 | const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
52 | const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
53 | const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
54 |
55 | return styleToString({
56 | transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
57 | opacity: t
58 | });
59 | },
60 | easing: cubicOut
61 | };
62 | };
--------------------------------------------------------------------------------
/src/routes/(examples)/+layout.svelte:
--------------------------------------------------------------------------------
1 | Code from example
2 |
3 | The code from the example as well as the annotations are available at GITHUB
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/routes/(examples)/basic/+page.svelte:
--------------------------------------------------------------------------------
1 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/routes/(examples)/client-mode/+page.svelte:
--------------------------------------------------------------------------------
1 |
48 |
49 |
50 |
51 |
62 |
63 |
64 | {
68 | enableVirtualization = !enableVirtualization;
69 | }}>{enableVirtualization ? 'Disable virtualization' : 'Enable virtualization'}
71 |
72 | {
76 | enableColumnVisiblitySelect = !enableColumnVisiblitySelect;
77 | }}>{enableColumnVisiblitySelect ? 'Disable column hiding' : 'Enable column hiding'}
79 | {
83 | enableColumnReordering = !enableColumnReordering;
84 | }}>{enableColumnReordering ? 'Disable column reordering' : 'Enable column reordering'}
86 | {
90 | enablePagination = !enablePagination;
91 | }}>{enablePagination ? 'Disable pagination' : 'Enable pagination'}
93 | {
97 | enableResizing = !enableResizing;
98 | }}>{enableResizing ? 'Disable resizing' : 'Enable resizing'}
100 | {
104 | enableSorting = !enableSorting;
105 | }}>{enableSorting ? 'Disable sorting' : 'Enable sorting'}
107 |
108 |
109 |
EXPERIMENTAL PREVIEW
110 |
Not tested enough, I would not use it in production
111 |
Pagination does not work with virtualization
112 |
--------------------------------------------------------------------------------
/src/routes/(examples)/column-filtering/+page.svelte:
--------------------------------------------------------------------------------
1 |
82 |
83 |
91 |
92 | Note
93 |
94 | In response to a question, I add an example of how to build column filtering. The component as
95 | such does not have a built-in way to add column filtering with a single value like
96 | "enableColumnFilter: number". You need to add a custom header cell with input and handle the
97 | change of value. You could make a store and bind values to it and then refetch the data by
98 | detecting the change.
99 |
100 |
--------------------------------------------------------------------------------
/src/routes/(examples)/column-filtering/_components/ExpandableRow.svelte:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 | 'bg-foreground/5 max-h-[200px] overflow-auto'
34 | }}
35 | />
36 |
--------------------------------------------------------------------------------
/src/routes/(examples)/column-filtering/_components/RatingCell.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | 4.6 && 'text-green-500')}>{props.value}
--------------------------------------------------------------------------------
/src/routes/(examples)/column-filtering/_components/TitleHeaderCell.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | {props.column.header}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/routes/(examples)/column-hiding/+page.svelte:
--------------------------------------------------------------------------------
1 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/src/routes/(examples)/column-ordering/+page.svelte:
--------------------------------------------------------------------------------
1 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/routes/(examples)/column-resizing/+page.svelte:
--------------------------------------------------------------------------------
1 |
49 |
50 |
51 |
52 |
60 |
--------------------------------------------------------------------------------
/src/routes/(examples)/conditional-styling/+page.svelte:
--------------------------------------------------------------------------------
1 |
44 |
45 | (row.title.startsWith('S') ? 'bg-red-400 hover:bg-red-400/80' : ''),
50 | cell: ({row, column}) => {
51 | return column.accessor == 'brand' ? 'bg-blue-400 hover:bg-blue-400/80' : '';
52 | }
53 | }}
54 | />
55 |
--------------------------------------------------------------------------------
/src/routes/(examples)/content-align/+page.svelte:
--------------------------------------------------------------------------------
1 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/src/routes/(examples)/custom-cells/+page.svelte:
--------------------------------------------------------------------------------
1 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/src/routes/(examples)/custom-cells/BrandCell.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {props.value}
8 |
--------------------------------------------------------------------------------
/src/routes/(examples)/custom-cells/DescriptionCell.svelte:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | Custom cell
--------------------------------------------------------------------------------
/src/routes/(examples)/custom-cells/IdCellHeader.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 | Custom header cell
--------------------------------------------------------------------------------
/src/routes/(examples)/custom-cells/RatingCell.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | 4.6 && 'text-green-500')}>{props.value}
--------------------------------------------------------------------------------
/src/routes/(examples)/pagination/+page.svelte:
--------------------------------------------------------------------------------
1 |
53 |
54 |
62 |
63 |
64 |
65 |
Use these values to apply pagination to the server
66 |
perPage: {perPage}
67 |
page: {page}
68 |
offset: {page * perPage - perPage}
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-expanding/+page.svelte:
--------------------------------------------------------------------------------
1 |
67 |
68 |
73 |
74 | Expanded rows:
75 |
76 | {JSON.stringify($expandedRows, '', 2)}
77 |
78 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-expanding/ExpandableRow.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | {JSON.stringify(props,"",2)}
9 |
10 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-inline-editing-save-on-click/+page.svelte:
--------------------------------------------------------------------------------
1 |
150 |
151 |
152 |
153 | Inline editing rows:
154 |
155 | {JSON.stringify(
156 | $rows.map((e) => {
157 | return { brand: e.brand, price: e.price };
158 | }),
159 | '',
160 | 2
161 | )}
162 |
163 |
164 | Note
165 |
166 | It is more common practice to save a row when clicking the save button than to edit cells directly
167 | as in the previous example. The nature of the component is very flexible, in this example I will
168 | show how I usually do it. You can add e.g. cancel button etc. it is up to you. Check out the code
169 | on github for more tips.
170 |
171 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-inline-editing-save-on-click/_components/InlineEditing.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 | {#if $inlineEditing.includes(rowId)}
23 | {
27 | // call the method to handle changed row
28 | onSave({ data: $rows.filter((s) => s.id == rowId)[0] });
29 |
30 | // remove row from store
31 | let filteredRowsStore = $rows.filter((s) => s.id != rowId);
32 | $rows = filteredRowsStore;
33 |
34 | // table inner state update
35 | inlineEditing.update((s) => s.filter((i) => i != rowId));
36 | }}>SAVE
38 | {:else}
39 | {
43 | // we add row to the store
44 | $rows = [{...props.row}, ...$rows];
45 | inlineEditing.update((s) => [...s, rowId]);
46 | }}>EDIT
48 | {/if}
49 |
50 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-inline-editing-save-on-click/_components/SelectBrand.svelte:
--------------------------------------------------------------------------------
1 |
2 |
3 |
33 |
34 | {
37 | let newRows = $rows.map((row) => {
38 | if (row.id === props.row.id) {
39 | return { ...row, brand: v?.value };
40 | }
41 | return row;
42 | });
43 | $rows = newRows;
44 | }}
45 | >
46 |
47 |
48 |
49 |
50 | {#each options as option}
51 | {option.label}
52 | {/each}
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-inline-editing-save-on-click/_components/ValueCellEdit.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 | {
13 | props.column.extra.onChange({
14 | value: +e.target.value,
15 | id: props.row.id,
16 | accessor: props.column.accessor
17 | });
18 | }}
19 | />
20 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-inline-editing/+page.svelte:
--------------------------------------------------------------------------------
1 |
70 |
71 |
72 |
73 | Inline editing rows:
74 |
75 | {JSON.stringify($inlineEditing, '', 2)}
76 |
77 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-modal-editing/+page.svelte:
--------------------------------------------------------------------------------
1 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-modal-editing/EditModal.svelte:
--------------------------------------------------------------------------------
1 |
9 |
10 |
16 |
17 |
18 | EDIT
19 |
20 |
21 |
22 | Edit profile
23 |
24 | Make changes to your profile here. Click save when you're done.
25 |
26 |
27 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/routes/(examples)/row-selection/+page.svelte:
--------------------------------------------------------------------------------
1 |
75 |
76 |
77 |
78 | Selected rows:
79 |
80 | {JSON.stringify($selectedRows, '', 2)}
81 |
82 |
--------------------------------------------------------------------------------
/src/routes/(examples)/sorting/+page.svelte:
--------------------------------------------------------------------------------
1 |
67 |
68 |
69 | Sorting is not working in the example because dummyjson.com does not support it
70 |
71 | {$sorting.accessor}
72 | {$sorting.direction}
73 |
74 |
--------------------------------------------------------------------------------
/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 |
36 |
37 |
38 |
83 |
84 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
99 |
100 | Sebastian "Tzezar" Drozd {new Date().getFullYear()}
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
123 |
--------------------------------------------------------------------------------
/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 |
156 |
157 |
158 |
161 | Table component built in svelte based on shadcn-svelte components.
162 |
163 |
164 |
165 |
180 |
181 | {#if enableActions}
182 |
202 | {/if}
203 |
204 |
205 |
206 |
207 | {#if $enableExpandableRow}
208 |
custom expanded row
209 | {/if}
210 |
211 |
212 |
213 |
214 |
215 | Sorting is not working in the example because dummyjson.com does not support it
216 |
217 |
218 |
219 | {
223 | enableVirtualization = !enableVirtualization;
224 | }}>{enableVirtualization ? 'Disable virtualization' : 'Enable virtualization'}
226 |
227 | {
231 | hideExpandedColumn();
232 | $enableExpandableRow = !$enableExpandableRow;
233 | }}>{$enableExpandableRow ? 'Disable expandable rows' : 'Enable expandable rows'}
235 | {
239 | enableActions = !enableActions;
240 | }}>{enableActions ? 'Disable actions' : 'Enable actions'}
242 | {
246 | enableColumnVisiblitySelect = !enableColumnVisiblitySelect;
247 | }}>{enableColumnVisiblitySelect ? 'Disable column hiding' : 'Enable column hiding'}
249 | {
253 | enableColumnReordering = !enableColumnReordering;
254 | }}>{enableColumnReordering ? 'Disable column reordering' : 'Enable column reordering'}
256 | {
260 | enablePagination = !enablePagination;
261 | }}>{enablePagination ? 'Disable pagination' : 'Enable pagination'}
263 | {
267 | enableResizing = !enableResizing;
268 | }}>{enableResizing ? 'Disable resizing' : 'Enable resizing'}
270 | {
274 | enableSorting = !enableSorting;
275 | }}>{enableSorting ? 'Disable sorting' : 'Enable sorting'}
277 | {
282 | enableFullscreenMode = !enableFullscreenMode;
283 | }}>{enableFullscreenMode ? 'Disable fullscreen mode' : 'Enable fullscreen mode'}
285 |
286 |
287 | What is this?
288 |
289 | I entrust to you a modest component, crafted atop the robust shadcn-svelte library, utilizing
290 | built-in svelte functions such as stores, among others. Every aspect of the table - its
291 | aesthetics, functionality, and beyond - can be customized to your heart's content. This serves as
292 | an excellent foundation to tailor a solution precisely to your requirements. If a component or
293 | basic solution doesn't quite align with your vision, fear not - mold it to your liking!
294 |
295 |
296 | For whom?
297 |
298 | The component efficiently manages server-side data (with client-side capability coming soon). It's
299 | designed for seamless extension with extra features, and styling integration should pose no major
300 | challenges. If you're already leveraging shadcn-svelte and tailwind, incorporating this component
301 | into your workflow is a natural fit.
302 |
303 | Genesis
304 |
305 | This project started as a way for me to make warehouse operations smoother with dynamic table
306 | displays. Despite trying options like ag-grid and headless solutions, none quite fit the bill.
307 | 'Full' solutions were tough to customize, and headless ones like tanstack-table had tricky
308 | documentation. Dealing with remote data was also a hassle. So, TZEZAR's TABLE (pronounced like
309 | 'Caesar') was born to bridge the gap, offering flexibility. Feel free to tweak this component to
310 | suit your needs!
311 |
312 |
313 | Currently Supported Functions
314 |
315 | Column Hiding
316 | Column Reordering
317 | Column Resizing
318 | Conditional Styling
319 | Content Alignment
320 | Custom Content
321 | Pagination
322 | Inline Row Editing
323 | Modal Row Editing
324 | Row Editing
325 | Row Expanding
326 | Single Column Sorting
327 |
328 | Planned Functions
329 |
345 | Not Planned for Immediate Addition
346 |
347 | Aggregation and Grouping
348 | Column Pinning
349 |
350 |
351 | If you spot any missing features, don't worry! Adding them should be a breeze. Feel free to
352 | suggest ideas or improvements, and let's work together to make our component even better. Your
353 | input is always welcome, and together, we can create something truly outstanding!
354 |
355 |
356 |
357 | If you find the project interesting feel free to give a star on github . Thanks! ❤️
360 |
361 |
--------------------------------------------------------------------------------
/src/routes/_components/RatingCell.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | 4.6 && 'text-green-500')}>{props.value}
--------------------------------------------------------------------------------
/src/routes/_components/Sidebar.svelte:
--------------------------------------------------------------------------------
1 |
38 |
39 |
54 |
--------------------------------------------------------------------------------
/src/routes/_components/TitleHeaderCell.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | {props.column.header}
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/routes/_components/custom-row-expand/CustomRowExpandToggle.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 | {#if $expandedRows.includes(rowId)}
18 |
expandedRows.collapse(rowId)}>
19 |
20 |
21 | {:else}
22 |
expandedRows.expand(rowId)}>
23 |
24 |
25 | {/if}
26 |
27 |
--------------------------------------------------------------------------------
/src/routes/installation/+page.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 | shadcn-svelte
9 |
10 | I assume you already have shadcn-svelte installed, if not here is a tutorial: https://www.shadcn-svelte.com/docs/installation
15 |
16 |
17 | Component
18 |
19 | Copy content of
20 | https://github.com/530RGE/table/tree/main/src/lib/components/table
25 | into your project.
26 |
27 |
28 | You also need cn helper function from
29 | https://github.com/530RGE/table/blob/main/src/lib/utils.ts .
32 |
33 |
34 | flyAndScale util is used for draggable column reordering (optional
35 | if you make custom component)
36 |
37 |
38 |
39 | Table out of the box use those shadcn-svelte components
40 |
41 |
42 |
43 | npx shadcn-svelte@latest add button
44 | npx shadcn-svelte@latest add select
45 | npx shadcn-svelte@latest add checkbox
46 | npx shadcn-svelte@latest add pagination
47 | npx shadcn-svelte@latest add dropdown-menu
48 | npx shadcn-svelte@latest add popover
49 | npx shadcn-svelte@latest add sheet
50 | npx shadcn-svelte@latest add input
51 |
52 |
53 |
54 |
55 | Draggable column reordering uses svelte-dnd-action
56 |
57 |
58 |
59 | npm i svelte-dnd-action
60 | npm i svelte-legos
61 |
62 |
63 |
64 | Optional
65 |
66 |
67 | npm install mode-watcher
68 | npm i @tanstack/svelte-query
69 | npm i @tanstack/svelte-query-devtools
70 |
71 |
72 |
73 |
74 | mode-watches is easy way to implement dark mode, and tanstack-query is good for data fetching
75 |
76 |
77 | 04/04/2024 update
78 |
79 | I rebuilt the shadcn table to use divs (easier styling, ability to change width, no weird
80 | behaviour) and used them in the component. It made component cleaner and easier to read. You don't
81 | have to overwrite it, you can have both the
82 | official shadcn version and the one for the component built with divs.
83 |
84 |
85 | just take a look at repo folder
86 |
87 |
88 |
89 | Code from examples
90 |
91 | The code from the example as well as the annotations are available at GITHUB
95 |
96 |
--------------------------------------------------------------------------------
/src/routes/planned/+page.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | What's planned?
7 |
8 |
9 |
Virtualisation
10 |
Added 21/03/2024
11 |
12 | Virtualisation is not easy especially with something as complex as tables. In a private
13 | project I use it with the table component in several places, but I am aware of one bug and
14 | until I fix it it will not be implemented. I need to spend some time on this and it will
15 | certainly be added.
16 |
17 |
18 | Client-side functionalities
19 |
20 | I actually have this already implemented in a private project too, but it's not pretty code and
21 | needs to be rewritten before it sees the light of day.
22 |
23 | More examples
24 |
25 | There are things such as filter slots or additional actions or global search that are not
26 | described. More examples will be added when I have time. Unfortunately I have a lot of other
27 | work right now.
28 |
29 | Advanced filter functionality
30 |
31 | I don't quite know if this fits in well with the theme of the table, on the one hand it is
32 | geared towards server data, but on the other hand such a component is something else entirely.
33 | Maybe it will be as an additional component.
34 |
35 |
36 |
37 | Async loading indicator
38 |
39 | In theory this is implemented and you can pass `loading` to a component, but the loading
40 | indicator is a simple loader, not some beauty. Definitely to be improved as I find time.
41 |
42 |
43 | Column filtering
44 |
45 | I'm not a big fan of this solution but I know some people will need it. To be done in the
46 | future.
47 |
48 | Density toggle
49 | This is actually implemented in my private project, I will soon add it for sure.
50 |
51 |
52 |
Fullscreen
53 |
Added 21/03/2024
54 |
55 | As above
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tzezar/table/67a908b769c7c7cf05f1adf4b102e0b69d9ce0e7/static/favicon.png
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from '@sveltejs/adapter-auto';
2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
3 |
4 | /** @type {import('@sveltejs/kit').Config} */
5 | const config = {
6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors
7 | // for more information about preprocessors
8 | preprocess: [vitePreprocess({})],
9 |
10 | kit: {
11 | alias: {
12 | "@/*": "./path/to/lib/*",
13 | },
14 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
15 | // If your environment is not supported or you settled on a specific environment, switch out the adapter.
16 | // See https://kit.svelte.dev/docs/adapters for more information about adapters.
17 | adapter: adapter()
18 | }
19 | };
20 |
21 | export default config;
22 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | import { fontFamily } from "tailwindcss/defaultTheme";
2 |
3 | /** @type {import('tailwindcss').Config} */
4 | const config = {
5 | darkMode: ["class"],
6 | content: ["./src/**/*.{html,js,svelte,ts}"],
7 | safelist: ["dark"],
8 | theme: {
9 | container: {
10 | center: true,
11 | padding: "2rem",
12 | screens: {
13 | "2xl": "1400px"
14 | }
15 | },
16 | extend: {
17 | colors: {
18 | border: "hsl(var(--border) / )",
19 | input: "hsl(var(--input) / )",
20 | ring: "hsl(var(--ring) / )",
21 | background: "hsl(var(--background) / )",
22 | foreground: "hsl(var(--foreground) / )",
23 | primary: {
24 | DEFAULT: "hsl(var(--primary) / )",
25 | foreground: "hsl(var(--primary-foreground) / )"
26 | },
27 | secondary: {
28 | DEFAULT: "hsl(var(--secondary) / )",
29 | foreground: "hsl(var(--secondary-foreground) / )"
30 | },
31 | destructive: {
32 | DEFAULT: "hsl(var(--destructive) / )",
33 | foreground: "hsl(var(--destructive-foreground) / )"
34 | },
35 | muted: {
36 | DEFAULT: "hsl(var(--muted) / )",
37 | foreground: "hsl(var(--muted-foreground) / )"
38 | },
39 | accent: {
40 | DEFAULT: "hsl(var(--accent) / )",
41 | foreground: "hsl(var(--accent-foreground) / )"
42 | },
43 | popover: {
44 | DEFAULT: "hsl(var(--popover) / )",
45 | foreground: "hsl(var(--popover-foreground) / )"
46 | },
47 | card: {
48 | DEFAULT: "hsl(var(--card) / )",
49 | foreground: "hsl(var(--card-foreground) / )"
50 | }
51 | },
52 | borderRadius: {
53 | lg: "var(--radius)",
54 | md: "calc(var(--radius) - 2px)",
55 | sm: "calc(var(--radius) - 4px)"
56 | },
57 | fontFamily: {
58 | sans: [...fontFamily.sans]
59 | },
60 |
61 |
62 | }
63 | },
64 | plugins: [
65 | require('@tailwindcss/typography'),
66 | // ...
67 | ],
68 | };
69 |
70 | export default config;
71 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "sourceMap": true,
11 | "strict": true,
12 | "module": "NodeNext",
13 | "moduleResolution": "NodeNext"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import { defineConfig } from 'vite';
3 |
4 | export default defineConfig({
5 | plugins: [sveltekit()],
6 | });
7 |
--------------------------------------------------------------------------------