flea-qml 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +511 -2
- package/THIRD-PARTY-NOTICES.md +29 -0
- package/demos/App.java +5 -0
- package/demos/Dockerfile +4 -0
- package/demos/Main.kt +3 -0
- package/demos/Program.cs +1 -0
- package/demos/README.md +12 -0
- package/demos/app.dart +3 -0
- package/demos/app.deb +0 -0
- package/demos/app.js +1 -0
- package/demos/backup.tar +0 -0
- package/demos/budget.xlsx +0 -0
- package/demos/build.sh +2 -0
- package/demos/bundle.zip +0 -0
- package/demos/clip.mp4 +0 -0
- package/demos/data.sqlite +0 -0
- package/demos/disk.iso +0 -0
- package/demos/engine.cpp +5 -0
- package/demos/firmware.bin +0 -0
- package/demos/flake.nix +4 -0
- package/demos/folder/inside.txt +1 -0
- package/demos/font.ttf +0 -0
- package/demos/index.html +5 -0
- package/demos/index.php +2 -0
- package/demos/init.lua +1 -0
- package/demos/letter.docx +0 -0
- package/demos/lib.rs +3 -0
- package/demos/main.c +6 -0
- package/demos/main.h +3 -0
- package/demos/math-and-diagrams.md +200 -0
- package/demos/notes.tar.gz +0 -0
- package/demos/notes.txt +3 -0
- package/demos/photo.png +0 -0
- package/demos/program +2 -0
- package/demos/report.pdf +32 -0
- package/demos/script.py +1 -0
- package/demos/server.go +7 -0
- package/demos/settings.json +4 -0
- package/demos/slides.pptx +0 -0
- package/demos/song.mp3 +0 -0
- package/demos/style.css +4 -0
- package/demos/tool.rb +1 -0
- package/demos/types.ts +2 -0
- package/docs/pele.md +23 -0
- package/docs/protocol.md +3420 -0
- package/docs/temml.md +63 -0
- package/index.js +107 -0
- package/package.json +34 -4
- package/src/archive.js +407 -0
- package/src/archiveops.js +728 -0
- package/src/backend.js +369 -0
- package/src/bulkrename.js +95 -0
- package/src/clip-host.js +76 -0
- package/src/clip.js +462 -0
- package/src/code.js +168 -0
- package/src/compare.js +74 -0
- package/src/create.js +128 -0
- package/src/dirsize.js +147 -0
- package/src/figure-svg.js +530 -0
- package/src/figure-thread.js +23 -0
- package/src/figure.js +132 -0
- package/src/find.js +55 -0
- package/src/flea.js +39 -0
- package/src/fsinfo.js +39 -0
- package/src/highlight.js +141 -0
- package/src/html.js +52 -0
- package/src/kinds.js +89 -0
- package/src/listing.js +130 -0
- package/src/markdown-html.js +317 -0
- package/src/mathml.js +186 -0
- package/src/menu.js +180 -0
- package/src/meta.js +135 -0
- package/src/office.js +810 -0
- package/src/order.js +100 -0
- package/src/peek.js +49 -0
- package/src/pele-wrapper.js +695 -0
- package/src/permissions.js +180 -0
- package/src/places.js +313 -0
- package/src/preview-language.js +10 -0
- package/src/terminal-server.js +95 -0
- package/src/terminal-shell.js +26 -0
- package/src/transfer.js +669 -0
- package/src/trash-record.js +41 -0
- package/src/trash.js +210 -0
- package/src/trashbrowse.js +327 -0
- package/src/uistate.js +393 -0
- package/src/uistore.js +168 -0
- package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
- package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
- package/src/vendor/LICENSES/MIT-katex.txt +21 -0
- package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
- package/src/vendor/LICENSES/MIT-pele.txt +40 -0
- package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
- package/src/vendor/LICENSES/MIT-temml.txt +21 -0
- package/src/vendor/pele.js +145 -0
- package/src/vendor/temml.mjs +14708 -0
- package/src/watch.js +98 -0
- package/src/wayland/client.js +109 -0
- package/src/wayland/protocol.js +55 -0
- package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
- package/src/wayland/protocols/wayland.xml +3248 -0
- package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
- package/src/wayland/resource-io.js +6 -0
- package/src/wayland/socket-discovery.js +26 -0
- package/src/wayland/transport-posix.js +120 -0
- package/src/wayland/transport-win32.js +11 -0
- package/src/wayland/transport.js +3 -0
- package/src/wayland/win32-resources.js +80 -0
- package/src/wayland/win32-wire.js +62 -0
- package/test/archive.test.js +80 -0
- package/test/bench-markdown-scroll.mjs +190 -0
- package/test/clip-host.test.js +113 -0
- package/test/code-preview.test.js +35 -0
- package/test/compare-ui-paths.test.js +24 -0
- package/test/compare.test.js +54 -0
- package/test/delete-trash.test.js +67 -0
- package/test/dirsize.test.js +138 -0
- package/test/file-ops.test.js +307 -0
- package/test/file-url.test.js +24 -0
- package/test/find-contents.test.js +161 -0
- package/test/find-input.test.js +66 -0
- package/test/fixtures/pele-parity.json +1006 -0
- package/test/highlight-launcher.test.js +35 -0
- package/test/html-preview.test.js +22 -0
- package/test/input.test.js +15 -0
- package/test/keymap.test.js +26 -0
- package/test/language-icons.test.js +36 -0
- package/test/launcher.test.js +51 -0
- package/test/manual-archive-here-ui.mjs +47 -0
- package/test/manual-code-scroll.mjs +28 -0
- package/test/manual-column-scroll.mjs +24 -0
- package/test/manual-compare-ui.mjs +20 -0
- package/test/manual-find-status.mjs +37 -0
- package/test/manual-folder-focus.mjs +63 -0
- package/test/manual-html-security.mjs +23 -0
- package/test/manual-html-ui.mjs +30 -0
- package/test/manual-syntax-preview.mjs +26 -0
- package/test/manual-terminal-lifecycle.mjs +42 -0
- package/test/manual-terminal-navigation.mjs +48 -0
- package/test/manual-terminal-ui.mjs +47 -0
- package/test/manual-trash-ui.mjs +86 -0
- package/test/markdown-diagrams.test.js +93 -0
- package/test/markdown-html.test.js +105 -0
- package/test/mathml.test.js +92 -0
- package/test/menu-transfer.test.js +57 -0
- package/test/office-preview.test.js +154 -0
- package/test/pele-parity.test.js +28 -0
- package/test/places.test.js +134 -0
- package/test/preview-keys.test.js +60 -0
- package/test/preview-language.test.js +22 -0
- package/test/status-filename.test.js +20 -0
- package/test/transfer-replace-merge.test.js +187 -0
- package/test/trash-address.test.js +23 -0
- package/test/trash-view.test.js +37 -0
- package/test/trashbrowse.test.js +135 -0
- package/ui/AboutFacts.qml +78 -0
- package/ui/ArchiveCards.qml +95 -0
- package/ui/ArchiveCompressDialog.qml +378 -0
- package/ui/ArchiveHereConfirm.qml +127 -0
- package/ui/ArchivePasswordDialog.qml +257 -0
- package/ui/Backend.qml +775 -0
- package/ui/BulkOldNames.qml +47 -0
- package/ui/BulkRenameDialog.qml +380 -0
- package/ui/CardFrame.qml +67 -0
- package/ui/CardScroll.qml +79 -0
- package/ui/CheckBox.qml +73 -0
- package/ui/ChromeBar.qml +360 -0
- package/ui/ChromeButton.qml +131 -0
- package/ui/ChromeModes.qml +43 -0
- package/ui/CodeLines.qml +256 -0
- package/ui/CodeRefusal.qml +52 -0
- package/ui/CollideConfirm.qml +147 -0
- package/ui/CollideHost.qml +167 -0
- package/ui/ColumnPane.qml +525 -0
- package/ui/ColumnRow.qml +380 -0
- package/ui/ColumnsArea.qml +594 -0
- package/ui/ColumnsLanding.qml +147 -0
- package/ui/CompareView.qml +321 -0
- package/ui/ContextMenu.qml +743 -0
- package/ui/ConvertDialog.qml +456 -0
- package/ui/CountedWorker.qml +7 -0
- package/ui/Crumb.qml +64 -0
- package/ui/CrumbDrop.qml +25 -0
- package/ui/CsvTable.qml +394 -0
- package/ui/CursorMark.qml +41 -0
- package/ui/DefaultClaim.qml +130 -0
- package/ui/DeviceLock.qml +47 -0
- package/ui/DeviceMounts.qml +540 -0
- package/ui/DialogButton.qml +150 -0
- package/ui/DialogField.qml +147 -0
- package/ui/DialogHeader.qml +31 -0
- package/ui/DialogScrim.qml +20 -0
- package/ui/DialogTitle.qml +37 -0
- package/ui/Divider.qml +9 -0
- package/ui/DropInto.qml +126 -0
- package/ui/DropTarget.qml +35 -0
- package/ui/DropboxMark.qml +60 -0
- package/ui/EmptyState.qml +150 -0
- package/ui/EscapeHint.qml +11 -0
- package/ui/FactsTable.qml +54 -0
- package/ui/FastScrollHandler.qml +476 -0
- package/ui/FatNamesConfirm.qml +157 -0
- package/ui/Favourites.qml +143 -0
- package/ui/FigureService.qml +120 -0
- package/ui/FileDrag.qml +267 -0
- package/ui/FilterStrip.qml +133 -0
- package/ui/FitMetrics.qml +22 -0
- package/ui/FlashDriveRows.qml +137 -0
- package/ui/FlashHost.qml +72 -0
- package/ui/FlashImageRow.qml +104 -0
- package/ui/FlashRunner.qml +119 -0
- package/ui/FlashStepRow.qml +172 -0
- package/ui/FlashStrip.qml +38 -0
- package/ui/FlashView.qml +397 -0
- package/ui/FleaMark.qml +88 -0
- package/ui/FlyoutFade.qml +23 -0
- package/ui/FontPane.qml +170 -0
- package/ui/Glass.qml +114 -0
- package/ui/GlassTagger.qml +59 -0
- package/ui/Glyph.qml +64 -0
- package/ui/GlyphSolid.qml +22 -0
- package/ui/GridArea.qml +664 -0
- package/ui/GridTile.qml +325 -0
- package/ui/GvfsBridge.qml +164 -0
- package/ui/Header.qml +433 -0
- package/ui/HoverTimers.qml +39 -0
- package/ui/HtmlClip.qml +30 -0
- package/ui/HtmlPane.qml +63 -0
- package/ui/HyprlandMark.qml +45 -0
- package/ui/Ipc.qml +1005 -0
- package/ui/IpcControls.qml +7 -0
- package/ui/IpcMenuState.qml +48 -0
- package/ui/IpcPreviewState.qml +185 -0
- package/ui/JumpPath.qml +51 -0
- package/ui/KeymapSheet.qml +561 -0
- package/ui/KeymapSheetResult.qml +89 -0
- package/ui/KindStack.qml +40 -0
- package/ui/LangMark.qml +51 -0
- package/ui/LangMarkLoader.qml +26 -0
- package/ui/List.qml +480 -0
- package/ui/LoadingState.qml +54 -0
- package/ui/LocalSend.qml +56 -0
- package/ui/LocalSendMark.qml +73 -0
- package/ui/MarkdownBlockView.qml +311 -0
- package/ui/MarkdownBlocks.qml +35 -0
- package/ui/MarkdownFigure.qml +254 -0
- package/ui/MarkdownImages.qml +72 -0
- package/ui/MarkdownList.qml +81 -0
- package/ui/MarkdownMathsText.qml +97 -0
- package/ui/MarkdownPane.qml +83 -0
- package/ui/MarkdownPictures.qml +41 -0
- package/ui/MarkdownQuote.qml +52 -0
- package/ui/MarkdownRemote.qml +82 -0
- package/ui/MarkdownSource.qml +155 -0
- package/ui/MarkdownTable.qml +222 -0
- package/ui/MarkdownTableScroll.qml +64 -0
- package/ui/MarkdownTableWheel.qml +126 -0
- package/ui/MarkdownText.qml +87 -0
- package/ui/MarkdownWorker.js +132 -0
- package/ui/MatchText.qml +99 -0
- package/ui/MediaSession.qml +38 -0
- package/ui/MediaSound.qml +26 -0
- package/ui/MediaStrip.qml +191 -0
- package/ui/MediaTrack.qml +36 -0
- package/ui/MediaVolume.qml +54 -0
- package/ui/MenuActionDialog.qml +396 -0
- package/ui/MenuEdgeFade.qml +24 -0
- package/ui/MenuHost.qml +227 -0
- package/ui/MenuRow.qml +351 -0
- package/ui/MountListing.qml +100 -0
- package/ui/NetworkDialog.qml +435 -0
- package/ui/NetworkForm.qml +426 -0
- package/ui/NetworkMounts.qml +913 -0
- package/ui/NetworkPlaces.qml +127 -0
- package/ui/OpenWithDialog.qml +613 -0
- package/ui/Opener.qml +95 -0
- package/ui/Pane.qml +1320 -0
- package/ui/PaneMenuActions.qml +527 -0
- package/ui/PanePath.qml +90 -0
- package/ui/PaneRail.qml +268 -0
- package/ui/PaneStates.qml +88 -0
- package/ui/PaneSwap.qml +339 -0
- package/ui/PaneWire.qml +601 -0
- package/ui/ParkedWait.qml +9 -0
- package/ui/PathEntry.qml +186 -0
- package/ui/PathJump.qml +400 -0
- package/ui/PdfViewer.qml +297 -0
- package/ui/PermissionsDialog.qml +658 -0
- package/ui/PermissionsHeadings.qml +31 -0
- package/ui/PhoneMounts.qml +67 -0
- package/ui/PickerAnswers.qml +75 -0
- package/ui/PickerBox.qml +26 -0
- package/ui/PickerChrome.qml +295 -0
- package/ui/PickerFilter.qml +97 -0
- package/ui/PickerGrid.qml +308 -0
- package/ui/PickerHeader.qml +28 -0
- package/ui/PickerLifecycle.qml +27 -0
- package/ui/PickerList.qml +218 -0
- package/ui/PickerListing.qml +149 -0
- package/ui/PickerPathBar.qml +127 -0
- package/ui/PickerPlaces.qml +189 -0
- package/ui/PickerRecent.qml +92 -0
- package/ui/PickerSave.qml +101 -0
- package/ui/PickerSelection.qml +155 -0
- package/ui/PickerWindow.qml +846 -0
- package/ui/PowerSectorsReader.qml +10 -0
- package/ui/PrebuildDriver.qml +146 -0
- package/ui/Preview.qml +1005 -0
- package/ui/PreviewAnimation.qml +24 -0
- package/ui/PreviewArchive.qml +91 -0
- package/ui/PreviewColumn.qml +553 -0
- package/ui/PreviewEdge.qml +63 -0
- package/ui/PreviewFacts.qml +30 -0
- package/ui/PreviewFactsLine.qml +34 -0
- package/ui/PreviewHtml.qml +233 -0
- package/ui/PreviewImage.qml +253 -0
- package/ui/PreviewImagePan.qml +13 -0
- package/ui/PreviewImageSharp.qml +32 -0
- package/ui/PreviewLines.qml +106 -0
- package/ui/PreviewMarkdown.qml +706 -0
- package/ui/PreviewMedia.qml +250 -0
- package/ui/PreviewPdf.qml +482 -0
- package/ui/PreviewScroll.qml +201 -0
- package/ui/PreviewSwap.qml +335 -0
- package/ui/PreviewText.qml +149 -0
- package/ui/ProtocolChip.qml +18 -0
- package/ui/QuickLookArchive.qml +41 -0
- package/ui/QuickLookBar.qml +103 -0
- package/ui/QuickLookPrepare.qml +355 -0
- package/ui/QuickLookSwap.qml +10 -0
- package/ui/QuickLookWarm.qml +65 -0
- package/ui/RailDrop.qml +155 -0
- package/ui/RailHeading.qml +19 -0
- package/ui/RailPlaces.qml +38 -0
- package/ui/RailTrashRow.qml +67 -0
- package/ui/RenameField.qml +353 -0
- package/ui/RendererRetry.qml +11 -0
- package/ui/ResizeHandle.qml +52 -0
- package/ui/Reveal.qml +54 -0
- package/ui/Row.qml +476 -0
- package/ui/RowDrag.qml +213 -0
- package/ui/RowDropTarget.qml +27 -0
- package/ui/RunCard.qml +286 -0
- package/ui/Scripts.qml +65 -0
- package/ui/SearchStrip.qml +232 -0
- package/ui/SelectionBand.qml +140 -0
- package/ui/SelectionPreview.qml +370 -0
- package/ui/SettingsFavourite.qml +122 -0
- package/ui/SettingsGroup.qml +96 -0
- package/ui/SettingsHint.qml +12 -0
- package/ui/SettingsMetrics.qml +29 -0
- package/ui/SettingsPane.qml +178 -0
- package/ui/SettingsPanel.qml +547 -0
- package/ui/SettingsRail.qml +128 -0
- package/ui/SettingsRow.qml +409 -0
- package/ui/SettingsRuler.qml +85 -0
- package/ui/SettingsSegment.qml +85 -0
- package/ui/ShareBrowser.qml +113 -0
- package/ui/ShareLink.qml +67 -0
- package/ui/ShelfPins.qml +101 -0
- package/ui/Sidebar.qml +728 -0
- package/ui/SidebarRow.qml +358 -0
- package/ui/Spinner.qml +60 -0
- package/ui/StableModel.qml +89 -0
- package/ui/StateMessage.qml +84 -0
- package/ui/StatusBar.qml +512 -0
- package/ui/StatusFileName.qml +27 -0
- package/ui/TabBar.qml +673 -0
- package/ui/TabDragGeometry.qml +60 -0
- package/ui/TagMenuMark.qml +52 -0
- package/ui/TagRailSection.qml +53 -0
- package/ui/TagSlot.qml +40 -0
- package/ui/TagState.qml +150 -0
- package/ui/TagSwatch.qml +28 -0
- package/ui/Taildrop.qml +86 -0
- package/ui/TailscaleMark.qml +50 -0
- package/ui/TerminalService.qml +69 -0
- package/ui/TerminalTab.qml +48 -0
- package/ui/TerminalTabs.qml +27 -0
- package/ui/Theme.qml +460 -0
- package/ui/ThemeColors.qml +43 -0
- package/ui/TransferCard.qml +239 -0
- package/ui/TrashConfirm.qml +129 -0
- package/ui/TrashDropHandler.qml +11 -0
- package/ui/TrashHost.qml +202 -0
- package/ui/TrashMonitor.qml +30 -0
- package/ui/TrashToolbar.qml +19 -0
- package/ui/TrashView.qml +492 -0
- package/ui/UnlockDialog.qml +450 -0
- package/ui/UnlockHost.qml +206 -0
- package/ui/UpdateCheck.qml +97 -0
- package/ui/UserDirs.qml +25 -0
- package/ui/ViewState.qml +565 -0
- package/ui/ViewportScrollBar.qml +195 -0
- package/ui/ViewportScrollBars.qml +25 -0
- package/ui/WebPreview.qml +33 -0
- package/ui/WebPreviewView.qml +26 -0
- package/ui/WindowBody.qml +829 -0
- package/ui/WindowDrag.qml +35 -0
- package/ui/boot/Commons/AudioNodes.qml +50 -0
- package/ui/boot/Commons/AudioNodesModel.js +96 -0
- package/ui/boot/Commons/Border.qml +243 -0
- package/ui/boot/Commons/BorderGeometry.js +373 -0
- package/ui/boot/Commons/Color.qml +258 -0
- package/ui/boot/Commons/I18n.qml +118 -0
- package/ui/boot/Commons/InputDevices.qml +112 -0
- package/ui/boot/Commons/InputMethodState.qml +38 -0
- package/ui/boot/Commons/IpcRegistry.qml +77 -0
- package/ui/boot/Commons/Numbers.js +19 -0
- package/ui/boot/Commons/Plural.js +91 -0
- package/ui/boot/Commons/ShellIpc.qml +12 -0
- package/ui/boot/Commons/Style.qml +561 -0
- package/ui/boot/Commons/Translations.qml +100 -0
- package/ui/boot/Commons/UntypedInput.qml +152 -0
- package/ui/boot/Commons/Util.qml +188 -0
- package/ui/boot/Commons/qmldir +13 -0
- package/ui/boot/LICENSE-omarchy +20 -0
- package/ui/boot/Ui/BackgroundMedia.qml +49 -0
- package/ui/boot/Ui/BarIconButton.qml +106 -0
- package/ui/boot/Ui/BarIconContent.qml +38 -0
- package/ui/boot/Ui/BarIndicator.qml +53 -0
- package/ui/boot/Ui/BarWidget.qml +50 -0
- package/ui/boot/Ui/BorderOverlay.qml +54 -0
- package/ui/boot/Ui/BorderSurface.qml +40 -0
- package/ui/boot/Ui/Button.qml +224 -0
- package/ui/boot/Ui/ButtonGroup.qml +131 -0
- package/ui/boot/Ui/ConfirmDialog.qml +134 -0
- package/ui/boot/Ui/CursorSurface.qml +42 -0
- package/ui/boot/Ui/Dropdown.qml +245 -0
- package/ui/boot/Ui/FilterInput.qml +26 -0
- package/ui/boot/Ui/IconContentBounds.qml +141 -0
- package/ui/boot/Ui/KeyboardPanel.qml +453 -0
- package/ui/boot/Ui/MultiSelect.qml +624 -0
- package/ui/boot/Ui/NumberField.qml +86 -0
- package/ui/boot/Ui/OpticalGlyph.qml +68 -0
- package/ui/boot/Ui/OverlayWindow.qml +102 -0
- package/ui/boot/Ui/Panel.qml +60 -0
- package/ui/boot/Ui/PanelActionButton.qml +105 -0
- package/ui/boot/Ui/PanelController.qml +16 -0
- package/ui/boot/Ui/PanelHero.qml +112 -0
- package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
- package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
- package/ui/boot/Ui/PanelSeparator.qml +19 -0
- package/ui/boot/Ui/PanelSlider.qml +156 -0
- package/ui/boot/Ui/PanelToolTip.qml +50 -0
- package/ui/boot/Ui/PluginBarApi.qml +89 -0
- package/ui/boot/Ui/PointerMoveGate.qml +54 -0
- package/ui/boot/Ui/PopupCard.qml +181 -0
- package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
- package/ui/boot/Ui/SearchableDropdown.qml +354 -0
- package/ui/boot/Ui/SizedImage.qml +125 -0
- package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
- package/ui/boot/Ui/TextField.qml +58 -0
- package/ui/boot/Ui/Toggle.qml +118 -0
- package/ui/boot/Ui/ToggleSwitch.qml +115 -0
- package/ui/boot/Ui/WidgetButton.qml +172 -0
- package/ui/boot/Ui/qmldir +41 -0
- package/ui/boot/fleatab.qml +50 -0
- package/ui/boot/picker.qml +39 -0
- package/ui/boot/shell.qml +131 -0
- package/ui/boot/tabtearoff.qml +51 -0
- package/ui/js/Anchor.js +379 -0
- package/ui/js/AnchorHold.js +162 -0
- package/ui/js/Archive.js +157 -0
- package/ui/js/ArchiveCard.js +44 -0
- package/ui/js/ArchiveOps.js +44 -0
- package/ui/js/BackReturn.js +118 -0
- package/ui/js/BulkRename.js +100 -0
- package/ui/js/Buttons.js +54 -0
- package/ui/js/ChromeKeys.js +116 -0
- package/ui/js/ClipMarks.js +73 -0
- package/ui/js/ClipSelection.js +67 -0
- package/ui/js/Clipboard.js +179 -0
- package/ui/js/Cloud.js +97 -0
- package/ui/js/CodeRuns.js +72 -0
- package/ui/js/Collide.js +212 -0
- package/ui/js/ColumnFit.js +28 -0
- package/ui/js/ColumnMenu.js +111 -0
- package/ui/js/Columns.js +298 -0
- package/ui/js/ColumnsCarry.js +103 -0
- package/ui/js/Compare.js +74 -0
- package/ui/js/Contrast.js +157 -0
- package/ui/js/ControlReader.js +42 -0
- package/ui/js/Convert.js +52 -0
- package/ui/js/CopyAs.js +52 -0
- package/ui/js/Crumbs.js +178 -0
- package/ui/js/Csv.js +231 -0
- package/ui/js/Density.js +44 -0
- package/ui/js/Devices.js +440 -0
- package/ui/js/DirSizes.js +180 -0
- package/ui/js/Drag.js +360 -0
- package/ui/js/DragOut.js +166 -0
- package/ui/js/DropDev.js +52 -0
- package/ui/js/Dropbox.js +41 -0
- package/ui/js/Eject.js +217 -0
- package/ui/js/Errors.js +188 -0
- package/ui/js/ExtThumbs.js +115 -0
- package/ui/js/Facts.js +402 -0
- package/ui/js/FigureDate.js +14 -0
- package/ui/js/Filter.js +285 -0
- package/ui/js/Find.js +46 -0
- package/ui/js/Flash.js +184 -0
- package/ui/js/FlashCard.js +79 -0
- package/ui/js/FlashEndings.js +125 -0
- package/ui/js/FlashPane.js +116 -0
- package/ui/js/FleaBin.js +12 -0
- package/ui/js/Focus.js +504 -0
- package/ui/js/FolderSorts.js +108 -0
- package/ui/js/FolderViews.js +44 -0
- package/ui/js/Format.js +314 -0
- package/ui/js/Fuzzy.js +141 -0
- package/ui/js/GlassTag.js +72 -0
- package/ui/js/Grid.js +33 -0
- package/ui/js/GridGeometry.js +90 -0
- package/ui/js/GridNames.js +153 -0
- package/ui/js/GvfsBridge.js +200 -0
- package/ui/js/HostClipboard.js +29 -0
- package/ui/js/Icons.js +218 -0
- package/ui/js/Input.js +50 -0
- package/ui/js/Jump.js +200 -0
- package/ui/js/KeyName.js +64 -0
- package/ui/js/Keymap.js +401 -0
- package/ui/js/Kinds.js +164 -0
- package/ui/js/LICENSES/ISC-lucide.txt +43 -0
- package/ui/js/LangMarkPaths.js +47 -0
- package/ui/js/LangMarks.js +120 -0
- package/ui/js/Lists.js +11 -0
- package/ui/js/LocalSend.js +39 -0
- package/ui/js/LockedMenu.js +63 -0
- package/ui/js/MakeDefault.js +186 -0
- package/ui/js/MarkBox.js +7 -0
- package/ui/js/Markdown.js +119 -0
- package/ui/js/MarkdownLists.js +86 -0
- package/ui/js/MarkdownMaths.js +58 -0
- package/ui/js/MarkdownPictures.js +32 -0
- package/ui/js/MarkdownPrepared.js +139 -0
- package/ui/js/MarkdownTableFit.js +34 -0
- package/ui/js/Marks.js +148 -0
- package/ui/js/Marquee.js +96 -0
- package/ui/js/Match.js +93 -0
- package/ui/js/Material.js +109 -0
- package/ui/js/MdBlocks.js +437 -0
- package/ui/js/MdBreak.js +71 -0
- package/ui/js/MdChunks.js +70 -0
- package/ui/js/MdContainer.js +137 -0
- package/ui/js/MdDocument.js +337 -0
- package/ui/js/MdEmph.js +97 -0
- package/ui/js/MdEntity.js +108 -0
- package/ui/js/MdEntityTable.js +223 -0
- package/ui/js/MdEscape.js +59 -0
- package/ui/js/MdFront.js +37 -0
- package/ui/js/MdHold.js +32 -0
- package/ui/js/MdHtml.js +307 -0
- package/ui/js/MdHtmlBlock.js +290 -0
- package/ui/js/MdHtmlHeading.js +53 -0
- package/ui/js/MdHtmlImage.js +179 -0
- package/ui/js/MdInline.js +154 -0
- package/ui/js/MdItems.js +212 -0
- package/ui/js/MdLeaf.js +309 -0
- package/ui/js/MdLink.js +196 -0
- package/ui/js/MdMath.js +67 -0
- package/ui/js/MdParagraphs.js +138 -0
- package/ui/js/MdRefs.js +232 -0
- package/ui/js/MdResolve.js +226 -0
- package/ui/js/MdRun.js +300 -0
- package/ui/js/MdUrl.js +226 -0
- package/ui/js/Menu.js +514 -0
- package/ui/js/MenuContext.js +85 -0
- package/ui/js/MenuFit.js +13 -0
- package/ui/js/MenuRefresh.js +74 -0
- package/ui/js/MenuWheel.js +35 -0
- package/ui/js/Messages.js +186 -0
- package/ui/js/Motion.js +16 -0
- package/ui/js/Mounts.js +320 -0
- package/ui/js/MouseNav.js +13 -0
- package/ui/js/Nav.js +329 -0
- package/ui/js/NetFs.js +26 -0
- package/ui/js/OpenWith.js +83 -0
- package/ui/js/Ops.js +585 -0
- package/ui/js/Palette.js +33 -0
- package/ui/js/PathBar.js +260 -0
- package/ui/js/Permissions.js +179 -0
- package/ui/js/Phones.js +112 -0
- package/ui/js/Picker.js +353 -0
- package/ui/js/PlaceMenu.js +96 -0
- package/ui/js/Places.js +265 -0
- package/ui/js/PreviewAsk.js +21 -0
- package/ui/js/PreviewKeys.js +155 -0
- package/ui/js/PreviewSettle.js +29 -0
- package/ui/js/PreviewSwap.js +101 -0
- package/ui/js/PropertyFacts.js +144 -0
- package/ui/js/Protocols.js +296 -0
- package/ui/js/QuickLookKinds.js +27 -0
- package/ui/js/QuickLookRect.js +24 -0
- package/ui/js/RailDrop.js +51 -0
- package/ui/js/RailKeys.js +87 -0
- package/ui/js/RailMenu.js +133 -0
- package/ui/js/Recent.js +135 -0
- package/ui/js/RecentMode.js +156 -0
- package/ui/js/Reload.js +60 -0
- package/ui/js/Renderer.js +9 -0
- package/ui/js/RunFile.js +143 -0
- package/ui/js/Scripts.js +28 -0
- package/ui/js/Scroll.js +304 -0
- package/ui/js/ScrollOff.js +69 -0
- package/ui/js/Search.js +478 -0
- package/ui/js/Selection.js +97 -0
- package/ui/js/Settings.js +476 -0
- package/ui/js/SettingsAbout.js +97 -0
- package/ui/js/SettingsShelf.js +52 -0
- package/ui/js/SheetKeys.js +42 -0
- package/ui/js/SheetQuery.js +281 -0
- package/ui/js/ShelfPile.js +27 -0
- package/ui/js/SlowClick.js +53 -0
- package/ui/js/SlowOp.js +6 -0
- package/ui/js/Sort.js +134 -0
- package/ui/js/Startup.js +63 -0
- package/ui/js/StateWords.js +17 -0
- package/ui/js/Status.js +238 -0
- package/ui/js/Swap.js +166 -0
- package/ui/js/TabMove.js +39 -0
- package/ui/js/Tabs.js +751 -0
- package/ui/js/Tags.js +134 -0
- package/ui/js/Taildrop.js +128 -0
- package/ui/js/Tap.js +180 -0
- package/ui/js/TextSize.js +107 -0
- package/ui/js/Thumbs.js +158 -0
- package/ui/js/Transfer.js +172 -0
- package/ui/js/Trash.js +84 -0
- package/ui/js/TrashDates.js +47 -0
- package/ui/js/TrashDrop.js +64 -0
- package/ui/js/UiState.js +438 -0
- package/ui/js/Unlock.js +152 -0
- package/ui/js/Update.js +130 -0
- package/ui/js/UserDirs.js +56 -0
- package/ui/qmldir +230 -0
package/ui/js/Tags.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Format.js" as Format
|
|
4
|
+
.import "Status.js" as Status
|
|
5
|
+
|
|
6
|
+
// Flea's seven tag names in menu order, which is also the 1 to 7 key order; src/backend/tags.rs NAMES is the same list.
|
|
7
|
+
var NAMES = ["Red", "Orange", "Yellow", "Green", "Blue", "Purple", "Gray"]
|
|
8
|
+
|
|
9
|
+
// The board's tag swatch square, in px.
|
|
10
|
+
var SWATCH_SIZE = 14
|
|
11
|
+
|
|
12
|
+
// The smaller swatch Properties040's Tags pair draws beside its 14 px text, in px.
|
|
13
|
+
var PAIR_SWATCH_SIZE = 10
|
|
14
|
+
|
|
15
|
+
// The digit each name answers to, "" when no digit names it.
|
|
16
|
+
function keyFor(name) {
|
|
17
|
+
var at = NAMES.indexOf(name)
|
|
18
|
+
return at < 0 ? "" : String(at + 1)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var APPLIED = "applied"
|
|
22
|
+
var MIXED = "mixed"
|
|
23
|
+
var ABSENT = "absent"
|
|
24
|
+
|
|
25
|
+
// Across a selection: applied when every file carries it, mixed when some do, absent otherwise.
|
|
26
|
+
function stateFor(files, name) {
|
|
27
|
+
var have = 0
|
|
28
|
+
for (var i = 0; i < files.length; i++) {
|
|
29
|
+
if (files[i].indexOf(name) >= 0) {
|
|
30
|
+
have++
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (have === 0) {
|
|
34
|
+
return ABSENT
|
|
35
|
+
}
|
|
36
|
+
return have === files.length ? APPLIED : MIXED
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function statesFor(files) {
|
|
40
|
+
var states = {}
|
|
41
|
+
for (var i = 0; i < NAMES.length; i++) {
|
|
42
|
+
states[NAMES[i]] = stateFor(files, NAMES[i])
|
|
43
|
+
}
|
|
44
|
+
return states
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// The same states from a backend read: the names every target carries, then the names only some carry.
|
|
48
|
+
function statesFrom(applied, mixed) {
|
|
49
|
+
var states = {}
|
|
50
|
+
for (var i = 0; i < NAMES.length; i++)
|
|
51
|
+
states[NAMES[i]] = applied.indexOf(NAMES[i]) >= 0 ? APPLIED : mixed.indexOf(NAMES[i]) >= 0 ? MIXED : ABSENT
|
|
52
|
+
return states
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// The status bar's own sentence after a tag change; the count agrees with ui/js/Ops.js nouns.
|
|
56
|
+
function statusLine(ok, name) {
|
|
57
|
+
if (ok === 1) return Format.fill("Tagged %1 item %2", ok, name) + Status.undoHint()
|
|
58
|
+
return Format.fill("Tagged %1 items %2", ok, name) + Status.undoHint()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// The same sentence for clearing every tag off the named rows.
|
|
62
|
+
function clearedLine(ok) {
|
|
63
|
+
if (ok === 1) return Format.fill("Removed all tags from %1 item", ok) + Status.undoHint()
|
|
64
|
+
return Format.fill("Removed all tags from %1 items", ok) + Status.undoHint()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// The same sentence for taking one tag off the named rows.
|
|
68
|
+
function removedLine(ok, name) {
|
|
69
|
+
if (ok === 1) return Format.fill("Removed %1 from %2 item", name, ok) + Status.undoHint()
|
|
70
|
+
return Format.fill("Removed %1 from %2 items", name, ok) + Status.undoHint()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// The line for a settagged answer, read from the op the backend applied rather than from the UI's guess.
|
|
74
|
+
function changedLine(op, ok, name) {
|
|
75
|
+
if (op === "clear") return clearedLine(ok)
|
|
76
|
+
return op === "remove" ? removedLine(ok, name) : statusLine(ok, name)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// The line when rows were skipped: the backend leaves out every row that is neither a file nor a folder, so the fragment counts items, not links.
|
|
80
|
+
function skippedLine(names) {
|
|
81
|
+
if (names.length === 1) return Format.fill("%1 item skipped", Format.count(names.length))
|
|
82
|
+
return Format.fill("%1 items skipped", Format.count(names.length))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// The whole answer line: the changed sentence, the skip fragment ahead of its undo hint, only the skip when nothing changed, and empty when neither holds.
|
|
86
|
+
function doneLine(op, ok, name, skipped) {
|
|
87
|
+
var skip = skipped && skipped.length > 0 ? skippedLine(skipped) : ""
|
|
88
|
+
if (ok <= 0) return skip
|
|
89
|
+
var changed = changedLine(op, ok, name)
|
|
90
|
+
if (skip === "") return changed
|
|
91
|
+
return changed.replace(/ \u00b7 z undoes$/, function () { return Format.fill(" \u00b7 %1 \u00b7 z undoes", skip) })
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// The flyout's rows: seven swatches with digit hints, then Remove all tags under a separator.
|
|
95
|
+
var CLEAR_ID = "__clear__"
|
|
96
|
+
function tagEntries(states, fallback) {
|
|
97
|
+
var out = []
|
|
98
|
+
for (var i = 0; i < NAMES.length; i++) {
|
|
99
|
+
out.push({ id: NAMES[i], label: NAMES[i], glyph: "tag", keyHint: String(i + 1), tagRow: { swatch: NAMES[i], fallback: fallback === true,
|
|
100
|
+
state: (states || {})[NAMES[i]] || ABSENT, digit: String(i + 1) } })
|
|
101
|
+
}
|
|
102
|
+
out.push({ separator: true })
|
|
103
|
+
out.push({ id: CLEAR_ID, label: "Remove all tags", glyph: "x" })
|
|
104
|
+
return out
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// One rows reply: every row learns whether the folder's slot stands, and inUse gains the tags seen; fresh starts the latch over.
|
|
108
|
+
function stamp(items, latched, inUse, fresh) {
|
|
109
|
+
var tagged = false
|
|
110
|
+
var grew = false
|
|
111
|
+
for (var i = 0; i < items.length; i++) {
|
|
112
|
+
var names = items[i].tg
|
|
113
|
+
if (names === undefined) continue
|
|
114
|
+
tagged = true
|
|
115
|
+
for (var j = 0; j < names.length; j++) {
|
|
116
|
+
if (inUse[names[j]] === true) continue
|
|
117
|
+
inUse[names[j]] = true
|
|
118
|
+
grew = true
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
var stands = tagged || (latched && !fresh)
|
|
122
|
+
for (var k = 0; k < items.length; k++) items[k].shown = stands
|
|
123
|
+
return { latched: stands, grew: grew }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// The TAGS section lists only tags in use, each row the rail's own entry shape.
|
|
127
|
+
function railEntries(inUse) {
|
|
128
|
+
var out = []
|
|
129
|
+
for (var i = 0; i < NAMES.length; i++) {
|
|
130
|
+
if (inUse[NAMES[i]] === true)
|
|
131
|
+
out.push({ label: NAMES[i], kind: "tag", tag: NAMES[i], glyph: "tag", swatch: NAMES[i], digit: String(i + 1) })
|
|
132
|
+
}
|
|
133
|
+
return out
|
|
134
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
// Adapted verbatim from the OEM tailscale plugin's own Model.js, read at
|
|
4
|
+
// /usr/share/omarchy/shell/plugins/panels/tailscale/Model.js: isTaildropTarget,
|
|
5
|
+
// displayHostName/shortDnsName/cleanDnsName and the Online/Mullvad filter in parseStatus.
|
|
6
|
+
|
|
7
|
+
// Sample input: `tailscale status --json`, trimmed to the fields this file reads.
|
|
8
|
+
// {"Self":{"UserID":1000000000000001},"Peer":{"nodekey:...":{"HostName":"laptop",
|
|
9
|
+
// "DNSName":"laptop.example-net.ts.net.","Online":true,"TaildropTarget":1,
|
|
10
|
+
// "TailscaleIPs":["100.1.2.3"],"UserID":1000000000000001}}}
|
|
11
|
+
function parsePeers(raw) {
|
|
12
|
+
var text = String(raw || "").trim()
|
|
13
|
+
if (text === "")
|
|
14
|
+
return []
|
|
15
|
+
var data
|
|
16
|
+
try {
|
|
17
|
+
data = JSON.parse(text)
|
|
18
|
+
} catch (e) {
|
|
19
|
+
return []
|
|
20
|
+
}
|
|
21
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return []
|
|
22
|
+
var selfUserId = String((data.Self && data.Self.UserID) || "")
|
|
23
|
+
var rawPeers = (data && data.Peer) || {}
|
|
24
|
+
var out = []
|
|
25
|
+
for (var id in rawPeers) {
|
|
26
|
+
var peer = rawPeers[id] || {}
|
|
27
|
+
if (!peer.Online)
|
|
28
|
+
continue
|
|
29
|
+
if (isMullvad(peer))
|
|
30
|
+
continue
|
|
31
|
+
if (!isTaildropTarget(peer, selfUserId))
|
|
32
|
+
continue
|
|
33
|
+
var address = peerAddress(peer)
|
|
34
|
+
if (address === "")
|
|
35
|
+
continue
|
|
36
|
+
out.push({ id: id, label: displayHostName(peer.HostName, peer.DNSName), address: address })
|
|
37
|
+
}
|
|
38
|
+
out.sort(function (a, b) { return a.label.localeCompare(b.label) })
|
|
39
|
+
return out
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// The code names the state for logic (statusFailed, invalid, signedOut, stopped, disabled, noPeers, or "" when ready); the reason is for people.
|
|
43
|
+
// Sample input: {"BackendState":"Running","Self":{"CapMap":{"https://tailscale.com/cap/file-sharing":[]}},"Peer":{}}.
|
|
44
|
+
function status(raw, exitCode, error) {
|
|
45
|
+
if (exitCode !== 0) return { peers: [], reason: String(error || "Tailscale could not be checked").trim(), code: "statusFailed" }
|
|
46
|
+
var data
|
|
47
|
+
try { data = JSON.parse(raw) } catch (e) { return { peers: [], reason: "invalid status", code: "invalid" } }
|
|
48
|
+
if (!data || typeof data !== "object") return { peers: [], reason: "invalid status", code: "invalid" }
|
|
49
|
+
if (data.BackendState === "NeedsLogin") return { peers: [], reason: "signed out", code: "signedOut" }
|
|
50
|
+
if (data.BackendState !== "Running") return { peers: [], reason: String(data.BackendState || "unavailable").toLowerCase(), code: "stopped" }
|
|
51
|
+
var self = data.Self || {}, capability = "https://tailscale.com/cap/file-sharing"
|
|
52
|
+
var capabilities = Array.isArray(self.Capabilities) ? self.Capabilities : []
|
|
53
|
+
if (!(self.CapMap && self.CapMap[capability] !== undefined)
|
|
54
|
+
&& capabilities.indexOf(capability) < 0)
|
|
55
|
+
return { peers: [], reason: "disabled for this account", code: "disabled" }
|
|
56
|
+
var peers = parsePeers(raw)
|
|
57
|
+
return { peers: peers, reason: peers.length ? "" : "no peers", code: peers.length ? "" : "noPeers" }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// A specific TaildropTarget wins outright; 0 (unset) falls back to "do we own it too".
|
|
61
|
+
function isTaildropTarget(peer, selfUserId) {
|
|
62
|
+
var target = peer && peer.TaildropTarget
|
|
63
|
+
if (typeof target === "number" && target !== 0)
|
|
64
|
+
return target === 1
|
|
65
|
+
var owner = String((peer && peer.UserID) || "")
|
|
66
|
+
return owner !== "" && owner === String(selfUserId || "")
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function cleanDnsName(name) {
|
|
70
|
+
var value = String(name || "")
|
|
71
|
+
return value.charAt(value.length - 1) === "." ? value.slice(0, -1) : value
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function shortDnsName(name) {
|
|
75
|
+
var clean = cleanDnsName(name)
|
|
76
|
+
return clean === "" ? "" : (clean.split(".")[0] || clean)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function displayHostName(hostName, dnsName) {
|
|
80
|
+
var host = String(hostName || "")
|
|
81
|
+
if (host !== "" && host.toLowerCase() !== "localhost")
|
|
82
|
+
return host
|
|
83
|
+
return shortDnsName(dnsName) || host || "Unknown"
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// An exit-node relay peer, never a real send target; see the OEM's own isMullvadPeer.
|
|
87
|
+
function isMullvad(peer) {
|
|
88
|
+
var suffix = ".mullvad.ts.net"
|
|
89
|
+
var dnsName = cleanDnsName((peer && peer.DNSName) || "").toLowerCase()
|
|
90
|
+
var hostName = String((peer && peer.HostName) || "").toLowerCase()
|
|
91
|
+
return endsWith(dnsName, suffix) || endsWith(hostName, suffix)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function endsWith(value, suffix) {
|
|
95
|
+
return value.length > suffix.length && value.lastIndexOf(suffix) === value.length - suffix.length
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// omarchy-tailscale-send resolves its own "$machine" argument the same three ways.
|
|
99
|
+
function peerAddress(peer) {
|
|
100
|
+
if (!peer)
|
|
101
|
+
return ""
|
|
102
|
+
if (peer.DNSName)
|
|
103
|
+
return cleanDnsName(peer.DNSName)
|
|
104
|
+
if (peer.HostName)
|
|
105
|
+
return String(peer.HostName)
|
|
106
|
+
var ips = filterIPv4(peer.TailscaleIPs || [])
|
|
107
|
+
return ips.length > 0 ? ips[0] : ""
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function filterIPv4(ips) {
|
|
111
|
+
var result = []
|
|
112
|
+
if (!ips || typeof ips.length !== "number")
|
|
113
|
+
return result
|
|
114
|
+
for (var i = 0; i < ips.length; i++) {
|
|
115
|
+
var ip = String(ips[i] || "")
|
|
116
|
+
if (/^100\./.test(ip))
|
|
117
|
+
result.push(ip)
|
|
118
|
+
}
|
|
119
|
+
return result
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function byId(peers, id) {
|
|
123
|
+
for (var i = 0; i < peers.length; i++) {
|
|
124
|
+
if (peers[i].id === id)
|
|
125
|
+
return peers[i]
|
|
126
|
+
}
|
|
127
|
+
return null
|
|
128
|
+
}
|
package/ui/js/Tap.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
.import "Search.js" as Search
|
|
3
|
+
.import "Tabs.js" as Tabs
|
|
4
|
+
.import "Filter.js" as Filter
|
|
5
|
+
|
|
6
|
+
// flea-qml: a pointer on the list takes the keys back from a query line, as the arrows already do
|
|
7
|
+
// (ui/js/Focus.js leavesLine): the filter keeps its query standing and gives up its caret, and a Find
|
|
8
|
+
// line hands the keys to the results without running. Otherwise the next Space or letter is typed
|
|
9
|
+
// into the line the pointer has just left.
|
|
10
|
+
function focusListing(root) {
|
|
11
|
+
if (root.renameEditor && root.renameEditor()) return
|
|
12
|
+
root.focusView = "list"
|
|
13
|
+
if (root.listArea) root.listArea.forceActiveFocus()
|
|
14
|
+
}
|
|
15
|
+
function releaseLines(root) {
|
|
16
|
+
if (root.filterTyping) Filter.commit(root)
|
|
17
|
+
if (root.searchMode === Search.TYPING) root.searchMode = Search.RESULTS
|
|
18
|
+
focusListing(root)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Hit the drawn label instead of the whole name slot, including centered grid captions.
|
|
22
|
+
function onName(label, owner, point, centered) {
|
|
23
|
+
if (!label || !label.visible) return false
|
|
24
|
+
var at = label.mapFromItem(owner, point.x, point.y)
|
|
25
|
+
var width = Math.min(label.width, label.contentWidth === undefined ? label.implicitWidth : label.contentWidth)
|
|
26
|
+
var height = Math.min(label.height, label.contentHeight === undefined ? label.implicitHeight : label.contentHeight)
|
|
27
|
+
var left = centered ? (label.width - width) / 2 : 0
|
|
28
|
+
return at.x >= left && at.x < left + width && at.y >= 0 && at.y < height
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// The pointer contract, declared in keys.toml's [[pointer]] table and decided here and nowhere
|
|
32
|
+
// else. tests/js/tap.js drives every row of Keymap.POINTER through the three functions below, so a
|
|
33
|
+
// click cannot change meaning without the table saying so and the table cannot advertise a click the
|
|
34
|
+
// code does not make.
|
|
35
|
+
//
|
|
36
|
+
// The rule is macOS's and the operator's: one tap selects, the second opens. The single-tap action is
|
|
37
|
+
// idempotent on a row, so it runs on both taps of a double click rather than behind a double-click
|
|
38
|
+
// timer, which would delay every selection by the whole mouseDoubleClickInterval.
|
|
39
|
+
|
|
40
|
+
// A view keeps its delegates across a re-list, so a tap count can outlive the row its first tap named.
|
|
41
|
+
var firstTap = null
|
|
42
|
+
// A later tap counts only on the row its gesture's first tap named; a tap on another row answers 0 and starts the count again.
|
|
43
|
+
function gestureCount(index, tapCount, root) {
|
|
44
|
+
var row = index >= 0 ? root.rowFor(index) : null
|
|
45
|
+
var key = String(root.path) + "\n" + (row ? row.n : "")
|
|
46
|
+
if (tapCount === 1 || firstTap === null || firstTap.pane !== root) {
|
|
47
|
+
firstTap = { pane: root, key: key, base: 0 }
|
|
48
|
+
return tapCount
|
|
49
|
+
}
|
|
50
|
+
if (firstTap.key !== key) {
|
|
51
|
+
firstTap = { pane: root, key: key, base: tapCount }
|
|
52
|
+
return 0
|
|
53
|
+
}
|
|
54
|
+
return tapCount - firstTap.base
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// One tap selects, the second opens; a click carries context 0 so the list never moves under the pointer.
|
|
58
|
+
function tapped(index, tapCount, modifiers, root) {
|
|
59
|
+
if (index < 0) return
|
|
60
|
+
releaseLines(root)
|
|
61
|
+
tapCount = gestureCount(index, tapCount, root)
|
|
62
|
+
if (tapCount === 0) return
|
|
63
|
+
// Single-click mode opens on the first tap alone, so later taps of one gesture add nothing.
|
|
64
|
+
if (root.singleClick === true && tapCount !== 1) return
|
|
65
|
+
// Finder's two selection modifiers. Neither ever opens, and only the first tap of one counts,
|
|
66
|
+
// so a modified double click selects once instead of toggling itself back off.
|
|
67
|
+
if (modifiers & Qt.ControlModifier) {
|
|
68
|
+
if (tapCount === 1) root.toggleSelectAt(index)
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
if (modifiers & Qt.ShiftModifier) {
|
|
72
|
+
if (tapCount === 1) root.extendSelectionTo(index)
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
// What a tap means is the search's to say, not this file's. flea-qml: on Find's results it is the
|
|
76
|
+
// same as anywhere, select on one tap and open on two, so the pointer browses results and the
|
|
77
|
+
// search stays; upstream revealed on the first tap. ui/js/Search.js activateAction answers it.
|
|
78
|
+
var verb = Search.activateAction(root)
|
|
79
|
+
if (verb === "reveal" && tapCount !== 1)
|
|
80
|
+
return
|
|
81
|
+
// Finder commits an open rename on click-away first, so its text lands before the selection moves.
|
|
82
|
+
root.commitOpenRename()
|
|
83
|
+
// A plain tap replaces the selection, so the next shift+click extends from a row on screen.
|
|
84
|
+
root.selectOnly(index, 0)
|
|
85
|
+
if (tapCount === 2 || verb === "reveal")
|
|
86
|
+
root.act(verb)
|
|
87
|
+
// Single-click mode opens files and folders on one tap, like the middle column already does.
|
|
88
|
+
if (tapCount === 1 && verb === "open" && root.singleClick === true)
|
|
89
|
+
root.act("open")
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// The columns view's own middle column, and ui/ColumnsArea.qml is its only caller, which is what
|
|
93
|
+
// keeps this out of the list and the grid. Its two neighbour columns already go into a directory on
|
|
94
|
+
// one tap, and the operator's 2026-09-11 ruling is that the column holding the cursor does the same,
|
|
95
|
+
// which is Finder's column view. A directory alone: everything else is an ordinary listing tap and
|
|
96
|
+
// reads tapped() above, so a file still opens on the second tap and a modifier still only selects.
|
|
97
|
+
function tappedMiddle(index, tapCount, modifiers, root) {
|
|
98
|
+
if (index >= 0) releaseLines(root)
|
|
99
|
+
var row = index >= 0 ? root.rowFor(index) : null
|
|
100
|
+
var plain = (modifiers & (Qt.ControlModifier | Qt.ShiftModifier)) === 0
|
|
101
|
+
// tapped() counts the gesture itself, so a tap is counted once on either path.
|
|
102
|
+
// flea-qml: a folder among Find's results is a result like any other: one tap selects it and the
|
|
103
|
+
// search stays; only a plain folder listing goes in on one tap.
|
|
104
|
+
if (!row || !row.d || !plain || Search.live(root)) {
|
|
105
|
+
tapped(index, tapCount, modifiers, root)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
tapCount = gestureCount(index, tapCount, root)
|
|
109
|
+
if (tapCount === 0) return
|
|
110
|
+
// The first tap moved the pane, so a second one is another directory's row, the same reason
|
|
111
|
+
// tappedColumn refuses to reveal a neighbour twice.
|
|
112
|
+
if (tapCount !== 1)
|
|
113
|
+
return
|
|
114
|
+
root.commitOpenRename()
|
|
115
|
+
root.selectOnly(index, 0)
|
|
116
|
+
// A directory listed as a search result is still a result, so the one decision point answers here
|
|
117
|
+
// too: it reveals rather than opening, exactly as the same row does in the list view.
|
|
118
|
+
root.act(Search.activateAction(root))
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Right click, in all three views: the row under the pointer takes the cursor and the menu opens there.
|
|
122
|
+
// Which rows it then means is decided by the pressed row, ui/js/Drag.js carried()'s rule for the
|
|
123
|
+
// pointer's other gesture: pressed inside the selection the menu addresses all of it, pressed outside
|
|
124
|
+
// it that row replaces the selection. Every entry ui/ContextMenu.qml draws is built from the cursor
|
|
125
|
+
// row while Move to Trash, Compress and Move to Dropbox dispatch through Ops.targetIndices, which
|
|
126
|
+
// prefers the selection, so a right click that left a selection elsewhere standing trashed rows the
|
|
127
|
+
// menu had never described.
|
|
128
|
+
function tappedMenu(index, eventPoint, root, menu) {
|
|
129
|
+
releaseLines(root)
|
|
130
|
+
var picked = root.selectedIndices()
|
|
131
|
+
if (picked.length > 0 && picked.indexOf(index) < 0)
|
|
132
|
+
root.clearSelection()
|
|
133
|
+
root.setCursor(index, 0)
|
|
134
|
+
menu.openAt(eventPoint.scenePosition)
|
|
135
|
+
root.cancelSlowClick()
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// A right click that landed on no row raises the directory's own menu, in all three views and the
|
|
139
|
+
// Trash; a row's own TapHandler has already answered for a row. A TapHandler declared inside a
|
|
140
|
+
// ListView or GridView belongs to its contentItem, so its position is already the content coordinate
|
|
141
|
+
// indexAt takes: adding contentY again read every row past the first screenful as empty space.
|
|
142
|
+
function onBackground(view, eventPoint) {
|
|
143
|
+
return view.indexAt(eventPoint.position.x, eventPoint.position.y) < 0
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// A neighbour column in the columns view is a peek with no cursor of its own, so its rows answer a
|
|
147
|
+
// verb rather than acting. One tap on a directory makes it the pane's listing, which is the column
|
|
148
|
+
// view's own reveal and not an open; only a second tap opens a file. A peeked row belongs to another
|
|
149
|
+
// directory and every menu action addresses the pane's cursor, so a right click there is routed by
|
|
150
|
+
// ColumnPane to menuOnNeighbour before this is asked.
|
|
151
|
+
function tappedColumn(row, button, tapCount) {
|
|
152
|
+
if (!row || button === Qt.RightButton)
|
|
153
|
+
return ""
|
|
154
|
+
if (button === Qt.MiddleButton)
|
|
155
|
+
return row.d && tapCount === 1 ? "openTab" : ""
|
|
156
|
+
if (row.d)
|
|
157
|
+
return tapCount === 1 ? "reveal" : ""
|
|
158
|
+
return tapCount === 2 ? "open" : ""
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Middle click on a directory opens it in a new tab; a file has no directory to show.
|
|
162
|
+
function tabTarget(row, base, root) {
|
|
163
|
+
return row && row.d && typeof row.n === "string" ? root.join(base, row.n) : ""
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function tappedTab(row, base, root) {
|
|
167
|
+
var target = tabTarget(row, base, root)
|
|
168
|
+
if (target.length === 0)
|
|
169
|
+
return
|
|
170
|
+
root.commitOpenRename()
|
|
171
|
+
Tabs.openNew(root, target)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// The slow click renames on the pane's timer; a second tap opens through tapped() instead, so only a lone tap on the name arms it.
|
|
175
|
+
function slowTap(pane, armed, index, modifiers, dragActive, wasSole) {
|
|
176
|
+
if (armed)
|
|
177
|
+
pane.armSlowClick(index, modifiers, dragActive, wasSole)
|
|
178
|
+
else
|
|
179
|
+
pane.cancelSlowClick()
|
|
180
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
.pragma library
|
|
2
|
+
|
|
3
|
+
.import "Format.js" as Format
|
|
4
|
+
.import "KeyName.js" as KeyName
|
|
5
|
+
|
|
6
|
+
// Flea's text size, which is the Display section's one control. The SettingsScale board rules the
|
|
7
|
+
// shape: Omarchy owns the size by default, and an override pins one stop from Omarchy's own range
|
|
8
|
+
// rather than a free number or a multiplier of its own. The monitor scale beside it belongs to the
|
|
9
|
+
// compositor, which is why nothing here steps or cycles one.
|
|
10
|
+
|
|
11
|
+
// Whole sentences with "%1" for a value, filled by fill so each translates as one.
|
|
12
|
+
var WORDS = {
|
|
13
|
+
followsOmarchy: "Text size follows Omarchy, %1",
|
|
14
|
+
override: "Text size %1. %2 follows Omarchy again",
|
|
15
|
+
overrideAlone: "Text size %1"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// The board's seven documented stops, in px, read off its own layout table. They are not
|
|
19
|
+
// contiguous: 13, 15, 17, 18 and 19 are not stops. The range is the OEM one, 9 to 20, so Flea
|
|
20
|
+
// offers no size Omarchy does not.
|
|
21
|
+
var STOPS = [9, 10, 11, 12, 14, 16, 20]
|
|
22
|
+
|
|
23
|
+
// Omarchy's own type ladder, from Commons/Style.qml, whose bodySmall is fontPx(0.917) and caption
|
|
24
|
+
// fontPx(0.833) over the base size. Running the same two ratios at a stop is what makes an override
|
|
25
|
+
// the size Omarchy itself would have drawn, rather than a second ladder that can disagree with it.
|
|
26
|
+
var BODY_RATIO = 1.0
|
|
27
|
+
var BODY_SMALL_RATIO = 0.917
|
|
28
|
+
var CAPTION_RATIO = 0.833
|
|
29
|
+
|
|
30
|
+
var FOLLOW = "system"
|
|
31
|
+
|
|
32
|
+
function follow() {
|
|
33
|
+
return { mode: FOLLOW }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Follow Omarchy is the default, and the board names its stored shape: {"mode":"system"}. An
|
|
37
|
+
// override is the same key holding a number instead, which is src/uischema.rs's own display.textSize
|
|
38
|
+
// rule: "system", or one stop the OEM panel could have produced. There is no second stored shape.
|
|
39
|
+
function following(stored) {
|
|
40
|
+
return !stored || !(Number(stored.mode) > 0)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// The nearest stop, so a base Omarchy invented that is not on the list still enters the override on
|
|
44
|
+
// a real stop, and a hand-edited file cannot pin a free number. A tie takes the smaller stop, which
|
|
45
|
+
// is what the strict comparison below does: 13 enters at 12 and 15 at 14, so nothing grows unasked.
|
|
46
|
+
function nearest(px) {
|
|
47
|
+
var best = STOPS[0]
|
|
48
|
+
for (var i = 1; i < STOPS.length; i++) {
|
|
49
|
+
if (Math.abs(STOPS[i] - px) < Math.abs(best - px))
|
|
50
|
+
best = STOPS[i]
|
|
51
|
+
}
|
|
52
|
+
return best
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// The size Flea actually draws at: Omarchy's own while following, the stored stop while overriding.
|
|
56
|
+
function effective(stored, omarchyBase) {
|
|
57
|
+
return following(stored) ? omarchyBase : nearest(Number(stored.mode))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Switching to Override starts on the stop beside the size already on screen, so the switch itself
|
|
61
|
+
// changes nothing and only a step does.
|
|
62
|
+
function pin(stored, omarchyBase) {
|
|
63
|
+
return { mode: nearest(effective(stored, omarchyBase)) }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// One stop along the list, clamped at both ends. Stepping while following becomes an override,
|
|
67
|
+
// which is what the first press of Ctrl+Shift+Plus should do.
|
|
68
|
+
function stepped(stored, omarchyBase, direction) {
|
|
69
|
+
var at = STOPS.indexOf(pin(stored, omarchyBase).mode)
|
|
70
|
+
var to = Math.max(0, Math.min(STOPS.length - 1, at + direction))
|
|
71
|
+
return { mode: STOPS[to] }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// A stored value another hand wrote, and 0.1.3's own {"mode":"override","px":N}: anything this
|
|
75
|
+
// cannot read as a size follows Omarchy, which is both the default and the state deleting ui.json
|
|
76
|
+
// restores, and a number that is not a stop lands on the nearest one rather than pinning a size the
|
|
77
|
+
// OEM panel could not produce. src/uistate.rs refuses the same shapes on the way in.
|
|
78
|
+
function parse(stored) {
|
|
79
|
+
var px = stored ? Number(stored.mode) : NaN
|
|
80
|
+
return px > 0 ? { mode: nearest(px) } : follow()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// One action-to-delta mapping for every caller, so Focus and the Trash host cannot drift apart.
|
|
84
|
+
function direction(action) {
|
|
85
|
+
return action === "textSizeReset" ? 0 : (action === "textSizeUp" ? 1 : -1)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function body(base) {
|
|
89
|
+
return Math.max(1, Math.round(base * BODY_RATIO))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function bodySmall(base) {
|
|
93
|
+
return Math.max(1, Math.round(base * BODY_SMALL_RATIO))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function caption(base) {
|
|
97
|
+
return Math.max(1, Math.round(base * CAPTION_RATIO))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// The sentence the status bar shows, because a size changed by a chord with the panel shut is
|
|
101
|
+
// otherwise a state with no readout and no named way back.
|
|
102
|
+
function announce(stored, omarchyBase) {
|
|
103
|
+
var px = effective(stored, omarchyBase) + "px"
|
|
104
|
+
if (following(stored)) return Format.fill(WORDS.followsOmarchy, px)
|
|
105
|
+
var reset = KeyName.keyFor("textSizeReset")
|
|
106
|
+
return reset.length > 0 ? Format.fill(WORDS.override, px, reset) : Format.fill(WORDS.overrideAlone, px)
|
|
107
|
+
}
|