|
102 | 102 | transition: .3s; |
103 | 103 | border-radius: var(--siz-radius1); |
104 | 104 | overflow-x: hidden; |
105 | | - height: calc(100vh - 66px); |
| 105 | + height: calc(100vh - 52px); |
106 | 106 | } |
107 | 107 |
|
108 | 108 | [flap-sidenav] small { |
|
541 | 541 | opacity: 0.7; |
542 | 542 | font-size: 14px; |
543 | 543 | padding: .5em .7em; |
544 | | - width: 70px; |
545 | 544 | gap: 5px; |
546 | 545 | position: relative; |
| 546 | + width: fit-content; |
547 | 547 |
|
548 | 548 | &:hover>.dropup-content.nested { |
549 | 549 | display: flex; |
|
562 | 562 |
|
563 | 563 | &>a { |
564 | 564 | width: calc(100% - 1.35em); |
| 565 | + |
565 | 566 | &>span { |
566 | | - transform: scale(0.9); |
| 567 | + transform: scale(0.9); |
567 | 568 | } |
568 | 569 | } |
569 | 570 | } |
|
592 | 593 | color: var(--colors-text-section); |
593 | 594 | background-color: var(--col-bg3); |
594 | 595 | border-radius: var(--siz-radius1); |
| 596 | + |
595 | 597 | &>span { |
596 | 598 | transform: none; |
597 | 599 | } |
|
961 | 963 | <div flap-nav> |
962 | 964 | <div class="nowid" onclick="refresh()"> |
963 | 965 | <a class="dropdownerthebob"><span class="material-symbols-rounded " id="ogrefreshbtn">refresh</span> |
964 | | - Refresh</a> |
| 966 | + </a> |
965 | 967 | </div> |
966 | 968 | <div class="nowid flappsearch" id="fileapptitledis"> |
967 | 969 | <div id="filetools"> |
|
1343 | 1345 | } |
1344 | 1346 | } |
1345 | 1347 |
|
1346 | | - var currentPath = 'Downloads/', nowfile, flmode = 'grid', onlyshow = false, fileToSelect = null, currentProc = null, slfileID = null; |
| 1348 | + var currentPath = 'Downloads/', nowfile, flmode = 'grid', onlyshow = false, fileToSelect = null, currentProc = null, slfileID = null, currentSort = "name_asc"; |
1347 | 1349 | var fllist = document.getElementById("filelist"); |
1348 | 1350 | var fdlist; |
1349 | 1351 | var binmode = false; |
|
1451 | 1453 | dropupDiv.innerHTML = ""; |
1452 | 1454 | const dropupContentDiv = document.createElement("div"); |
1453 | 1455 | dropupContentDiv.className = "dropup-content"; |
1454 | | - const moreToolsDiv = document.getElementById("moretoolsdropdwn"); |
1455 | | - moreToolsDiv.innerHTML = ""; |
1456 | 1456 | const pathSegments = folderPath.split('/').filter(Boolean); |
1457 | 1457 | const isSystemFolder = folderPath === "System/" || folderPath === ""; |
1458 | 1458 | const isRootLevel = pathSegments.length <= 1; |
|
1521 | 1521 | }, |
1522 | 1522 | icon: flmode === 'grid' ? 'view_list' : 'grid_view', |
1523 | 1523 | label: flmode === 'grid' ? 'List View' : 'Grid View' |
| 1524 | + }, |
| 1525 | + { |
| 1526 | + id: "toggleSort", |
| 1527 | + title: "Sort files", |
| 1528 | + onclick: async function () { |
| 1529 | + const options = [ |
| 1530 | + { label: "Time ↑", mode: "time_asc", icon: "schedule" }, |
| 1531 | + { label: "Time ↓", mode: "time_desc", icon: "schedule" }, |
| 1532 | + { label: "Name A-Z", mode: "name_asc", icon: "sort_by_alpha" }, |
| 1533 | + { label: "Name Z-A", mode: "name_desc", icon: "sort_by_alpha" }, |
| 1534 | + { label: "Type", mode: "type", icon: "category" } |
| 1535 | + ]; |
| 1536 | + const selected = await window.parent.showDropdownModal( |
| 1537 | + "Sort files", |
| 1538 | + "Choose a sorting method:", |
| 1539 | + options.map(o => o.label) |
| 1540 | + ); |
| 1541 | + const choice = options.find(o => o.label === selected); |
| 1542 | + if (choice) { |
| 1543 | + currentSort = choice.mode; |
| 1544 | + this.title = `Sort: ${choice.label}`; |
| 1545 | + this.innerHTML = `<span class="material-symbols-rounded">${choice.icon}</span> <b>${choice.label}</b>`; |
| 1546 | + } |
| 1547 | + listFiles(); |
| 1548 | + }, |
| 1549 | + icon: (() => { |
| 1550 | + const mapping = { |
| 1551 | + time_asc: "schedule", |
| 1552 | + time_desc: "schedule", |
| 1553 | + name_asc: "sort_by_alpha", |
| 1554 | + name_desc: "sort_by_alpha", |
| 1555 | + type: "category" |
| 1556 | + }; |
| 1557 | + return mapping[currentSort] || "sort"; |
| 1558 | + })(), |
| 1559 | + label: (() => { |
| 1560 | + const mapping = { |
| 1561 | + time_asc: "Time ↑", |
| 1562 | + time_desc: "Time ↓", |
| 1563 | + name_asc: "Name A-Z", |
| 1564 | + name_desc: "Name Z-A", |
| 1565 | + type: "Type" |
| 1566 | + }; |
| 1567 | + return mapping[currentSort] || "Sort files"; |
| 1568 | + })() |
1524 | 1569 | } |
1525 | 1570 | ] |
1526 | 1571 | }; |
1527 | 1572 |
|
1528 | | - const actionLinks = []; |
1529 | | - |
1530 | 1573 | for (const [groupName, group] of Object.entries(groups)) { |
1531 | 1574 | const groupToggle = document.createElement("a"); |
1532 | 1575 | groupToggle.classList.add("dropdownerthebob"); |
|
1543 | 1586 | link.innerHTML = `<span class="material-symbols-rounded">${icon}</span> <b>${label}</b>`; |
1544 | 1587 | link.id = `topbarAction-${id}`; |
1545 | 1588 | if (disabled) link.classList.add("disabled"); |
1546 | | - actionLinks.push(link); |
1547 | 1589 | groupMenu.appendChild(link); |
1548 | 1590 | } |
1549 | 1591 | } |
1550 | 1592 |
|
1551 | 1593 | dropupDiv.appendChild(dropupContentDiv); |
1552 | | - |
1553 | 1594 | if (!silly) { |
1554 | 1595 | currentPath = folderPath; |
1555 | 1596 | updpth(); |
|
1576 | 1617 | function dragfl(ev, obj) { |
1577 | 1618 | ev.dataTransfer.setData("Text", obj.getAttribute('unid')); |
1578 | 1619 | } |
1579 | | - |
1580 | | - let cachedFiles = {}; |
1581 | | - var PrevPath = "Downloads"; |
| 1620 | + let cachedFiles = {}; var PrevPath = "Downloads"; |
1582 | 1621 |
|
1583 | 1622 | async function listFiles(folderName = currentPath, gen) { |
1584 | 1623 | if (sessiontype != "opener" && sessiontype != "saveas") { |
1585 | 1624 | myWindow.setTitle(removeEndSlash(folderName) + " - Files"); |
1586 | 1625 | } |
1587 | | - |
1588 | | - if (sessiontype == "directory") { |
1589 | | - return; |
1590 | | - } |
| 1626 | + if (sessiontype == "directory") return; |
1591 | 1627 | const startTime = performance.now(); |
1592 | 1628 | if (currentPath == folderName && gen) { |
1593 | 1629 | const previousFiles = cachedFiles[currentPath] || []; |
1594 | 1630 | const currentFiles = await window.parent.getFileNamesByFolder(folderName); |
1595 | | - |
1596 | | - if (JSON.stringify(previousFiles) === JSON.stringify(currentFiles)) { |
1597 | | - return; |
1598 | | - } |
| 1631 | + if (JSON.stringify(previousFiles) === JSON.stringify(currentFiles)) return; |
1599 | 1632 | } |
1600 | 1633 | fllist.innerHTML = ``; |
1601 | 1634 | await window.parent.updateMemoryData(); |
|
1604 | 1637 | let parts = path.split('/').filter(p => p !== ''); |
1605 | 1638 | for (let i = 0; i < parts.length; i++) { |
1606 | 1639 | let key = parts[i] + '/'; |
1607 | | - if (obj[key]) { |
1608 | | - obj = obj[key]; |
1609 | | - } else { |
1610 | | - return null; |
1611 | | - } |
| 1640 | + if (obj[key]) obj = obj[key]; |
| 1641 | + else return null; |
1612 | 1642 | } |
1613 | 1643 | return obj; |
1614 | 1644 | } |
1615 | 1645 |
|
1616 | 1646 | const folder = findFolder(folderName, window.parent.memory.root); |
1617 | | - if (folder) { |
1618 | | - PrevPath = folder; |
1619 | | - fillDropup(folderName); |
1620 | | - |
1621 | | - const filesInFolder = await window.parent.getAllItemsInFolder(folderName); |
1622 | | - if (filesInFolder) { |
1623 | | - if (filesInFolder.length > 0) { |
1624 | | - document.getElementById("fileinfobn").innerHTML = filesInFolder.length + " items"; |
1625 | | - if (!gen) { |
1626 | | - const previousFiles = cachedFiles[currentPath] || []; |
1627 | | - const currentFileNames = new Set(filesInFolder.map(file => file.name)); |
1628 | | - |
1629 | | - const removedFiles = previousFiles.filter(file => !currentFileNames.has(file.name)); |
1630 | | - const addedFiles = filesInFolder.filter(file => !previousFiles.some(prev => prev.name === file.name)); |
1631 | | - |
1632 | | - removedFiles.forEach(removedFile => { |
1633 | | - const fileElement = document.querySelector(`[title^="${removedFile.name}"]`); |
1634 | | - fileElement?.remove(); |
1635 | | - }); |
1636 | | - |
1637 | | - for (const newFile of addedFiles) { |
1638 | | - await createFileElement(newFile); |
1639 | | - } |
| 1647 | + if (!folder) { |
| 1648 | + console.error("No such path."); |
| 1649 | + listFiles(PrevPath); |
| 1650 | + return; |
| 1651 | + } |
1640 | 1652 |
|
1641 | | - } else { |
1642 | | - cachedFiles[currentPath] = filesInFolder; |
1643 | | - } |
1644 | | - } else { |
1645 | | - fllist.innerHTML = `<center class='thisfolderisempty'><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="74.20199" height="94.1023" viewBox="0,0,74.20199,94.1023"><g transform="translate(-224.61774,-142.87893)"><g data-paper-data="{"isPaintingLayer":true}" fill-rule="nonzero" stroke="#ffffff" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" style="mix-blend-mode: normal"><path style="animation: headsad .5s 2;" d="M227.11774,158.26119c0,-7.11468 5.76758,-12.88226 12.88226,-12.88226c7.11468,0 12.88226,5.76758 12.88226,12.88226c0,7.11468 -5.76758,12.88226 -12.88226,12.88226c-7.11468,0 -12.88226,-5.76758 -12.88226,-12.88226z" fill="none" stroke-width="5" stroke-linecap="butt"/><path d="M244.56247,233.94447l9.12493,-32.20565l-8.58817,-28.98508" fill="none" stroke-width="5" stroke-linecap="round"/><path d="M253.6874,202.81234l17.71311,31.66888" fill="none" stroke-width="5" stroke-linecap="round"/><path d="M246.17275,178.6581l-7.51465,27.37481" fill="none" stroke-width="5" stroke-linecap="round"/><path d="M250.46684,179.73163l28.44833,-12.3455" fill="none" stroke-width="5" stroke-linecap="round"/><path d="M260.82196,192.96703l-1.81137,-23.54791l37.99776,-2.9229l1.81138,23.54791z" fill="#aa8b00" stroke-width="0" stroke-linecap="butt"/><path onclick="ntxSession.send("sysUI.say",'You found it :3')" d="M256.80524,189.29958l2.20535,-19.88046l37.99776,-2.9229l-2.20535,19.53118z" fill="#ffcf00" stroke-width="0" stroke-linecap="butt"/><path d="M279.06646,168.81576l-0.1513,-1.42964" fill="none" stroke-width="5" stroke-linecap="round"/></g></g></svg><br>This folder is empty.</center>`; |
1646 | | - } |
1647 | | - } |
| 1653 | + PrevPath = folder; |
| 1654 | + fillDropup(folderName); |
| 1655 | + const filesInFolder = await window.parent.getAllItemsInFolder(folderName); |
1648 | 1656 |
|
1649 | | - (document.getElementById("listfilesloader")) ? document.getElementById("listfilesloader").remove() : null; |
1650 | | - } else { |
1651 | | - console.error("No such path.") |
1652 | | - listFiles(PrevPath); |
| 1657 | + if (!filesInFolder || filesInFolder.length === 0) { |
| 1658 | + fllist.innerHTML = `<center class='thisfolderisempty'><svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="74.20199" height="94.1023" viewBox="0,0,74.20199,94.1023"><g transform="translate(-224.61774,-142.87893)"><g data-paper-data="{"isPaintingLayer":true}" fill-rule="nonzero" stroke="#ffffff" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0" style="mix-blend-mode: normal"><path style="animation: headsad .5s 2;" d="M227.11774,158.26119c0,-7.11468 5.76758,-12.88226 12.88226,-12.88226c7.11468,0 12.88226,5.76758 12.88226,12.88226c0,7.11468 -5.76758,12.88226 -12.88226,12.88226c-7.11468,0 -12.88226,-5.76758 -12.88226,-12.88226z" fill="none" stroke-width="5" stroke-linecap="butt"/><path d="M244.56247,233.94447l9.12493,-32.20565l-8.58817,-28.98508" fill="none" stroke-width="5" stroke-linecap="round"/><path d="M253.6874,202.81234l17.71311,31.66888" fill="none" stroke-width="5" stroke-linecap="round"/><path d="M246.17275,178.6581l-7.51465,27.37481" fill="none" stroke-width="5" stroke-linecap="round"/><path d="M250.46684,179.73163l28.44833,-12.3455" fill="none" stroke-width="5" stroke-linecap="round"/><path d="M260.82196,192.96703l-1.81137,-23.54791l37.99776,-2.9229l1.81138,23.54791z" fill="#aa8b00" stroke-width="0" stroke-linecap="butt"/><path onclick="ntxSession.send("sysUI.say",'You found it :3')" d="M256.80524,189.29958l2.20535,-19.88046l37.99776,-2.9229l-2.20535,19.53118z" fill="#ffcf00" stroke-width="0" stroke-linecap="butt"/><path d="M279.06646,168.81576l-0.1513,-1.42964" fill="none" stroke-width="5" stroke-linecap="round"/></g></g></svg><br>This folder is empty.</center>`; |
| 1659 | + return; |
1653 | 1660 | } |
| 1661 | + |
| 1662 | + document.getElementById("fileinfobn").innerHTML = filesInFolder.length + " items"; |
| 1663 | + let sortedFiles = [...filesInFolder]; |
| 1664 | + switch (currentSort) { |
| 1665 | + case "time_asc": |
| 1666 | + sortedFiles.sort((a, b) => { |
| 1667 | + const t1 = a.metadata?.datetime ? new Date(a.metadata.datetime) : 0; |
| 1668 | + const t2 = b.metadata?.datetime ? new Date(b.metadata.datetime) : 0; |
| 1669 | + return t1 - t2; |
| 1670 | + }); |
| 1671 | + break; |
| 1672 | + case "time_desc": |
| 1673 | + sortedFiles.sort((a, b) => { |
| 1674 | + const t1 = a.metadata?.datetime ? new Date(a.metadata.datetime) : 0; |
| 1675 | + const t2 = b.metadata?.datetime ? new Date(b.metadata.datetime) : 0; |
| 1676 | + return t2 - t1; |
| 1677 | + }); |
| 1678 | + break; |
| 1679 | + case "name_asc": |
| 1680 | + sortedFiles.sort((a, b) => a.name.localeCompare(b.name)); |
| 1681 | + break; |
| 1682 | + case "name_desc": |
| 1683 | + sortedFiles.sort((a, b) => b.name.localeCompare(a.name)); |
| 1684 | + break; |
| 1685 | + case "type": |
| 1686 | + sortedFiles.sort((a, b) => { |
| 1687 | + if (a.type === b.type) return a.name.localeCompare(b.name); |
| 1688 | + return a.type === 'folder' ? -1 : 1; |
| 1689 | + }); |
| 1690 | + break; |
| 1691 | + } |
| 1692 | + |
| 1693 | + if (!gen) { |
| 1694 | + const previousFiles = cachedFiles[currentPath] || []; |
| 1695 | + const currentFileNames = new Set(sortedFiles.map(f => f.name)); |
| 1696 | + const removedFiles = previousFiles.filter(f => !currentFileNames.has(f.name)); |
| 1697 | + const addedFiles = sortedFiles.filter(f => !previousFiles.some(prev => prev.name === f.name)); |
| 1698 | + removedFiles.forEach(f => document.querySelector(`[title^="${f.name}"]`)?.remove()); |
| 1699 | + for (const newFile of addedFiles) await createFileElement(newFile); |
| 1700 | + } else { |
| 1701 | + cachedFiles[currentPath] = sortedFiles; |
| 1702 | + for (const file of sortedFiles) await createFileElement(file); |
| 1703 | + } (document.getElementById("listfilesloader")) ? document.getElementById("listfilesloader").remove() : null; |
1654 | 1704 | } |
| 1705 | + |
| 1706 | + |
1655 | 1707 | async function createFileElement(file) { |
1656 | 1708 | const fileElement = document.createElement('div'); |
1657 | 1709 | fileElement.classList.add('file'); |
|
0 commit comments