mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-10-31 18:16:00 +08:00 
			
		
		
		
	chore (rewrite): filesystem elements
This commit is contained in:
		| @ -21,7 +21,7 @@ export default function(ctrl) { | ||||
|         render($page); | ||||
|  | ||||
|         // feature1: setup the breadcrumb path | ||||
|         qs($page, `[is="component-breadcrumb"]`).setAttribute("path", urlToPath(location.pathname)); | ||||
|         qs($page, `[is="component-breadcrumb"]`).setAttribute("path", urlToPath(location.pathname + location.hash)); | ||||
|  | ||||
|         // feature2: setup the childrens | ||||
|         const $main = qs($page, `[data-bind="filemanager-children"]`); | ||||
|  | ||||
| @ -45,7 +45,7 @@ class Loader extends window.HTMLElement { | ||||
|  | ||||
| customElements.define("component-loader", Loader); | ||||
| export function createLoader($parent, opts = {}) { | ||||
|     const { wait = 500 } = opts; | ||||
|     const { wait = 250 } = opts; | ||||
|     const cancel = effect(new rxjs.Observable((observer) => { | ||||
|         const $icon = createElement(` | ||||
|             <div class="component_loader"> | ||||
| @ -61,7 +61,7 @@ export function createLoader($parent, opts = {}) { | ||||
|         `); | ||||
|         const id = window.setTimeout(() => { | ||||
|             $parent.replaceChildren($icon); | ||||
|             animate($icon, { time: 1000, keyframes: opacityIn() }); | ||||
|             animate($icon, { time: 750, keyframes: opacityIn() }); | ||||
|         }, wait); | ||||
|         return () => { | ||||
|             clearTimeout(id); | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| [is="component_filesystem"] .component_filesystem { | ||||
|     padding-top: 5px; | ||||
|     padding-top: 3px; | ||||
| } | ||||
| [is="component_filesystem"] .empty { | ||||
|     text-align: center; | ||||
|  | ||||
| @ -49,15 +49,15 @@ export default async function(render) { | ||||
|             if (!!state.search) { | ||||
|                 const removeLoader = createLoader($header); | ||||
|                 return search(state.search_q).pipe(rxjs.map((files) => ({ | ||||
|                     ...rest, files, ...state, | ||||
|                     ...rest, files, ...state, read_only: true, | ||||
|                 })), removeLoader); | ||||
|             } | ||||
|             return rxjs.of({ ...rest, files, ...state }); | ||||
|             return rxjs.of({ ...rest, files, ...state, read_only: false }); | ||||
|         }))), | ||||
|         rxjs.mergeMap(({ show_hidden, files, ...rest }) => { | ||||
|             if (show_hidden === false) files = files.filter(({ name }) => name[0] !== "."); | ||||
|             console.log(rest); | ||||
|             files = sort(files, rest.sort); | ||||
|             files = sort(files, rest.sort, rest.order); | ||||
|             return rxjs.of({ ...rest, files }) | ||||
|         }), | ||||
|         removeLoader, | ||||
| @ -69,7 +69,7 @@ export default async function(render) { | ||||
|             return rxjs.of({...rest, files }); | ||||
|         }), | ||||
|         rxjs.mergeMap((obj) => refreshOnResize$.pipe(rxjs.mapTo(obj))), | ||||
|         rxjs.mergeMap(({ files, path, view }) => { // STEP1: setup the list of files | ||||
|         rxjs.mergeMap(({ files, path, view, read_only }) => { // STEP1: setup the list of files | ||||
|             $list.closest(".scroll-y").scrollTop = 0; | ||||
|             let FILE_HEIGHT, COLUMN_PER_ROW; | ||||
|             switch(view) { | ||||
| @ -99,7 +99,7 @@ export default async function(render) { | ||||
|                 $fs.appendChild(createThing({ | ||||
|                     ...file, | ||||
|                     ...createLink(file, path), | ||||
|                     view, | ||||
|                     view, read_only, | ||||
|                     n: i, | ||||
|                 })); | ||||
|             } | ||||
| @ -129,9 +129,10 @@ export default async function(render) { | ||||
|                 $listAfter.style.height = `${height - size}px`; | ||||
|             }; | ||||
|             setHeight(0); | ||||
|             // const top = ($node) => $node.getBoundingClientRect().top; | ||||
|             const top = ($node) => $node.getBoundingClientRect().top; | ||||
|             return rxjs.of({ | ||||
|                 files, | ||||
|                 read_only, | ||||
|                 path, | ||||
|                 view, | ||||
|                 currentState: 0, | ||||
| @ -140,11 +141,11 @@ export default async function(render) { | ||||
|                 FILE_HEIGHT, | ||||
|                 BLOCK_SIZE, | ||||
|                 COLUMN_PER_ROW, | ||||
|                 MARGIN: 35, // TODO: top($list) - top($list.closest(".scroll-y")); | ||||
|                 MARGIN: top($list) - top($list.closest(".scroll-y")), | ||||
|             }); | ||||
|         }), | ||||
|         rxjs.mergeMap(({ | ||||
|             files, path, view, | ||||
|             files, path, view, read_only, | ||||
|             BLOCK_SIZE, COLUMN_PER_ROW, FILE_HEIGHT, | ||||
|             MARGIN, | ||||
|             currentState, | ||||
| @ -207,7 +208,7 @@ export default async function(render) { | ||||
|                         type: "hidden", | ||||
|                     })); | ||||
|                     else $fs.appendChild(createThing({ | ||||
|                         ...file, | ||||
|                         ...file, read_only, | ||||
|                         ...createLink(file, path), | ||||
|                         view, | ||||
|                         n: i, | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
|     position: sticky; | ||||
|     top: 0; | ||||
|     z-index: 3; | ||||
|     padding: 5px 0; | ||||
|     padding: 4px 0; | ||||
|     backdrop-filter: blur(20px) saturate(2); | ||||
|     transition: 0.2s ease box-shadow; | ||||
| } | ||||
|  | ||||
| @ -16,7 +16,7 @@ import componentDelete from "./modal_delete.js"; | ||||
|  | ||||
| import { getSelection$, clearSelection } from "./state_selection.js"; | ||||
| import { getAction$, setAction } from "./state_event.js"; | ||||
| import { setState } from "./state_filesystem.js"; | ||||
| import { setState, getState$ } from "./state_filesystem.js"; | ||||
|  | ||||
| const modalOpt = { | ||||
|     withButtonsRight: "OK", | ||||
| @ -38,7 +38,7 @@ export default async function(render) { | ||||
|     componentRight(createRender(qs($page, ".action.right"))); | ||||
|  | ||||
|     effect(rxjs.fromEvent($scroll, "scroll", { passive: true }).pipe( | ||||
|         rxjs.map((e) => e.target.scrollTop > 30), | ||||
|         rxjs.map((e) => e.target.scrollTop > 12), | ||||
|         rxjs.distinctUntilChanged(), | ||||
|         rxjs.startWith(false), | ||||
|         rxjs.tap((scrolling) => scrolling | ||||
| @ -157,20 +157,20 @@ function componentRight(render) { | ||||
|                 <img class="component_icon" draggable="false" src="data:image/svg+xml;base64,${ICONS.SORT}" alt="sort" /> | ||||
|             </button> | ||||
|             <div class="component_dropdown view sort" data-target="sort"> | ||||
|               <div class="dropdown_container"> | ||||
|                 <ul> | ||||
|                   <li data-target="type"> | ||||
|                        Sort By Type | ||||
|                        <img class="component_icon" draggable="false" src="data:image/svg+xml;base64,${ICONS.CHECK}" alt="check" /> | ||||
|                   </li> | ||||
|                   <li data-target="date"> | ||||
|                       Sort By Date | ||||
|                   </li> | ||||
|                   <li data-target="name"> | ||||
|                     Sort By Name | ||||
|                   </li> | ||||
|                 </ul> | ||||
|               </div> | ||||
|                 <div class="dropdown_container"> | ||||
|                     <ul> | ||||
|                         <li data-target="type"> | ||||
|                             Sort By Type | ||||
|                             <img class="component_icon" draggable="false" src="data:image/svg+xml;base64,${ICONS.CHECK}" alt="check" /> | ||||
|                         </li> | ||||
|                         <li data-target="date"> | ||||
|                             Sort By Date | ||||
|                         </li> | ||||
|                         <li data-target="name"> | ||||
|                             Sort By Name | ||||
|                         </li> | ||||
|                     </ul> | ||||
|                 </div> | ||||
|             </div> | ||||
|         `))), | ||||
|         rxjs.mergeMap(($page) => rxjs.merge( | ||||
| @ -208,18 +208,23 @@ function componentRight(render) { | ||||
|                     } | ||||
|                     const $lis = qsa($page, `.dropdown_container li`); | ||||
|                     return onClick($lis).pipe( | ||||
|                         rxjs.tap(($el) => { | ||||
|                         rxjs.first(), | ||||
|                         rxjs.mergeMap(($el) => getState$().pipe(rxjs.first(), rxjs.map((state) => ({ | ||||
|                             order: state.order, | ||||
|                             $el, | ||||
|                         })))), | ||||
|                         rxjs.tap(({ $el, order }) => { | ||||
|                             setState( | ||||
|                                 "sort", $el.getAttribute("data-target"), | ||||
|                                 "order", !!$el.querySelector("img") ? "asc" : "des", | ||||
|                                 "order", order === "asc" ? "des" : "asc", | ||||
|                             ); | ||||
|                             [...$lis].map(($li) => { | ||||
|                                 const $img = $li.querySelector("img"); | ||||
|                                 if ($img) $img.remove(); | ||||
|                             }); | ||||
|                             $el.appendChild(createElement(`<img class="component_icon" src="data:image/svg+xml;base64,${ICONS.CHECK}" alt="check" />`)); | ||||
|                             $sort.classList.remove("active"); | ||||
|                         }), | ||||
|                         rxjs.tap(() => $sort.classList.remove("active")), | ||||
|                     ); | ||||
|                 }), | ||||
|             ), | ||||
|  | ||||
| @ -1,85 +1,94 @@ | ||||
| import { extname } from "../../lib/path.js"; | ||||
|  | ||||
| export function sort(files, type) { | ||||
|     if (type === "name") { | ||||
|         return sortByName(files); | ||||
|     } else if (type === "date") { | ||||
|         return sortByDate(files); | ||||
|     } else { | ||||
|         return sortByType(files); | ||||
| export function sort(files, type, order) { | ||||
|     switch(type) { | ||||
|     case "name": return sortByName(files, order); | ||||
|     case "date": return sortByDate(files, order); | ||||
|     default: return sortByType(files, order); | ||||
|     } | ||||
| }; | ||||
| } | ||||
|  | ||||
| function sortByType(files, order) { | ||||
|     let tmp; | ||||
|     return files.sort(function(fileA, fileB) { | ||||
|         tmp = _moveLoadingDownward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         tmp = _moveFolderUpward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         tmp = _moveHiddenFilesDownward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         const faname = fileA.name.toLowerCase(); | ||||
|         const fbname = fileB.name.toLowerCase(); | ||||
|  | ||||
|         const aExt = extname(faname); | ||||
|         const bExt = extname(fbname); | ||||
|  | ||||
|         if (aExt === bExt) return sortString(faname, fbname, order); | ||||
|         return sortString(aExt, bExt, order); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function sortByName(files, order) { | ||||
|     let tmp; | ||||
|     return files.sort(function(fileA, fileB) { | ||||
|         tmp = _moveLoadingDownward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         tmp = _moveFolderUpward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         tmp = _moveHiddenFilesDownward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         return sortString(fileA.name.toLowerCase(), fileB.name.toLowerCase(), order); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function sortByDate(files, order) { | ||||
|     return files.sort(function(fileA, fileB) { | ||||
|         if (fileB.time === fileA.time) { | ||||
|             return sortString(fileA.name, fileB.name, order); | ||||
|         } | ||||
|         return sortNumber(fileA.time, fileB.time, order); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function sortString(a, b, order) { | ||||
|     if (order === "asc") return a > b ? +1 : -1; | ||||
|     return a < b ? +1 : -1; | ||||
| } | ||||
|  | ||||
| function sortNumber(a, b, order) { | ||||
|     if (order === "asc") return b - a; | ||||
|     return a - b; | ||||
| } | ||||
|  | ||||
| function _moveLoadingDownward(fileA, fileB) { | ||||
|     if (fileA.icon === "loading" && fileB.icon !== "loading") { | ||||
|         return +1; | ||||
|     } else if (fileA.icon !== "loading" && fileB.icon === "loading") { | ||||
|         return -1; | ||||
|     } | ||||
|     const aIsLoading = fileA.icon === "loading"; | ||||
|     const bIsLoading = fileB.icon === "loading"; | ||||
|  | ||||
|     if (aIsLoading && !bIsLoading) return +1; | ||||
|     else if (!aIsLoading && bIsLoading) return -1; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| function _moveFolderUpward(fileA, fileB) { | ||||
|     if (["directory", "link"].indexOf(fileA.type) === -1 && | ||||
|         ["directory", "link"].indexOf(fileB.type) !== -1) { | ||||
|         return +1; | ||||
|     } else if (["directory", "link"].indexOf(fileA.type) !== -1 && | ||||
|                ["directory", "link"].indexOf(fileB.type) === -1) { | ||||
|         return -1; | ||||
|     } | ||||
|     const aIsDirectory = ["directory", "link"].indexOf(fileA.type) !== -1; | ||||
|     const bIsDirectory = ["directory", "link"].indexOf(fileB.type) !== -1; | ||||
|  | ||||
|     if (!aIsDirectory && bIsDirectory) return +1; | ||||
|     else if (aIsDirectory && !bIsDirectory) return -1; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| function _moveHiddenFilesDownward(fileA, fileB) { | ||||
|     if (fileA.name[0] === "." && fileB.name[0] !== ".") return +1; | ||||
|     else if (fileA.name[0] !== "." && fileB.name[0] === ".") return -1; | ||||
|     const aIsHidden = fileA.name[0] === "."; | ||||
|     const bIsHidden = fileB.name[0] === "."; | ||||
|  | ||||
|     if (aIsHidden && !bIsHidden) return +1; | ||||
|     if (!aIsHidden && bIsHidden) return -1; | ||||
|     return 0; | ||||
| } | ||||
| function sortByType(files) { | ||||
|     return files.sort((fileA, fileB) => { | ||||
|         let tmp = _moveLoadingDownward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         tmp = _moveFolderUpward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         tmp = _moveHiddenFilesDownward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         const aExt = extname(fileA.name.toLowerCase()); | ||||
|         const bExt = extname(fileB.name.toLowerCase()); | ||||
|  | ||||
|         if (fileA.name.toLowerCase() === fileB.name.toLowerCase()) { | ||||
|             return fileA.name > fileB.name ? +1 : -1; | ||||
|         } else { | ||||
|             if (aExt !== bExt) return aExt > bExt ? +1 : -1; | ||||
|             else return fileA.name.toLowerCase() > fileB.name.toLowerCase() ? +1 : -1; | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| function sortByName(files) { | ||||
|     return files.sort((fileA, fileB) => { | ||||
|         let tmp = _moveLoadingDownward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         tmp = _moveFolderUpward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         tmp = _moveHiddenFilesDownward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         if (fileA.name.toLowerCase() === fileB.name.toLowerCase()) { | ||||
|             return fileA.name > fileB.name ? +1 : -1; | ||||
|         } | ||||
|         return fileA.name.toLowerCase() > fileB.name.toLowerCase() ? +1 : -1; | ||||
|     }); | ||||
| } | ||||
| function sortByDate(files) { | ||||
|     return files.sort((fileA, fileB) => { | ||||
|         const tmp = _moveLoadingDownward(fileA, fileB); | ||||
|         if (tmp !== 0) return tmp; | ||||
|  | ||||
|         if (fileB.time === fileA.time) { | ||||
|             return fileA.name > fileB.name ? +1 : -1; | ||||
|         } | ||||
|         return fileB.time - fileA.time; | ||||
|     }); | ||||
| } | ||||
|  | ||||
| @ -46,6 +46,7 @@ export function createThing({ | ||||
|     // permissions = {} | ||||
|     view = "", | ||||
|     n = 0, | ||||
|     read_only = false, | ||||
| }) { | ||||
|     const $thing = $tmpl.cloneNode(true); | ||||
|     assert.type($thing, window.HTMLElement); | ||||
| @ -60,7 +61,12 @@ export function createThing({ | ||||
|     $thing.classList.add("view-" + view); | ||||
|     $time.textContent = formatTime(new Date(time)); | ||||
|     sideEffectSelection($thing, isSelected(n)); | ||||
|     if (type === "hidden") $thing.classList.add("hidden"); | ||||
|  | ||||
|     if (read_only === true) return $thing; | ||||
|     else if (type === "hidden") { | ||||
|         $thing.classList.add("hidden"); | ||||
|         return $thing; | ||||
|     } | ||||
|  | ||||
|     $thing.querySelector(".component_checkbox").onclick = function(e) { | ||||
|         e.preventDefault(); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 MickaelK
					MickaelK