diff --git a/web/.prettierrc b/web/.prettierrc index 281bce185ab..fb0e0c92b4c 100644 --- a/web/.prettierrc +++ b/web/.prettierrc @@ -4,6 +4,6 @@ "printWidth": 120, "semi": true, "organizeImportsSkipDestructiveCodeActions": true, - "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], + "plugins": ["prettier-plugin-svelte"], "pluginSearchDirs": false } diff --git a/web/package-lock.json b/web/package-lock.json index cecddfe9cff..e3d24741c59 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -50,16 +50,12 @@ "eslint-config-prettier": "^8.6.0", "eslint-plugin-svelte": "^2.30.0", "factory.ts": "^1.3.0", - "flowbite": "^1.8.1", - "flowbite-svelte": "^0.43.1", - "flowbite-svelte-icons": "^0.3.6", "identity-obj-proxy": "^3.0.0", "jest": "^29.4.3", "jest-environment-jsdom": "^29.4.3", "postcss": "^8.4.21", "prettier": "^2.8.4", "prettier-plugin-svelte": "^2.10.1", - "prettier-plugin-tailwindcss": "^0.4.1", "svelte": "^4.0.5", "svelte-check": "^3.4.3", "svelte-jester": "^2.3.2", @@ -3204,16 +3200,6 @@ "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, "node_modules/@rollup/plugin-commonjs": { "version": "24.0.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.1.tgz", @@ -6236,45 +6222,6 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, - "node_modules/flowbite": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-1.8.1.tgz", - "integrity": "sha512-lXTcO8a6dRTPFpINyOLcATCN/pK1Of/jY4PryklPllAiqH64tSDUsOdQpar3TO59ZXWwugm2e92oaqwH6X90Xg==", - "dev": true, - "dependencies": { - "@popperjs/core": "^2.9.3", - "mini-svg-data-uri": "^1.4.3" - } - }, - "node_modules/flowbite-svelte": { - "version": "0.43.1", - "resolved": "https://registry.npmjs.org/flowbite-svelte/-/flowbite-svelte-0.43.1.tgz", - "integrity": "sha512-01ofjsHi7YRNx/MvmjpULQ5L6ar8El7yqWD3aJJupyaXRvTyPb5CHPUP5fT1rOJA11oeZDnPRTdJ27aDuTXpZQ==", - "dev": true, - "dependencies": { - "@floating-ui/dom": "^1.5.1", - "flowbite": "^1.8.1", - "tailwind-merge": "^1.14.0" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - }, - "peerDependencies": { - "svelte": "^3.55.1 || ^4.0.0" - } - }, - "node_modules/flowbite-svelte-icons": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/flowbite-svelte-icons/-/flowbite-svelte-icons-0.3.6.tgz", - "integrity": "sha512-4YEq++cbD36KF+zGgLqfkmQgfWGMAP7tjDbesuieROx6UgbMBTtj7f4n49iO+g1cMLelGsCkyZiwelCXDbIJ2w==", - "dev": true, - "peerDependencies": { - "svelte": "^3.54.0 || ^4.0.0", - "tailwind-merge": "^1.13.2", - "tailwindcss": "^3.3.2" - } - }, "node_modules/follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -9629,15 +9576,6 @@ "node": ">=4" } }, - "node_modules/mini-svg-data-uri": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", - "dev": true, - "bin": { - "mini-svg-data-uri": "cli.js" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -10288,80 +10226,6 @@ "svelte": "^3.2.0 || ^4.0.0-next.0" } }, - "node_modules/prettier-plugin-tailwindcss": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.4.1.tgz", - "integrity": "sha512-hwn2EiJmv8M+AW4YDkbjJ6HlZCTzLyz1QlySn9sMuKV/Px0fjwldlB7tol8GzdgqtkdPtzT3iJ4UzdnYXP25Ag==", - "dev": true, - "engines": { - "node": ">=12.17.0" - }, - "peerDependencies": { - "@ianvs/prettier-plugin-sort-imports": "*", - "@prettier/plugin-pug": "*", - "@shopify/prettier-plugin-liquid": "*", - "@shufo/prettier-plugin-blade": "*", - "@trivago/prettier-plugin-sort-imports": "*", - "prettier": "^2.2 || ^3.0", - "prettier-plugin-astro": "*", - "prettier-plugin-css-order": "*", - "prettier-plugin-import-sort": "*", - "prettier-plugin-jsdoc": "*", - "prettier-plugin-marko": "*", - "prettier-plugin-organize-attributes": "*", - "prettier-plugin-organize-imports": "*", - "prettier-plugin-style-order": "*", - "prettier-plugin-svelte": "*", - "prettier-plugin-twig-melody": "*" - }, - "peerDependenciesMeta": { - "@ianvs/prettier-plugin-sort-imports": { - "optional": true - }, - "@prettier/plugin-pug": { - "optional": true - }, - "@shopify/prettier-plugin-liquid": { - "optional": true - }, - "@shufo/prettier-plugin-blade": { - "optional": true - }, - "@trivago/prettier-plugin-sort-imports": { - "optional": true - }, - "prettier-plugin-astro": { - "optional": true - }, - "prettier-plugin-css-order": { - "optional": true - }, - "prettier-plugin-import-sort": { - "optional": true - }, - "prettier-plugin-jsdoc": { - "optional": true - }, - "prettier-plugin-marko": { - "optional": true - }, - "prettier-plugin-organize-attributes": { - "optional": true - }, - "prettier-plugin-organize-imports": { - "optional": true - }, - "prettier-plugin-style-order": { - "optional": true - }, - "prettier-plugin-svelte": { - "optional": true - }, - "prettier-plugin-twig-melody": { - "optional": true - } - } - }, "node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", @@ -14414,12 +14278,6 @@ "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, - "@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "dev": true - }, "@rollup/plugin-commonjs": { "version": "24.0.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.0.1.tgz", @@ -16653,34 +16511,6 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, - "flowbite": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/flowbite/-/flowbite-1.8.1.tgz", - "integrity": "sha512-lXTcO8a6dRTPFpINyOLcATCN/pK1Of/jY4PryklPllAiqH64tSDUsOdQpar3TO59ZXWwugm2e92oaqwH6X90Xg==", - "dev": true, - "requires": { - "@popperjs/core": "^2.9.3", - "mini-svg-data-uri": "^1.4.3" - } - }, - "flowbite-svelte": { - "version": "0.43.1", - "resolved": "https://registry.npmjs.org/flowbite-svelte/-/flowbite-svelte-0.43.1.tgz", - "integrity": "sha512-01ofjsHi7YRNx/MvmjpULQ5L6ar8El7yqWD3aJJupyaXRvTyPb5CHPUP5fT1rOJA11oeZDnPRTdJ27aDuTXpZQ==", - "dev": true, - "requires": { - "@floating-ui/dom": "^1.5.1", - "flowbite": "^1.8.1", - "tailwind-merge": "^1.14.0" - } - }, - "flowbite-svelte-icons": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/flowbite-svelte-icons/-/flowbite-svelte-icons-0.3.6.tgz", - "integrity": "sha512-4YEq++cbD36KF+zGgLqfkmQgfWGMAP7tjDbesuieROx6UgbMBTtj7f4n49iO+g1cMLelGsCkyZiwelCXDbIJ2w==", - "dev": true, - "requires": {} - }, "follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -19150,12 +18980,6 @@ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, - "mini-svg-data-uri": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", - "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", - "dev": true - }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -19595,13 +19419,6 @@ "dev": true, "requires": {} }, - "prettier-plugin-tailwindcss": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.4.1.tgz", - "integrity": "sha512-hwn2EiJmv8M+AW4YDkbjJ6HlZCTzLyz1QlySn9sMuKV/Px0fjwldlB7tol8GzdgqtkdPtzT3iJ4UzdnYXP25Ag==", - "dev": true, - "requires": {} - }, "pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", diff --git a/web/package.json b/web/package.json index d555cb22d27..d1d4d25c073 100644 --- a/web/package.json +++ b/web/package.json @@ -43,16 +43,12 @@ "eslint-config-prettier": "^8.6.0", "eslint-plugin-svelte": "^2.30.0", "factory.ts": "^1.3.0", - "flowbite": "^1.8.1", - "flowbite-svelte": "^0.43.1", - "flowbite-svelte-icons": "^0.3.6", "identity-obj-proxy": "^3.0.0", "jest": "^29.4.3", "jest-environment-jsdom": "^29.4.3", "postcss": "^8.4.21", "prettier": "^2.8.4", "prettier-plugin-svelte": "^2.10.1", - "prettier-plugin-tailwindcss": "^0.4.1", "svelte": "^4.0.5", "svelte-check": "^3.4.3", "svelte-jester": "^2.3.2", diff --git a/web/src/lib/components/shared-components/context-menu/menu-option.svelte b/web/src/lib/components/shared-components/context-menu/menu-option.svelte index ded60ad6dc0..d2e2eb69b74 100644 --- a/web/src/lib/components/shared-components/context-menu/menu-option.svelte +++ b/web/src/lib/components/shared-components/context-menu/menu-option.svelte @@ -1,5 +1,6 @@ diff --git a/web/src/lib/components/user-settings-page/library-list.svelte b/web/src/lib/components/user-settings-page/library-list.svelte index c3f8588e88c..0e783aad151 100644 --- a/web/src/lib/components/user-settings-page/library-list.svelte +++ b/web/src/lib/components/user-settings-page/library-list.svelte @@ -10,14 +10,14 @@ import Database from 'svelte-material-icons/Database.svelte'; import Upload from 'svelte-material-icons/Upload.svelte'; import Pulse from 'svelte-loading-spinners/Pulse.svelte'; - import { slide } from 'svelte/transition'; - import { Dropdown, DropdownDivider, DropdownItem, Helper } from 'flowbite-svelte'; - import { Icon } from 'flowbite-svelte-icons'; import LibraryImportPathsForm from '../forms/library-import-paths-form.svelte'; import LibraryScanSettingsForm from '../forms/library-scan-settings-form.svelte'; import LibraryRenameForm from '../forms/library-rename-form.svelte'; import { getBytesWithUnit } from '$lib/utils/byte-units'; + import Portal from '../shared-components/portal/portal.svelte'; + import ContextMenu from '../shared-components/context-menu/context-menu.svelte'; + import MenuOption from '../shared-components/context-menu/menu-option.svelte'; let libraries: LibraryResponseDto[] = []; @@ -40,6 +40,9 @@ let deleteAssetCount = 0; let dropdownOpen: boolean[] = []; + let showContextMenu = false; + let contextMenuPosition = { x: 0, y: 0 }; + let libraryType: LibraryType; onMount(() => { readLibraryList(); @@ -50,12 +53,22 @@ editScanSettings = null; renameLibrary = null; updateLibraryIndex = null; + showContextMenu = false; for (let i = 0; i < dropdownOpen.length; i++) { dropdownOpen[i] = false; } }; + const showMenu = ({ x, y }: MouseEvent, type: LibraryType) => { + contextMenuPosition = { x, y }; + showContextMenu = !showContextMenu; + libraryType = type; + }; + + const onMenuExit = () => { + showContextMenu = false; + }; const refreshStats = async (listIndex: number) => { const { data } = await api.libraryApi.getLibraryStatistics({ id: libraries[listIndex].id }); stats[listIndex] = data; @@ -201,6 +214,59 @@ handleError(error, 'Unable to remove offline files'); } }; + + const onRenameClicked = (index: number) => { + closeAll(); + renameLibrary = index; + updateLibraryIndex = index; + }; + + const onEditImportPathClicked = (index: number) => { + closeAll(); + editImportPaths = index; + updateLibraryIndex = index; + }; + + const onScanNewLibraryClicked = (libraryId: string) => { + closeAll(); + handleScan(libraryId); + }; + + const onScanSettingClicked = (index: number) => { + closeAll(); + editScanSettings = index; + updateLibraryIndex = index; + }; + + const onScanAllLibraryFilesClicked = (libraryId: string) => { + closeAll(); + handleScanChanges(libraryId); + }; + + const onForceScanAllLibraryFilesClicked = (libraryId: string) => { + closeAll(); + handleForceScan(libraryId); + }; + + const onRemoveOfflineFilesClicked = (libraryId: string) => { + closeAll(); + handleRemoveOffline(libraryId); + }; + + const onDeleteLibraryClicked = (index: number, library: LibraryResponseDto) => { + closeAll(); + + if (confirm(`Are you sure you want to delete ${library.name} library?`) == true) { + refreshStats(index); + if (totalCount[index] > 0) { + deleteAssetCount = totalCount[index]; + confirmDeleteLibrary = library; + } else { + deleteLibrary = library; + handleDelete(); + } + } + }; {#if confirmDeleteLibrary} @@ -260,88 +326,46 @@ - - { - closeAll(); - renameLibrary = index; - updateLibraryIndex = index; - }}>Rename - {#if library.type === LibraryType.External} - - Scan Library Files - Looks for new files - - { - closeAll(); - editImportPaths = index; - updateLibraryIndex = index; - }}>Edit Import Paths - - Manage - - - { - closeAll(); - editScanSettings = index; - updateLibraryIndex = index; - }}>Scan Settings - - Scan All Library Files - Rescan, but also refreshes modified files - - Force Scan All Library Files - Rescan, but refreshes every file - - Remove Offline Files - Any offline files are removed from Immich - - + onMenuExit()}> + onRenameClicked(index)} text="Rename" /> - if (totalCount[index] > 0) { - deleteAssetCount = totalCount[index]; - confirmDeleteLibrary = library; - } else { - deleteLibrary = library; - handleDelete(); - } - }}>Delete Library - - {/if} - + {#if libraryType === LibraryType.External} + onEditImportPathClicked(index)} text="Edit Import Paths" /> + onScanSettingClicked(index)} text="Scan Settings" /> +
+ onScanNewLibraryClicked(library.id)} + text="Scan New Library Files" + /> + onScanAllLibraryFilesClicked(library.id)} + text="Re-scan All Library Files" + subtitle={'Only refreshes modified files'} + /> + onForceScanAllLibraryFilesClicked(library.id)} + text="Force Re-scan All Library Files" + subtitle={'Refreshes every file'} + /> +
+ onRemoveOfflineFilesClicked(library.id)} + text="Remove Offline Files" + /> + onDeleteLibraryClicked(index, library)}> +

Delete library

+
+ {/if} + + + {/if} {#if renameLibrary === index} diff --git a/web/tailwind.config.cjs b/web/tailwind.config.cjs index bf534a9d0cc..cc212d25869 100644 --- a/web/tailwind.config.cjs +++ b/web/tailwind.config.cjs @@ -1,6 +1,6 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: ['./src/**/*.{html,js,svelte,ts}', './node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}'], + content: ['./src/**/*.{html,js,svelte,ts}'], darkMode: 'class', theme: { extend: { @@ -22,20 +22,6 @@ module.exports = { 'immich-dark-error': '#d32f2f', 'immich-dark-success': '#388e3c', 'immich-dark-warning': '#f57c00', - - // flowbite-svelte - primary: { - 50: '#FFF5F2', - 100: '#FFF1EE', - 200: '#FFE4DE', - 300: '#FFD5CC', - 400: '#FFBCAD', - 500: '#FE795D', - 600: '#EF562F', - 700: '#EB4F27', - 800: '#CC4522', - 900: '#A5371B', - }, }, fontFamily: { 'immich-title': ['Snowburst One', 'cursive'], @@ -45,5 +31,4 @@ module.exports = { }, }, }, - plugins: [require('flowbite/plugin')], };