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
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import Quickshell
|
|
3
|
+
import Quickshell.Io
|
|
4
|
+
|
|
5
|
+
// Wayland window positions are not QWindow positions. Match the one source client
|
|
6
|
+
// by pid using Theme's hyprctl Process pattern, once per lift, never on motion.
|
|
7
|
+
Item {
|
|
8
|
+
id: root
|
|
9
|
+
property string token: ""
|
|
10
|
+
property string queryToken: ""
|
|
11
|
+
property bool queryDrained: true
|
|
12
|
+
property var rect: null
|
|
13
|
+
property var strip: null
|
|
14
|
+
|
|
15
|
+
function begin(lift, band) {
|
|
16
|
+
root.token = lift
|
|
17
|
+
root.rect = null
|
|
18
|
+
root.strip = band
|
|
19
|
+
// An old query drains before the latest token starts its own query.
|
|
20
|
+
if (query.running || !root.queryDrained)
|
|
21
|
+
return
|
|
22
|
+
root.queryDrained = false
|
|
23
|
+
root.queryToken = lift
|
|
24
|
+
query.running = true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Exit must clear running and drain old stdout before the next token starts.
|
|
28
|
+
function restartLatest() {
|
|
29
|
+
if (!query.running && root.queryDrained && root.queryToken !== root.token) root.begin(root.token, root.strip)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Process {
|
|
33
|
+
id: query
|
|
34
|
+
command: ["hyprctl", "clients", "-j"]
|
|
35
|
+
onExited: Qt.callLater(root.restartLatest)
|
|
36
|
+
stdout: StdioCollector {
|
|
37
|
+
waitForEnd: true
|
|
38
|
+
onStreamFinished: {
|
|
39
|
+
root.queryDrained = true
|
|
40
|
+
Qt.callLater(root.restartLatest)
|
|
41
|
+
if (root.queryToken !== root.token)
|
|
42
|
+
return
|
|
43
|
+
try {
|
|
44
|
+
// Sample input: [{"pid":111,"at":[0,0],"size":[900,500],"mapped":true,"hidden":false}].
|
|
45
|
+
var clients = JSON.parse(text)
|
|
46
|
+
var matches = clients.filter(function (client) {
|
|
47
|
+
return String(client.pid) === String(Quickshell.processId)
|
|
48
|
+
&& client.mapped !== false && client.hidden !== true
|
|
49
|
+
})
|
|
50
|
+
if (matches.length === 1) {
|
|
51
|
+
var client = matches[0]
|
|
52
|
+
if (client.at && client.size && isFinite(client.at[0]) && isFinite(client.at[1])
|
|
53
|
+
&& client.size[0] > 0 && client.size[1] > 0)
|
|
54
|
+
root.rect = { x: client.at[0], y: client.at[1], width: client.size[0], height: client.size[1] }
|
|
55
|
+
}
|
|
56
|
+
} catch (error) { root.rect = null }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import "js/Tags.js" as Tags
|
|
3
|
+
|
|
4
|
+
// A Tags flyout row's rule-14 box and swatch, built only for those rows; the box is the root so it anchors as a sibling of the hint.
|
|
5
|
+
Item {
|
|
6
|
+
id: root
|
|
7
|
+
required property Item row
|
|
8
|
+
required property Item mark
|
|
9
|
+
required property Item hint
|
|
10
|
+
readonly property var tagRow: root.row.entry.tagRow || ({ swatch: "", fallback: false, state: Tags.ABSENT, digit: "" })
|
|
11
|
+
readonly property color ink: root.row.labelColor
|
|
12
|
+
// The thinnest mixed bar.
|
|
13
|
+
readonly property int mixedBarMin: 2
|
|
14
|
+
visible: root.row.entry.tagRow !== undefined
|
|
15
|
+
anchors.right: root.hint.left
|
|
16
|
+
anchors.rightMargin: Theme.spacing.gap
|
|
17
|
+
anchors.verticalCenter: parent.verticalCenter
|
|
18
|
+
width: Tags.SWATCH_SIZE
|
|
19
|
+
height: Tags.SWATCH_SIZE
|
|
20
|
+
|
|
21
|
+
Rectangle {
|
|
22
|
+
anchors.fill: parent
|
|
23
|
+
color: "transparent"
|
|
24
|
+
border.width: Theme.spacing.hairline
|
|
25
|
+
border.color: root.ink
|
|
26
|
+
opacity: root.row.available ? 1 : Theme.disabledOpacity
|
|
27
|
+
}
|
|
28
|
+
Glyph {
|
|
29
|
+
anchors.fill: parent
|
|
30
|
+
visible: root.tagRow.state === Tags.APPLIED
|
|
31
|
+
name: "check"
|
|
32
|
+
color: root.ink
|
|
33
|
+
}
|
|
34
|
+
Rectangle {
|
|
35
|
+
visible: root.tagRow.state === Tags.MIXED
|
|
36
|
+
anchors.left: parent.left
|
|
37
|
+
anchors.right: parent.right
|
|
38
|
+
anchors.verticalCenter: parent.verticalCenter
|
|
39
|
+
height: Math.max(root.mixedBarMin, Theme.spacing.hairline * 2)
|
|
40
|
+
color: root.ink
|
|
41
|
+
}
|
|
42
|
+
// Reparented to the mark slot, so the swatch is centred in it as the glyph would be.
|
|
43
|
+
TagSwatch {
|
|
44
|
+
parent: root.mark
|
|
45
|
+
anchors.centerIn: parent
|
|
46
|
+
visible: root.visible
|
|
47
|
+
swatch: root.tagRow.swatch
|
|
48
|
+
fallback: root.tagRow.fallback
|
|
49
|
+
digit: root.tagRow.digit
|
|
50
|
+
tagColors: Theme.tag.menuColors
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
pragma ComponentBehavior: Bound
|
|
2
|
+
|
|
3
|
+
import QtQuick
|
|
4
|
+
import qs.Commons
|
|
5
|
+
import "js/Tags.js" as Tags
|
|
6
|
+
|
|
7
|
+
// The rail's TAGS section: the heading and one row per tag in use. The rail builds it once, when the setting is on and a tag is in use.
|
|
8
|
+
Column {
|
|
9
|
+
id: root
|
|
10
|
+
required property var sidebar
|
|
11
|
+
width: parent.width
|
|
12
|
+
// A rail that follows a pane with no tag in use draws no heading, and the network gap reserves no height for it.
|
|
13
|
+
visible: sidebar.placesState.showTags === true && root.entries.length > 0
|
|
14
|
+
height: root.visible ? root.implicitHeight : 0
|
|
15
|
+
// Guarded as Sidebar.tagsListed is, because the rail can move to a pane that has built no tag state.
|
|
16
|
+
readonly property var entries: Tags.railEntries(root.sidebar.navigationPane !== null && root.sidebar.navigationPane.tagState !== null
|
|
17
|
+
? root.sidebar.navigationPane.tagState.inUse : ({}))
|
|
18
|
+
// Where this section's first row stands among the rail's entries.
|
|
19
|
+
readonly property int base: root.sidebar.placesEntries.length - root.entries.length
|
|
20
|
+
function itemAt(i) { return tagRepeater.itemAt(i) }
|
|
21
|
+
// The Loader sizes its item to the 13 px slot, so the 14 px swatch is a child the Loader leaves alone.
|
|
22
|
+
Component {
|
|
23
|
+
id: markComponent
|
|
24
|
+
Item {
|
|
25
|
+
id: slot
|
|
26
|
+
property var entry: ({})
|
|
27
|
+
TagSwatch {
|
|
28
|
+
anchors.centerIn: parent
|
|
29
|
+
swatch: slot.entry.swatch || ""
|
|
30
|
+
fallback: Theme.tag.fallback
|
|
31
|
+
digit: slot.entry.digit || ""
|
|
32
|
+
tagColors: Theme.tag.menuColors
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
RailHeading {
|
|
38
|
+
text: "TAGS"
|
|
39
|
+
topExtra: Style.spacing.panelGap
|
|
40
|
+
}
|
|
41
|
+
Repeater {
|
|
42
|
+
id: tagRepeater
|
|
43
|
+
model: root.entries
|
|
44
|
+
delegate: SidebarRow {
|
|
45
|
+
lit: index + root.base === root.sidebar.litIndex
|
|
46
|
+
highlighted: index + root.base === root.sidebar.highlightedIndex
|
|
47
|
+
cursor: root.sidebar.cursorDrawn && index + root.base === root.sidebar.cursorIndex
|
|
48
|
+
focused: root.sidebar.focused
|
|
49
|
+
tagMark: markComponent
|
|
50
|
+
onActivated: function (idx) { root.sidebar.activate(idx + root.base) }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
package/ui/TagSlot.qml
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
pragma ComponentBehavior: Bound
|
|
2
|
+
|
|
3
|
+
import QtQuick
|
|
4
|
+
import "js/Tags.js" as Tags
|
|
5
|
+
|
|
6
|
+
// One row's tag swatches: 14 px squares at 3 px gaps, each carrying its digit in the fallback.
|
|
7
|
+
Item {
|
|
8
|
+
id: root
|
|
9
|
+
readonly property int swatchGap: 3
|
|
10
|
+
property var tags: []
|
|
11
|
+
// A row reserves the 88 px slot and a tile its own cell, so only the whole swatches that fit are drawn, with no counter.
|
|
12
|
+
readonly property real room: root.below && root.parent ? root.parent.width : Theme.tagSlotWidth
|
|
13
|
+
readonly property var drawn: root.tags.slice(0, Math.max(0, Math.floor((root.room + root.swatchGap) / (Tags.SWATCH_SIZE + root.swatchGap))))
|
|
14
|
+
// The item this slot follows on a row, or the caption it sits under on a tile; hug follows a text's own end.
|
|
15
|
+
property Item after: null
|
|
16
|
+
property Item below: null
|
|
17
|
+
property bool hug: false
|
|
18
|
+
visible: root.tags.length > 0
|
|
19
|
+
width: Math.max(0, root.drawn.length * (Tags.SWATCH_SIZE + root.swatchGap) - root.swatchGap)
|
|
20
|
+
height: Tags.SWATCH_SIZE
|
|
21
|
+
anchors.left: root.after ? (root.hug ? root.after.left : root.after.right) : undefined
|
|
22
|
+
anchors.leftMargin: root.after && root.hug ? root.after.contentWidth + Theme.spacing.gap : Theme.spacing.gap
|
|
23
|
+
anchors.verticalCenter: root.after ? root.after.verticalCenter : undefined
|
|
24
|
+
anchors.top: root.below ? root.below.bottom : undefined
|
|
25
|
+
anchors.horizontalCenter: root.below ? parent.horizontalCenter : undefined
|
|
26
|
+
|
|
27
|
+
Repeater {
|
|
28
|
+
model: root.drawn
|
|
29
|
+
delegate: TagSwatch {
|
|
30
|
+
id: cell
|
|
31
|
+
required property int index
|
|
32
|
+
required property string modelData
|
|
33
|
+
x: cell.index * (Tags.SWATCH_SIZE + root.swatchGap)
|
|
34
|
+
swatch: cell.modelData
|
|
35
|
+
fallback: Theme.tag.fallback
|
|
36
|
+
digit: Tags.keyFor(cell.modelData)
|
|
37
|
+
tagColors: Theme.tag.colors
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
package/ui/TagState.qml
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import "js/Filter.js" as Filter
|
|
3
|
+
import "js/Menu.js" as Menu
|
|
4
|
+
import "js/Ops.js" as Ops
|
|
5
|
+
import "js/Search.js" as Search
|
|
6
|
+
import "js/Tags.js" as Tags
|
|
7
|
+
|
|
8
|
+
// One pane's file tags, built only when a listing first carries one or a tag key or menu first asks.
|
|
9
|
+
Item {
|
|
10
|
+
id: root
|
|
11
|
+
required property var pane
|
|
12
|
+
// The 88 px slot stands on every row of a folder once a tagged row has been seen in it.
|
|
13
|
+
property bool latched: false
|
|
14
|
+
// Every tag this session has seen set, which is what the rail's TAGS section lists.
|
|
15
|
+
property var inUse: ({})
|
|
16
|
+
// The changes sent and not yet answered, oldest first; each settagged answer or settags refusal takes the oldest.
|
|
17
|
+
property var pending: []
|
|
18
|
+
// The backend's read of a selection reaching past the held window, and the one still out.
|
|
19
|
+
property var asked: null
|
|
20
|
+
property var asking: null
|
|
21
|
+
property int askId: 0
|
|
22
|
+
|
|
23
|
+
// A rows reply is the whole held window; a fresh listing starts the latch over.
|
|
24
|
+
function take(items, fresh) {
|
|
25
|
+
var seen = Tags.stamp(items, root.latched, root.inUse, fresh)
|
|
26
|
+
root.latched = seen.latched
|
|
27
|
+
if (seen.grew) root.inUse = Object.assign({}, root.inUse)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Each target's tags while every target is in the held window; null once one is outside it, where only the backend knows.
|
|
31
|
+
function filesFor(indices) {
|
|
32
|
+
var files = []
|
|
33
|
+
for (var i = 0; i < indices.length; i++) {
|
|
34
|
+
var row = root.pane.rowFor(indices[i])
|
|
35
|
+
if (!row) return null
|
|
36
|
+
files.push(row.tg || [])
|
|
37
|
+
}
|
|
38
|
+
return files
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Names the selection a backend read answers for: the numbering, the selection's version and, with no selection, the cursor.
|
|
42
|
+
function selectionKey() {
|
|
43
|
+
var pane = root.pane
|
|
44
|
+
return pane.backend.heldListing + ":" + pane.selectionVersion + ":" + (pane.selectionCount() > 0 ? "" : pane.cursorIndex)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// The flyout's rows for the selection: seven tags with digit hints, then Remove all tags; absent until a backend read lands.
|
|
48
|
+
function flyout() {
|
|
49
|
+
var files = root.filesFor(Ops.targetIndices(root.pane))
|
|
50
|
+
if (files !== null) return Tags.tagEntries(Tags.statesFor(files), Theme.tag.fallback)
|
|
51
|
+
var asked = root.asked !== null && root.asked.key === root.selectionKey() ? root.asked : null
|
|
52
|
+
return Tags.tagEntries(asked ? Tags.statesFrom(asked.applied, asked.mixed) : {}, Theme.tag.fallback)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// A selection past the held window asks what its rows carry (again: re-ask after a write); the answer redraws the flyout.
|
|
56
|
+
function ask(again) {
|
|
57
|
+
var rows = Ops.targetIndices(root.pane)
|
|
58
|
+
if (rows.length === 0 || root.filesFor(rows) !== null) return
|
|
59
|
+
var key = root.selectionKey()
|
|
60
|
+
if (again !== true && ((root.asked !== null && root.asked.key === key) || (root.asking !== null && root.asking.key === key))) return
|
|
61
|
+
root.askId += 1
|
|
62
|
+
root.asking = { id: root.askId, key: key, listing: root.pane.backend.heldListing }
|
|
63
|
+
root.pane.backend.send({ c: "tagstates", rows: rows, id: root.askId })
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// A flyout choice toggles that tag over the selection, or clears every tag off it; the backend decides add or remove for all.
|
|
67
|
+
function choose(name) {
|
|
68
|
+
var rows = Ops.targetIndices(root.pane)
|
|
69
|
+
if (rows.length === 0) return
|
|
70
|
+
var clear = name === Tags.CLEAR_ID
|
|
71
|
+
root.pending = root.pending.concat([{ tag: clear ? "" : name }])
|
|
72
|
+
root.pane.backend.send({ c: "settags", rows: rows, op: clear ? "clear" : "toggle", tag: clear ? "" : name })
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// T opens the Tags flyout straight from the listing, the same list the menu's Tags row opens.
|
|
76
|
+
function openMenu() {
|
|
77
|
+
var pane = root.pane
|
|
78
|
+
if (pane.lockedTarget.length > 0) return
|
|
79
|
+
if (!pane.canTag) {
|
|
80
|
+
pane.message("This filesystem does not support file tags.", true)
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
var menu = pane.contextMenu()
|
|
84
|
+
if (!Menu.openAtCursor(pane, menu, Theme.spacing.rowPaddingX)) return
|
|
85
|
+
for (var i = 0; i < menu.entries.length; i++) {
|
|
86
|
+
if (menu.entries[i].action === "tags") {
|
|
87
|
+
menu.openSubmenu(i)
|
|
88
|
+
return
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// A tag walks Home for that tag, an explicit walk like any search; esc returns to the listing.
|
|
94
|
+
function openTag(name) {
|
|
95
|
+
if (!name || !Search.takesQuery(root.pane)) return
|
|
96
|
+
Filter.close(root.pane)
|
|
97
|
+
Search.openQuery(root.pane, "tag:" + name)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// A tagstates answer for the read still out lands only in the numbering it was asked in.
|
|
101
|
+
function statesDone(message) {
|
|
102
|
+
var asking = root.asking
|
|
103
|
+
if (asking === null || message.id !== asking.id) return
|
|
104
|
+
root.asking = null
|
|
105
|
+
if (message.listing !== asking.listing) return
|
|
106
|
+
root.asked = { key: asking.key, applied: message.applied || [], mixed: message.mixed || [] }
|
|
107
|
+
root.pane.contextMenu().refreshProviderRows()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// A settagged answer lands the oldest pending change: forget every read made before it, ask the visible window again, and say it when a file changed or a row was skipped.
|
|
111
|
+
function setTaggedDone(message) {
|
|
112
|
+
var change = root.pending.length > 0 ? root.pending[0] : null
|
|
113
|
+
root.pending = root.pending.slice(1)
|
|
114
|
+
var flyoutUp = root.pane.menuVisible === true
|
|
115
|
+
// An open flyout keeps drawing its last read until the fresh one lands, so no box blanks between the two.
|
|
116
|
+
if (!flyoutUp) root.asked = null
|
|
117
|
+
root.asking = null
|
|
118
|
+
if (!change) return
|
|
119
|
+
root.pane.backend.window(root.pane.held, root.pane.windowSize)
|
|
120
|
+
if (flyoutUp) root.ask(true)
|
|
121
|
+
// The backend sends data and the UI words it: the changed sentence, the skipped one, or both.
|
|
122
|
+
var line = Tags.doneLine(message.op, message.ok || 0, change.tag, message.skipped)
|
|
123
|
+
if (line !== "") root.pane.message(line, false)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// A held window that lands while a flyout is up carries the tags just written; the menu's rows source follows it a turn later, so the redraw waits for that turn.
|
|
127
|
+
Connections {
|
|
128
|
+
target: root.pane
|
|
129
|
+
function onRowsChanged() {
|
|
130
|
+
var menu = root.pane.contextMenu()
|
|
131
|
+
if (menu.submenuOpen === true) Qt.callLater(function() { menu.refreshProviderRows() })
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
Connections {
|
|
136
|
+
target: root.pane.backend
|
|
137
|
+
function onTagStatesResult(message) { root.statesDone(message) }
|
|
138
|
+
function onSettagged(message) { root.setTaggedDone(message) }
|
|
139
|
+
// A refused settags answers its own pending change; a backend that stopped answers none of them.
|
|
140
|
+
function onFailed(where, input) {
|
|
141
|
+
if (where === "backend" || where === "read") {
|
|
142
|
+
root.pending = []
|
|
143
|
+
root.asked = null
|
|
144
|
+
root.asking = null
|
|
145
|
+
} else if (where === "settags" || (where === "stale" && input === "settags")) {
|
|
146
|
+
root.pending = root.pending.slice(1)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
package/ui/TagSwatch.qml
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import "js/Tags.js" as Tags
|
|
3
|
+
|
|
4
|
+
// One tag swatch: the fill, the fallback border, the digit text.
|
|
5
|
+
Rectangle {
|
|
6
|
+
id: root
|
|
7
|
+
property string swatch: ""
|
|
8
|
+
property bool fallback: false
|
|
9
|
+
property string digit: ""
|
|
10
|
+
required property var tagColors
|
|
11
|
+
property int size: Tags.SWATCH_SIZE
|
|
12
|
+
readonly property int fallbackBorder: 2
|
|
13
|
+
width: root.size
|
|
14
|
+
height: root.size
|
|
15
|
+
color: root.fallback ? "transparent" : root.tagColors[root.swatch] || "transparent"
|
|
16
|
+
border.width: root.fallback ? root.fallbackBorder : 0
|
|
17
|
+
border.color: root.tagColors[root.swatch] || "transparent"
|
|
18
|
+
Text {
|
|
19
|
+
visible: root.fallback
|
|
20
|
+
anchors.centerIn: parent
|
|
21
|
+
text: root.digit
|
|
22
|
+
color: root.tagColors[root.swatch] || "transparent"
|
|
23
|
+
font.family: Theme.font.family
|
|
24
|
+
font.pixelSize: Theme.font.caption
|
|
25
|
+
font.bold: true
|
|
26
|
+
textFormat: Text.PlainText
|
|
27
|
+
}
|
|
28
|
+
}
|
package/ui/Taildrop.qml
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import Quickshell
|
|
3
|
+
import Quickshell.Io
|
|
4
|
+
import "js/Taildrop.js" as TaildropJs
|
|
5
|
+
|
|
6
|
+
// The context menu's own Service, the same shape as ui/NetworkMounts.qml: this is the only thing
|
|
7
|
+
// here that touches tailscale, ui/ContextMenu.qml only reads "peers" and renders it.
|
|
8
|
+
Item {
|
|
9
|
+
id: root
|
|
10
|
+
|
|
11
|
+
property var peers: []
|
|
12
|
+
property string reason: "checking"
|
|
13
|
+
// What state the reason is, for logic: ui/js/Taildrop.js status() names the codes.
|
|
14
|
+
property string code: ""
|
|
15
|
+
property string sendCommand: ""
|
|
16
|
+
property bool checking: false
|
|
17
|
+
property bool _awaitingStart: false
|
|
18
|
+
// The OEM Tailscale service's pollWatchdog bounds status queries at fifteen seconds.
|
|
19
|
+
readonly property int statusTimeoutSeconds: 15
|
|
20
|
+
signal refreshed()
|
|
21
|
+
// onExited can race the StdioCollector's own text, see ui/NetworkMounts.qml's header comment.
|
|
22
|
+
property string _statusOutput: ""
|
|
23
|
+
property string _statusError: ""
|
|
24
|
+
|
|
25
|
+
function refresh(facts) {
|
|
26
|
+
if (checking) return false
|
|
27
|
+
peers = []
|
|
28
|
+
var provider = facts.taildrop || {}, sender = facts.taildropSend || {}
|
|
29
|
+
sendCommand = sender.command || ""
|
|
30
|
+
reason = provider.reason || sender.reason || "checking"
|
|
31
|
+
code = ""
|
|
32
|
+
if (!provider.command || !sendCommand) return true
|
|
33
|
+
checking = true
|
|
34
|
+
_awaitingStart = true
|
|
35
|
+
_statusOutput = ""
|
|
36
|
+
_statusError = ""
|
|
37
|
+
statusProcess.command = ["timeout", "--signal=KILL", String(statusTimeoutSeconds), provider.command, "status", "--json"]
|
|
38
|
+
statusProcess.running = true
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// argv-direct and detached: the script owns its own success/failure notification, see
|
|
43
|
+
// docs/superpowers/specs/2026-08-31-flea-operations-design.md "4.1 Taildrop".
|
|
44
|
+
function send(peerId, paths) {
|
|
45
|
+
var peer = TaildropJs.byId(root.peers, peerId)
|
|
46
|
+
if (!peer || !sendCommand || checking) return false
|
|
47
|
+
Quickshell.execDetached([sendCommand, peer.address].concat(paths))
|
|
48
|
+
return true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ui/Pane.qml's own dispatch-confirmation message reads a name, not the id chosen() carries.
|
|
52
|
+
function labelFor(peerId) {
|
|
53
|
+
var peer = TaildropJs.byId(root.peers, peerId)
|
|
54
|
+
return peer ? peer.label : "that peer"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
Process {
|
|
58
|
+
id: statusProcess
|
|
59
|
+
stdout: StdioCollector {
|
|
60
|
+
id: statusOut
|
|
61
|
+
waitForEnd: true
|
|
62
|
+
onStreamFinished: root._statusOutput = text
|
|
63
|
+
}
|
|
64
|
+
stderr: StdioCollector { id: statusErr; waitForEnd: true; onStreamFinished: root._statusError = text }
|
|
65
|
+
onStarted: root._awaitingStart = false
|
|
66
|
+
onRunningChanged: {
|
|
67
|
+
if (root._awaitingStart && !running) {
|
|
68
|
+
root._awaitingStart = false
|
|
69
|
+
root.checking = false
|
|
70
|
+
root.reason = "Tailscale could not be checked"
|
|
71
|
+
root.code = ""
|
|
72
|
+
root.refreshed()
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
onExited: function (exitCode) {
|
|
76
|
+
root._awaitingStart = false
|
|
77
|
+
var state = TaildropJs.status(statusOut.text || root._statusOutput, exitCode,
|
|
78
|
+
exitCode === 137 || exitCode === 9 ? "Tailscale did not answer in time" : statusErr.text || root._statusError)
|
|
79
|
+
root.peers = state.peers
|
|
80
|
+
root.reason = state.reason
|
|
81
|
+
root.code = state.code
|
|
82
|
+
root.checking = false
|
|
83
|
+
root.refreshed()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import qs.Commons
|
|
3
|
+
|
|
4
|
+
// The Tailscale mark, reproduced from the official artwork rather than recut. Decided on the
|
|
5
|
+
// reproduction after both recuts were rendered beside the original at the sizes this actually draws
|
|
6
|
+
// at: a stroked mark spends most of a small glyph on outline, and a one-weight language cannot carry
|
|
7
|
+
// the mark's own emphasis. It sits where FleaMark sits, outside the cut and outside Glyph.qml.
|
|
8
|
+
Item {
|
|
9
|
+
id: root
|
|
10
|
+
|
|
11
|
+
// The type scale, not the slot, and clamped so a reproduction can never out-size the cut glyph
|
|
12
|
+
// beside it. A smaller caller slot still wins, the way Glyph's own min() lets it.
|
|
13
|
+
property real iconSize: Theme.markSize
|
|
14
|
+
property color color: "transparent"
|
|
15
|
+
|
|
16
|
+
// The official file's own box and geometry: circles of radius 18 at 30.5, 84.5 and 138.5.
|
|
17
|
+
readonly property real grid: 169
|
|
18
|
+
readonly property real dotRadius: 18
|
|
19
|
+
readonly property var centres: [30.5, 84.5, 138.5]
|
|
20
|
+
// The official draws the middle row plus the bottom centre solid and the rest at 0.4; the two
|
|
21
|
+
// opacities are the mark, because the brand toolkit says the gray dots adapt in opacity.
|
|
22
|
+
readonly property real mutedOpacity: 0.4
|
|
23
|
+
readonly property real drawn: Math.min(Theme.markSize, root.iconSize)
|
|
24
|
+
readonly property real unit: root.drawn / root.grid
|
|
25
|
+
|
|
26
|
+
implicitWidth: root.drawn
|
|
27
|
+
implicitHeight: root.drawn
|
|
28
|
+
width: root.drawn
|
|
29
|
+
height: root.drawn
|
|
30
|
+
|
|
31
|
+
Repeater {
|
|
32
|
+
model: 9
|
|
33
|
+
|
|
34
|
+
delegate: Rectangle {
|
|
35
|
+
required property int index
|
|
36
|
+
readonly property int row: Math.floor(index / 3)
|
|
37
|
+
readonly property int col: index % 3
|
|
38
|
+
// Row 1 is the middle row, and column 1 of row 2 is the bottom centre.
|
|
39
|
+
readonly property bool solid: row === 1 || (row === 2 && col === 1)
|
|
40
|
+
|
|
41
|
+
width: 2 * root.dotRadius * root.unit
|
|
42
|
+
height: width
|
|
43
|
+
radius: width / 2
|
|
44
|
+
x: root.centres[col] * root.unit - width / 2
|
|
45
|
+
y: root.centres[row] * root.unit - height / 2
|
|
46
|
+
color: root.color
|
|
47
|
+
opacity: solid ? 1.0 : root.mutedOpacity
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
pragma Singleton
|
|
2
|
+
import QtQuick
|
|
3
|
+
import Quickshell
|
|
4
|
+
import Quickshell.Io
|
|
5
|
+
|
|
6
|
+
// All terminal views share this one server; each has its own reconnect token/PTY.
|
|
7
|
+
QtObject {
|
|
8
|
+
id: root
|
|
9
|
+
property var tabs: ({})
|
|
10
|
+
property int serial: 0
|
|
11
|
+
property bool ready: false
|
|
12
|
+
property bool stopping: false
|
|
13
|
+
function acquire(path) {
|
|
14
|
+
var id = "terminal-" + (++serial)
|
|
15
|
+
var next = Object.assign({}, tabs)
|
|
16
|
+
next[id] = { path: path, url: "", error: "" }
|
|
17
|
+
tabs = next
|
|
18
|
+
if (!server.running && !stopping) server.running = true
|
|
19
|
+
if (ready) server.write(JSON.stringify({id:id,path:path}) + "\n")
|
|
20
|
+
return id
|
|
21
|
+
}
|
|
22
|
+
function release(id) {
|
|
23
|
+
var next = Object.assign({}, tabs)
|
|
24
|
+
delete next[id]
|
|
25
|
+
tabs = next
|
|
26
|
+
if (Object.keys(next).length === 0) {
|
|
27
|
+
ready = false
|
|
28
|
+
if (server.running && !stopping) {
|
|
29
|
+
stopping = true
|
|
30
|
+
server.write(JSON.stringify({shutdown:true}) + "\n")
|
|
31
|
+
}
|
|
32
|
+
} else if (ready) server.write(JSON.stringify({id:id,close:true}) + "\n")
|
|
33
|
+
}
|
|
34
|
+
function fail(message) {
|
|
35
|
+
ready = false
|
|
36
|
+
var next = {}
|
|
37
|
+
for (var id in tabs) next[id] = { path: tabs[id].path, url: "", error: message }
|
|
38
|
+
tabs = next
|
|
39
|
+
}
|
|
40
|
+
property var process: Process {
|
|
41
|
+
id: server
|
|
42
|
+
stdinEnabled: true
|
|
43
|
+
command: [Quickshell.env("BUNINU_BUN") || "bun", Quickshell.shellDir + "/../../src/terminal-server.js"]
|
|
44
|
+
stdout: SplitParser {
|
|
45
|
+
onRead: function(line) {
|
|
46
|
+
try {
|
|
47
|
+
var result = JSON.parse(line)
|
|
48
|
+
if (result.ready) {
|
|
49
|
+
if (root.stopping) return
|
|
50
|
+
root.ready = true
|
|
51
|
+
for (var id in root.tabs) if (!root.tabs[id].error) server.write(JSON.stringify({id:id,path:root.tabs[id].path}) + "\n")
|
|
52
|
+
} else if (result.id && root.tabs[result.id]) {
|
|
53
|
+
var next = Object.assign({}, root.tabs)
|
|
54
|
+
next[result.id] = { path: next[result.id].path, url: result.url || "", error: result.error || "" }
|
|
55
|
+
root.tabs = next
|
|
56
|
+
} else if (!result.id && result.error) root.fail(result.error)
|
|
57
|
+
} catch(e) { root.fail("Invalid terminal server response.") }
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
onExited: {
|
|
61
|
+
if (root.stopping) {
|
|
62
|
+
root.stopping = false
|
|
63
|
+
root.ready = false
|
|
64
|
+
// A tab opened during shutdown waits for the old listener to exit.
|
|
65
|
+
if (Object.keys(root.tabs).length) Qt.callLater(function() { server.running = true })
|
|
66
|
+
} else root.fail("Terminal server exited.")
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import QtWebEngine
|
|
3
|
+
import Quickshell
|
|
4
|
+
import "." as Flea
|
|
5
|
+
import Quickshell.Io
|
|
6
|
+
import qs.Commons
|
|
7
|
+
|
|
8
|
+
// Kept alive while another tab is selected; destroyed only when this tab closes.
|
|
9
|
+
Item {
|
|
10
|
+
id: root
|
|
11
|
+
property string directory: ""
|
|
12
|
+
property string sessionId: ""
|
|
13
|
+
readonly property var session: Flea.TerminalService.tabs[sessionId] || ({})
|
|
14
|
+
readonly property string address: session.url || ""
|
|
15
|
+
readonly property string status: session.error || "Starting terminal…"
|
|
16
|
+
property bool selected: false
|
|
17
|
+
function focusTerminal() {
|
|
18
|
+
if (selected && address.length) Qt.callLater(function() {
|
|
19
|
+
if (root.selected && root.address.length) web.forceActiveFocus()
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
onSelectedChanged: focusTerminal()
|
|
23
|
+
onAddressChanged: focusTerminal()
|
|
24
|
+
visible: selected
|
|
25
|
+
anchors.fill: parent
|
|
26
|
+
Rectangle { anchors.fill: parent; color: Theme.color.background }
|
|
27
|
+
WebEngineView {
|
|
28
|
+
id: web
|
|
29
|
+
anchors.fill: parent
|
|
30
|
+
visible: root.address.length > 0
|
|
31
|
+
url: root.address
|
|
32
|
+
backgroundColor: Theme.color.background
|
|
33
|
+
settings.javascriptEnabled: true
|
|
34
|
+
onLoadingChanged: function(info) { if(info.errorCode) console.warn("Terminal WebEngineView:", info.errorString) }
|
|
35
|
+
}
|
|
36
|
+
Text {
|
|
37
|
+
anchors.centerIn: parent
|
|
38
|
+
width: Math.max(0, parent.width - 32)
|
|
39
|
+
horizontalAlignment: Text.AlignHCenter
|
|
40
|
+
wrapMode: Text.Wrap
|
|
41
|
+
textFormat: Text.PlainText
|
|
42
|
+
color: Theme.color.foreground
|
|
43
|
+
font.family: Theme.font.family
|
|
44
|
+
font.pixelSize: Theme.font.body
|
|
45
|
+
visible: root.address.length === 0
|
|
46
|
+
text: root.status
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import QtQuick
|
|
2
|
+
import "." as Flea
|
|
3
|
+
|
|
4
|
+
// Dynamic objects preserve each iframe/PTY when tab order or selection changes.
|
|
5
|
+
Item {
|
|
6
|
+
id: root
|
|
7
|
+
property var pane: null
|
|
8
|
+
property var sessions: ({})
|
|
9
|
+
function open(directory) {
|
|
10
|
+
var component = Qt.createComponent("TerminalTab.qml")
|
|
11
|
+
if (component.status !== Component.Ready) {
|
|
12
|
+
pane.message(component.errorString(), true)
|
|
13
|
+
return ""
|
|
14
|
+
}
|
|
15
|
+
var key = Flea.TerminalService.acquire(directory)
|
|
16
|
+
var item = component.createObject(root, { directory: directory, sessionId: key })
|
|
17
|
+
if (!item) { Flea.TerminalService.release(key); pane.message("Could not create the terminal view.", true); return "" }
|
|
18
|
+
item.selected = Qt.binding(function() { return root.pane.terminalId === key })
|
|
19
|
+
sessions[key] = item
|
|
20
|
+
return key
|
|
21
|
+
}
|
|
22
|
+
Component.onDestruction: { for (var key in sessions) Flea.TerminalService.release(key) }
|
|
23
|
+
function close(key) {
|
|
24
|
+
var item = sessions[key]
|
|
25
|
+
if (item) { Flea.TerminalService.release(key); delete sessions[key]; item.destroy() }
|
|
26
|
+
}
|
|
27
|
+
}
|