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.
Files changed (637) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +511 -2
  3. package/THIRD-PARTY-NOTICES.md +29 -0
  4. package/demos/App.java +5 -0
  5. package/demos/Dockerfile +4 -0
  6. package/demos/Main.kt +3 -0
  7. package/demos/Program.cs +1 -0
  8. package/demos/README.md +12 -0
  9. package/demos/app.dart +3 -0
  10. package/demos/app.deb +0 -0
  11. package/demos/app.js +1 -0
  12. package/demos/backup.tar +0 -0
  13. package/demos/budget.xlsx +0 -0
  14. package/demos/build.sh +2 -0
  15. package/demos/bundle.zip +0 -0
  16. package/demos/clip.mp4 +0 -0
  17. package/demos/data.sqlite +0 -0
  18. package/demos/disk.iso +0 -0
  19. package/demos/engine.cpp +5 -0
  20. package/demos/firmware.bin +0 -0
  21. package/demos/flake.nix +4 -0
  22. package/demos/folder/inside.txt +1 -0
  23. package/demos/font.ttf +0 -0
  24. package/demos/index.html +5 -0
  25. package/demos/index.php +2 -0
  26. package/demos/init.lua +1 -0
  27. package/demos/letter.docx +0 -0
  28. package/demos/lib.rs +3 -0
  29. package/demos/main.c +6 -0
  30. package/demos/main.h +3 -0
  31. package/demos/math-and-diagrams.md +200 -0
  32. package/demos/notes.tar.gz +0 -0
  33. package/demos/notes.txt +3 -0
  34. package/demos/photo.png +0 -0
  35. package/demos/program +2 -0
  36. package/demos/report.pdf +32 -0
  37. package/demos/script.py +1 -0
  38. package/demos/server.go +7 -0
  39. package/demos/settings.json +4 -0
  40. package/demos/slides.pptx +0 -0
  41. package/demos/song.mp3 +0 -0
  42. package/demos/style.css +4 -0
  43. package/demos/tool.rb +1 -0
  44. package/demos/types.ts +2 -0
  45. package/docs/pele.md +23 -0
  46. package/docs/protocol.md +3420 -0
  47. package/docs/temml.md +63 -0
  48. package/index.js +107 -0
  49. package/package.json +34 -4
  50. package/src/archive.js +407 -0
  51. package/src/archiveops.js +728 -0
  52. package/src/backend.js +369 -0
  53. package/src/bulkrename.js +95 -0
  54. package/src/clip-host.js +76 -0
  55. package/src/clip.js +462 -0
  56. package/src/code.js +168 -0
  57. package/src/compare.js +74 -0
  58. package/src/create.js +128 -0
  59. package/src/dirsize.js +147 -0
  60. package/src/figure-svg.js +530 -0
  61. package/src/figure-thread.js +23 -0
  62. package/src/figure.js +132 -0
  63. package/src/find.js +55 -0
  64. package/src/flea.js +39 -0
  65. package/src/fsinfo.js +39 -0
  66. package/src/highlight.js +141 -0
  67. package/src/html.js +52 -0
  68. package/src/kinds.js +89 -0
  69. package/src/listing.js +130 -0
  70. package/src/markdown-html.js +317 -0
  71. package/src/mathml.js +186 -0
  72. package/src/menu.js +180 -0
  73. package/src/meta.js +135 -0
  74. package/src/office.js +810 -0
  75. package/src/order.js +100 -0
  76. package/src/peek.js +49 -0
  77. package/src/pele-wrapper.js +695 -0
  78. package/src/permissions.js +180 -0
  79. package/src/places.js +313 -0
  80. package/src/preview-language.js +10 -0
  81. package/src/terminal-server.js +95 -0
  82. package/src/terminal-shell.js +26 -0
  83. package/src/transfer.js +669 -0
  84. package/src/trash-record.js +41 -0
  85. package/src/trash.js +210 -0
  86. package/src/trashbrowse.js +327 -0
  87. package/src/uistate.js +393 -0
  88. package/src/uistore.js +168 -0
  89. package/src/vendor/LICENSES/Apache-2.0.txt +202 -0
  90. package/src/vendor/LICENSES/MIT-katex-2015.txt +27 -0
  91. package/src/vendor/LICENSES/MIT-katex.txt +21 -0
  92. package/src/vendor/LICENSES/MIT-mermaid.txt +21 -0
  93. package/src/vendor/LICENSES/MIT-pele.txt +40 -0
  94. package/src/vendor/LICENSES/MIT-perseus.txt +18 -0
  95. package/src/vendor/LICENSES/MIT-temml.txt +21 -0
  96. package/src/vendor/pele.js +145 -0
  97. package/src/vendor/temml.mjs +14708 -0
  98. package/src/watch.js +98 -0
  99. package/src/wayland/client.js +109 -0
  100. package/src/wayland/protocol.js +55 -0
  101. package/src/wayland/protocols/ext-data-control-v1.xml +276 -0
  102. package/src/wayland/protocols/wayland.xml +3248 -0
  103. package/src/wayland/protocols/wlr-data-control-unstable-v1.xml +278 -0
  104. package/src/wayland/resource-io.js +6 -0
  105. package/src/wayland/socket-discovery.js +26 -0
  106. package/src/wayland/transport-posix.js +120 -0
  107. package/src/wayland/transport-win32.js +11 -0
  108. package/src/wayland/transport.js +3 -0
  109. package/src/wayland/win32-resources.js +80 -0
  110. package/src/wayland/win32-wire.js +62 -0
  111. package/test/archive.test.js +80 -0
  112. package/test/bench-markdown-scroll.mjs +190 -0
  113. package/test/clip-host.test.js +113 -0
  114. package/test/code-preview.test.js +35 -0
  115. package/test/compare-ui-paths.test.js +24 -0
  116. package/test/compare.test.js +54 -0
  117. package/test/delete-trash.test.js +67 -0
  118. package/test/dirsize.test.js +138 -0
  119. package/test/file-ops.test.js +307 -0
  120. package/test/file-url.test.js +24 -0
  121. package/test/find-contents.test.js +161 -0
  122. package/test/find-input.test.js +66 -0
  123. package/test/fixtures/pele-parity.json +1006 -0
  124. package/test/highlight-launcher.test.js +35 -0
  125. package/test/html-preview.test.js +22 -0
  126. package/test/input.test.js +15 -0
  127. package/test/keymap.test.js +26 -0
  128. package/test/language-icons.test.js +36 -0
  129. package/test/launcher.test.js +51 -0
  130. package/test/manual-archive-here-ui.mjs +47 -0
  131. package/test/manual-code-scroll.mjs +28 -0
  132. package/test/manual-column-scroll.mjs +24 -0
  133. package/test/manual-compare-ui.mjs +20 -0
  134. package/test/manual-find-status.mjs +37 -0
  135. package/test/manual-folder-focus.mjs +63 -0
  136. package/test/manual-html-security.mjs +23 -0
  137. package/test/manual-html-ui.mjs +30 -0
  138. package/test/manual-syntax-preview.mjs +26 -0
  139. package/test/manual-terminal-lifecycle.mjs +42 -0
  140. package/test/manual-terminal-navigation.mjs +48 -0
  141. package/test/manual-terminal-ui.mjs +47 -0
  142. package/test/manual-trash-ui.mjs +86 -0
  143. package/test/markdown-diagrams.test.js +93 -0
  144. package/test/markdown-html.test.js +105 -0
  145. package/test/mathml.test.js +92 -0
  146. package/test/menu-transfer.test.js +57 -0
  147. package/test/office-preview.test.js +154 -0
  148. package/test/pele-parity.test.js +28 -0
  149. package/test/places.test.js +134 -0
  150. package/test/preview-keys.test.js +60 -0
  151. package/test/preview-language.test.js +22 -0
  152. package/test/status-filename.test.js +20 -0
  153. package/test/transfer-replace-merge.test.js +187 -0
  154. package/test/trash-address.test.js +23 -0
  155. package/test/trash-view.test.js +37 -0
  156. package/test/trashbrowse.test.js +135 -0
  157. package/ui/AboutFacts.qml +78 -0
  158. package/ui/ArchiveCards.qml +95 -0
  159. package/ui/ArchiveCompressDialog.qml +378 -0
  160. package/ui/ArchiveHereConfirm.qml +127 -0
  161. package/ui/ArchivePasswordDialog.qml +257 -0
  162. package/ui/Backend.qml +775 -0
  163. package/ui/BulkOldNames.qml +47 -0
  164. package/ui/BulkRenameDialog.qml +380 -0
  165. package/ui/CardFrame.qml +67 -0
  166. package/ui/CardScroll.qml +79 -0
  167. package/ui/CheckBox.qml +73 -0
  168. package/ui/ChromeBar.qml +360 -0
  169. package/ui/ChromeButton.qml +131 -0
  170. package/ui/ChromeModes.qml +43 -0
  171. package/ui/CodeLines.qml +256 -0
  172. package/ui/CodeRefusal.qml +52 -0
  173. package/ui/CollideConfirm.qml +147 -0
  174. package/ui/CollideHost.qml +167 -0
  175. package/ui/ColumnPane.qml +525 -0
  176. package/ui/ColumnRow.qml +380 -0
  177. package/ui/ColumnsArea.qml +594 -0
  178. package/ui/ColumnsLanding.qml +147 -0
  179. package/ui/CompareView.qml +321 -0
  180. package/ui/ContextMenu.qml +743 -0
  181. package/ui/ConvertDialog.qml +456 -0
  182. package/ui/CountedWorker.qml +7 -0
  183. package/ui/Crumb.qml +64 -0
  184. package/ui/CrumbDrop.qml +25 -0
  185. package/ui/CsvTable.qml +394 -0
  186. package/ui/CursorMark.qml +41 -0
  187. package/ui/DefaultClaim.qml +130 -0
  188. package/ui/DeviceLock.qml +47 -0
  189. package/ui/DeviceMounts.qml +540 -0
  190. package/ui/DialogButton.qml +150 -0
  191. package/ui/DialogField.qml +147 -0
  192. package/ui/DialogHeader.qml +31 -0
  193. package/ui/DialogScrim.qml +20 -0
  194. package/ui/DialogTitle.qml +37 -0
  195. package/ui/Divider.qml +9 -0
  196. package/ui/DropInto.qml +126 -0
  197. package/ui/DropTarget.qml +35 -0
  198. package/ui/DropboxMark.qml +60 -0
  199. package/ui/EmptyState.qml +150 -0
  200. package/ui/EscapeHint.qml +11 -0
  201. package/ui/FactsTable.qml +54 -0
  202. package/ui/FastScrollHandler.qml +476 -0
  203. package/ui/FatNamesConfirm.qml +157 -0
  204. package/ui/Favourites.qml +143 -0
  205. package/ui/FigureService.qml +120 -0
  206. package/ui/FileDrag.qml +267 -0
  207. package/ui/FilterStrip.qml +133 -0
  208. package/ui/FitMetrics.qml +22 -0
  209. package/ui/FlashDriveRows.qml +137 -0
  210. package/ui/FlashHost.qml +72 -0
  211. package/ui/FlashImageRow.qml +104 -0
  212. package/ui/FlashRunner.qml +119 -0
  213. package/ui/FlashStepRow.qml +172 -0
  214. package/ui/FlashStrip.qml +38 -0
  215. package/ui/FlashView.qml +397 -0
  216. package/ui/FleaMark.qml +88 -0
  217. package/ui/FlyoutFade.qml +23 -0
  218. package/ui/FontPane.qml +170 -0
  219. package/ui/Glass.qml +114 -0
  220. package/ui/GlassTagger.qml +59 -0
  221. package/ui/Glyph.qml +64 -0
  222. package/ui/GlyphSolid.qml +22 -0
  223. package/ui/GridArea.qml +664 -0
  224. package/ui/GridTile.qml +325 -0
  225. package/ui/GvfsBridge.qml +164 -0
  226. package/ui/Header.qml +433 -0
  227. package/ui/HoverTimers.qml +39 -0
  228. package/ui/HtmlClip.qml +30 -0
  229. package/ui/HtmlPane.qml +63 -0
  230. package/ui/HyprlandMark.qml +45 -0
  231. package/ui/Ipc.qml +1005 -0
  232. package/ui/IpcControls.qml +7 -0
  233. package/ui/IpcMenuState.qml +48 -0
  234. package/ui/IpcPreviewState.qml +185 -0
  235. package/ui/JumpPath.qml +51 -0
  236. package/ui/KeymapSheet.qml +561 -0
  237. package/ui/KeymapSheetResult.qml +89 -0
  238. package/ui/KindStack.qml +40 -0
  239. package/ui/LangMark.qml +51 -0
  240. package/ui/LangMarkLoader.qml +26 -0
  241. package/ui/List.qml +480 -0
  242. package/ui/LoadingState.qml +54 -0
  243. package/ui/LocalSend.qml +56 -0
  244. package/ui/LocalSendMark.qml +73 -0
  245. package/ui/MarkdownBlockView.qml +311 -0
  246. package/ui/MarkdownBlocks.qml +35 -0
  247. package/ui/MarkdownFigure.qml +254 -0
  248. package/ui/MarkdownImages.qml +72 -0
  249. package/ui/MarkdownList.qml +81 -0
  250. package/ui/MarkdownMathsText.qml +97 -0
  251. package/ui/MarkdownPane.qml +83 -0
  252. package/ui/MarkdownPictures.qml +41 -0
  253. package/ui/MarkdownQuote.qml +52 -0
  254. package/ui/MarkdownRemote.qml +82 -0
  255. package/ui/MarkdownSource.qml +155 -0
  256. package/ui/MarkdownTable.qml +222 -0
  257. package/ui/MarkdownTableScroll.qml +64 -0
  258. package/ui/MarkdownTableWheel.qml +126 -0
  259. package/ui/MarkdownText.qml +87 -0
  260. package/ui/MarkdownWorker.js +132 -0
  261. package/ui/MatchText.qml +99 -0
  262. package/ui/MediaSession.qml +38 -0
  263. package/ui/MediaSound.qml +26 -0
  264. package/ui/MediaStrip.qml +191 -0
  265. package/ui/MediaTrack.qml +36 -0
  266. package/ui/MediaVolume.qml +54 -0
  267. package/ui/MenuActionDialog.qml +396 -0
  268. package/ui/MenuEdgeFade.qml +24 -0
  269. package/ui/MenuHost.qml +227 -0
  270. package/ui/MenuRow.qml +351 -0
  271. package/ui/MountListing.qml +100 -0
  272. package/ui/NetworkDialog.qml +435 -0
  273. package/ui/NetworkForm.qml +426 -0
  274. package/ui/NetworkMounts.qml +913 -0
  275. package/ui/NetworkPlaces.qml +127 -0
  276. package/ui/OpenWithDialog.qml +613 -0
  277. package/ui/Opener.qml +95 -0
  278. package/ui/Pane.qml +1320 -0
  279. package/ui/PaneMenuActions.qml +527 -0
  280. package/ui/PanePath.qml +90 -0
  281. package/ui/PaneRail.qml +268 -0
  282. package/ui/PaneStates.qml +88 -0
  283. package/ui/PaneSwap.qml +339 -0
  284. package/ui/PaneWire.qml +601 -0
  285. package/ui/ParkedWait.qml +9 -0
  286. package/ui/PathEntry.qml +186 -0
  287. package/ui/PathJump.qml +400 -0
  288. package/ui/PdfViewer.qml +297 -0
  289. package/ui/PermissionsDialog.qml +658 -0
  290. package/ui/PermissionsHeadings.qml +31 -0
  291. package/ui/PhoneMounts.qml +67 -0
  292. package/ui/PickerAnswers.qml +75 -0
  293. package/ui/PickerBox.qml +26 -0
  294. package/ui/PickerChrome.qml +295 -0
  295. package/ui/PickerFilter.qml +97 -0
  296. package/ui/PickerGrid.qml +308 -0
  297. package/ui/PickerHeader.qml +28 -0
  298. package/ui/PickerLifecycle.qml +27 -0
  299. package/ui/PickerList.qml +218 -0
  300. package/ui/PickerListing.qml +149 -0
  301. package/ui/PickerPathBar.qml +127 -0
  302. package/ui/PickerPlaces.qml +189 -0
  303. package/ui/PickerRecent.qml +92 -0
  304. package/ui/PickerSave.qml +101 -0
  305. package/ui/PickerSelection.qml +155 -0
  306. package/ui/PickerWindow.qml +846 -0
  307. package/ui/PowerSectorsReader.qml +10 -0
  308. package/ui/PrebuildDriver.qml +146 -0
  309. package/ui/Preview.qml +1005 -0
  310. package/ui/PreviewAnimation.qml +24 -0
  311. package/ui/PreviewArchive.qml +91 -0
  312. package/ui/PreviewColumn.qml +553 -0
  313. package/ui/PreviewEdge.qml +63 -0
  314. package/ui/PreviewFacts.qml +30 -0
  315. package/ui/PreviewFactsLine.qml +34 -0
  316. package/ui/PreviewHtml.qml +233 -0
  317. package/ui/PreviewImage.qml +253 -0
  318. package/ui/PreviewImagePan.qml +13 -0
  319. package/ui/PreviewImageSharp.qml +32 -0
  320. package/ui/PreviewLines.qml +106 -0
  321. package/ui/PreviewMarkdown.qml +706 -0
  322. package/ui/PreviewMedia.qml +250 -0
  323. package/ui/PreviewPdf.qml +482 -0
  324. package/ui/PreviewScroll.qml +201 -0
  325. package/ui/PreviewSwap.qml +335 -0
  326. package/ui/PreviewText.qml +149 -0
  327. package/ui/ProtocolChip.qml +18 -0
  328. package/ui/QuickLookArchive.qml +41 -0
  329. package/ui/QuickLookBar.qml +103 -0
  330. package/ui/QuickLookPrepare.qml +355 -0
  331. package/ui/QuickLookSwap.qml +10 -0
  332. package/ui/QuickLookWarm.qml +65 -0
  333. package/ui/RailDrop.qml +155 -0
  334. package/ui/RailHeading.qml +19 -0
  335. package/ui/RailPlaces.qml +38 -0
  336. package/ui/RailTrashRow.qml +67 -0
  337. package/ui/RenameField.qml +353 -0
  338. package/ui/RendererRetry.qml +11 -0
  339. package/ui/ResizeHandle.qml +52 -0
  340. package/ui/Reveal.qml +54 -0
  341. package/ui/Row.qml +476 -0
  342. package/ui/RowDrag.qml +213 -0
  343. package/ui/RowDropTarget.qml +27 -0
  344. package/ui/RunCard.qml +286 -0
  345. package/ui/Scripts.qml +65 -0
  346. package/ui/SearchStrip.qml +232 -0
  347. package/ui/SelectionBand.qml +140 -0
  348. package/ui/SelectionPreview.qml +370 -0
  349. package/ui/SettingsFavourite.qml +122 -0
  350. package/ui/SettingsGroup.qml +96 -0
  351. package/ui/SettingsHint.qml +12 -0
  352. package/ui/SettingsMetrics.qml +29 -0
  353. package/ui/SettingsPane.qml +178 -0
  354. package/ui/SettingsPanel.qml +547 -0
  355. package/ui/SettingsRail.qml +128 -0
  356. package/ui/SettingsRow.qml +409 -0
  357. package/ui/SettingsRuler.qml +85 -0
  358. package/ui/SettingsSegment.qml +85 -0
  359. package/ui/ShareBrowser.qml +113 -0
  360. package/ui/ShareLink.qml +67 -0
  361. package/ui/ShelfPins.qml +101 -0
  362. package/ui/Sidebar.qml +728 -0
  363. package/ui/SidebarRow.qml +358 -0
  364. package/ui/Spinner.qml +60 -0
  365. package/ui/StableModel.qml +89 -0
  366. package/ui/StateMessage.qml +84 -0
  367. package/ui/StatusBar.qml +512 -0
  368. package/ui/StatusFileName.qml +27 -0
  369. package/ui/TabBar.qml +673 -0
  370. package/ui/TabDragGeometry.qml +60 -0
  371. package/ui/TagMenuMark.qml +52 -0
  372. package/ui/TagRailSection.qml +53 -0
  373. package/ui/TagSlot.qml +40 -0
  374. package/ui/TagState.qml +150 -0
  375. package/ui/TagSwatch.qml +28 -0
  376. package/ui/Taildrop.qml +86 -0
  377. package/ui/TailscaleMark.qml +50 -0
  378. package/ui/TerminalService.qml +69 -0
  379. package/ui/TerminalTab.qml +48 -0
  380. package/ui/TerminalTabs.qml +27 -0
  381. package/ui/Theme.qml +460 -0
  382. package/ui/ThemeColors.qml +43 -0
  383. package/ui/TransferCard.qml +239 -0
  384. package/ui/TrashConfirm.qml +129 -0
  385. package/ui/TrashDropHandler.qml +11 -0
  386. package/ui/TrashHost.qml +202 -0
  387. package/ui/TrashMonitor.qml +30 -0
  388. package/ui/TrashToolbar.qml +19 -0
  389. package/ui/TrashView.qml +492 -0
  390. package/ui/UnlockDialog.qml +450 -0
  391. package/ui/UnlockHost.qml +206 -0
  392. package/ui/UpdateCheck.qml +97 -0
  393. package/ui/UserDirs.qml +25 -0
  394. package/ui/ViewState.qml +565 -0
  395. package/ui/ViewportScrollBar.qml +195 -0
  396. package/ui/ViewportScrollBars.qml +25 -0
  397. package/ui/WebPreview.qml +33 -0
  398. package/ui/WebPreviewView.qml +26 -0
  399. package/ui/WindowBody.qml +829 -0
  400. package/ui/WindowDrag.qml +35 -0
  401. package/ui/boot/Commons/AudioNodes.qml +50 -0
  402. package/ui/boot/Commons/AudioNodesModel.js +96 -0
  403. package/ui/boot/Commons/Border.qml +243 -0
  404. package/ui/boot/Commons/BorderGeometry.js +373 -0
  405. package/ui/boot/Commons/Color.qml +258 -0
  406. package/ui/boot/Commons/I18n.qml +118 -0
  407. package/ui/boot/Commons/InputDevices.qml +112 -0
  408. package/ui/boot/Commons/InputMethodState.qml +38 -0
  409. package/ui/boot/Commons/IpcRegistry.qml +77 -0
  410. package/ui/boot/Commons/Numbers.js +19 -0
  411. package/ui/boot/Commons/Plural.js +91 -0
  412. package/ui/boot/Commons/ShellIpc.qml +12 -0
  413. package/ui/boot/Commons/Style.qml +561 -0
  414. package/ui/boot/Commons/Translations.qml +100 -0
  415. package/ui/boot/Commons/UntypedInput.qml +152 -0
  416. package/ui/boot/Commons/Util.qml +188 -0
  417. package/ui/boot/Commons/qmldir +13 -0
  418. package/ui/boot/LICENSE-omarchy +20 -0
  419. package/ui/boot/Ui/BackgroundMedia.qml +49 -0
  420. package/ui/boot/Ui/BarIconButton.qml +106 -0
  421. package/ui/boot/Ui/BarIconContent.qml +38 -0
  422. package/ui/boot/Ui/BarIndicator.qml +53 -0
  423. package/ui/boot/Ui/BarWidget.qml +50 -0
  424. package/ui/boot/Ui/BorderOverlay.qml +54 -0
  425. package/ui/boot/Ui/BorderSurface.qml +40 -0
  426. package/ui/boot/Ui/Button.qml +224 -0
  427. package/ui/boot/Ui/ButtonGroup.qml +131 -0
  428. package/ui/boot/Ui/ConfirmDialog.qml +134 -0
  429. package/ui/boot/Ui/CursorSurface.qml +42 -0
  430. package/ui/boot/Ui/Dropdown.qml +245 -0
  431. package/ui/boot/Ui/FilterInput.qml +26 -0
  432. package/ui/boot/Ui/IconContentBounds.qml +141 -0
  433. package/ui/boot/Ui/KeyboardPanel.qml +453 -0
  434. package/ui/boot/Ui/MultiSelect.qml +624 -0
  435. package/ui/boot/Ui/NumberField.qml +86 -0
  436. package/ui/boot/Ui/OpticalGlyph.qml +68 -0
  437. package/ui/boot/Ui/OverlayWindow.qml +102 -0
  438. package/ui/boot/Ui/Panel.qml +60 -0
  439. package/ui/boot/Ui/PanelActionButton.qml +105 -0
  440. package/ui/boot/Ui/PanelController.qml +16 -0
  441. package/ui/boot/Ui/PanelHero.qml +112 -0
  442. package/ui/boot/Ui/PanelKeyCatcher.qml +100 -0
  443. package/ui/boot/Ui/PanelSectionHeader.qml +31 -0
  444. package/ui/boot/Ui/PanelSeparator.qml +19 -0
  445. package/ui/boot/Ui/PanelSlider.qml +156 -0
  446. package/ui/boot/Ui/PanelToolTip.qml +50 -0
  447. package/ui/boot/Ui/PluginBarApi.qml +89 -0
  448. package/ui/boot/Ui/PointerMoveGate.qml +54 -0
  449. package/ui/boot/Ui/PopupCard.qml +181 -0
  450. package/ui/boot/Ui/ScreenMoveRemap.qml +43 -0
  451. package/ui/boot/Ui/SearchableDropdown.qml +354 -0
  452. package/ui/boot/Ui/SizedImage.qml +125 -0
  453. package/ui/boot/Ui/SpeedTestOverlay.qml +412 -0
  454. package/ui/boot/Ui/TextField.qml +58 -0
  455. package/ui/boot/Ui/Toggle.qml +118 -0
  456. package/ui/boot/Ui/ToggleSwitch.qml +115 -0
  457. package/ui/boot/Ui/WidgetButton.qml +172 -0
  458. package/ui/boot/Ui/qmldir +41 -0
  459. package/ui/boot/fleatab.qml +50 -0
  460. package/ui/boot/picker.qml +39 -0
  461. package/ui/boot/shell.qml +131 -0
  462. package/ui/boot/tabtearoff.qml +51 -0
  463. package/ui/js/Anchor.js +379 -0
  464. package/ui/js/AnchorHold.js +162 -0
  465. package/ui/js/Archive.js +157 -0
  466. package/ui/js/ArchiveCard.js +44 -0
  467. package/ui/js/ArchiveOps.js +44 -0
  468. package/ui/js/BackReturn.js +118 -0
  469. package/ui/js/BulkRename.js +100 -0
  470. package/ui/js/Buttons.js +54 -0
  471. package/ui/js/ChromeKeys.js +116 -0
  472. package/ui/js/ClipMarks.js +73 -0
  473. package/ui/js/ClipSelection.js +67 -0
  474. package/ui/js/Clipboard.js +179 -0
  475. package/ui/js/Cloud.js +97 -0
  476. package/ui/js/CodeRuns.js +72 -0
  477. package/ui/js/Collide.js +212 -0
  478. package/ui/js/ColumnFit.js +28 -0
  479. package/ui/js/ColumnMenu.js +111 -0
  480. package/ui/js/Columns.js +298 -0
  481. package/ui/js/ColumnsCarry.js +103 -0
  482. package/ui/js/Compare.js +74 -0
  483. package/ui/js/Contrast.js +157 -0
  484. package/ui/js/ControlReader.js +42 -0
  485. package/ui/js/Convert.js +52 -0
  486. package/ui/js/CopyAs.js +52 -0
  487. package/ui/js/Crumbs.js +178 -0
  488. package/ui/js/Csv.js +231 -0
  489. package/ui/js/Density.js +44 -0
  490. package/ui/js/Devices.js +440 -0
  491. package/ui/js/DirSizes.js +180 -0
  492. package/ui/js/Drag.js +360 -0
  493. package/ui/js/DragOut.js +166 -0
  494. package/ui/js/DropDev.js +52 -0
  495. package/ui/js/Dropbox.js +41 -0
  496. package/ui/js/Eject.js +217 -0
  497. package/ui/js/Errors.js +188 -0
  498. package/ui/js/ExtThumbs.js +115 -0
  499. package/ui/js/Facts.js +402 -0
  500. package/ui/js/FigureDate.js +14 -0
  501. package/ui/js/Filter.js +285 -0
  502. package/ui/js/Find.js +46 -0
  503. package/ui/js/Flash.js +184 -0
  504. package/ui/js/FlashCard.js +79 -0
  505. package/ui/js/FlashEndings.js +125 -0
  506. package/ui/js/FlashPane.js +116 -0
  507. package/ui/js/FleaBin.js +12 -0
  508. package/ui/js/Focus.js +504 -0
  509. package/ui/js/FolderSorts.js +108 -0
  510. package/ui/js/FolderViews.js +44 -0
  511. package/ui/js/Format.js +314 -0
  512. package/ui/js/Fuzzy.js +141 -0
  513. package/ui/js/GlassTag.js +72 -0
  514. package/ui/js/Grid.js +33 -0
  515. package/ui/js/GridGeometry.js +90 -0
  516. package/ui/js/GridNames.js +153 -0
  517. package/ui/js/GvfsBridge.js +200 -0
  518. package/ui/js/HostClipboard.js +29 -0
  519. package/ui/js/Icons.js +218 -0
  520. package/ui/js/Input.js +50 -0
  521. package/ui/js/Jump.js +200 -0
  522. package/ui/js/KeyName.js +64 -0
  523. package/ui/js/Keymap.js +401 -0
  524. package/ui/js/Kinds.js +164 -0
  525. package/ui/js/LICENSES/ISC-lucide.txt +43 -0
  526. package/ui/js/LangMarkPaths.js +47 -0
  527. package/ui/js/LangMarks.js +120 -0
  528. package/ui/js/Lists.js +11 -0
  529. package/ui/js/LocalSend.js +39 -0
  530. package/ui/js/LockedMenu.js +63 -0
  531. package/ui/js/MakeDefault.js +186 -0
  532. package/ui/js/MarkBox.js +7 -0
  533. package/ui/js/Markdown.js +119 -0
  534. package/ui/js/MarkdownLists.js +86 -0
  535. package/ui/js/MarkdownMaths.js +58 -0
  536. package/ui/js/MarkdownPictures.js +32 -0
  537. package/ui/js/MarkdownPrepared.js +139 -0
  538. package/ui/js/MarkdownTableFit.js +34 -0
  539. package/ui/js/Marks.js +148 -0
  540. package/ui/js/Marquee.js +96 -0
  541. package/ui/js/Match.js +93 -0
  542. package/ui/js/Material.js +109 -0
  543. package/ui/js/MdBlocks.js +437 -0
  544. package/ui/js/MdBreak.js +71 -0
  545. package/ui/js/MdChunks.js +70 -0
  546. package/ui/js/MdContainer.js +137 -0
  547. package/ui/js/MdDocument.js +337 -0
  548. package/ui/js/MdEmph.js +97 -0
  549. package/ui/js/MdEntity.js +108 -0
  550. package/ui/js/MdEntityTable.js +223 -0
  551. package/ui/js/MdEscape.js +59 -0
  552. package/ui/js/MdFront.js +37 -0
  553. package/ui/js/MdHold.js +32 -0
  554. package/ui/js/MdHtml.js +307 -0
  555. package/ui/js/MdHtmlBlock.js +290 -0
  556. package/ui/js/MdHtmlHeading.js +53 -0
  557. package/ui/js/MdHtmlImage.js +179 -0
  558. package/ui/js/MdInline.js +154 -0
  559. package/ui/js/MdItems.js +212 -0
  560. package/ui/js/MdLeaf.js +309 -0
  561. package/ui/js/MdLink.js +196 -0
  562. package/ui/js/MdMath.js +67 -0
  563. package/ui/js/MdParagraphs.js +138 -0
  564. package/ui/js/MdRefs.js +232 -0
  565. package/ui/js/MdResolve.js +226 -0
  566. package/ui/js/MdRun.js +300 -0
  567. package/ui/js/MdUrl.js +226 -0
  568. package/ui/js/Menu.js +514 -0
  569. package/ui/js/MenuContext.js +85 -0
  570. package/ui/js/MenuFit.js +13 -0
  571. package/ui/js/MenuRefresh.js +74 -0
  572. package/ui/js/MenuWheel.js +35 -0
  573. package/ui/js/Messages.js +186 -0
  574. package/ui/js/Motion.js +16 -0
  575. package/ui/js/Mounts.js +320 -0
  576. package/ui/js/MouseNav.js +13 -0
  577. package/ui/js/Nav.js +329 -0
  578. package/ui/js/NetFs.js +26 -0
  579. package/ui/js/OpenWith.js +83 -0
  580. package/ui/js/Ops.js +585 -0
  581. package/ui/js/Palette.js +33 -0
  582. package/ui/js/PathBar.js +260 -0
  583. package/ui/js/Permissions.js +179 -0
  584. package/ui/js/Phones.js +112 -0
  585. package/ui/js/Picker.js +353 -0
  586. package/ui/js/PlaceMenu.js +96 -0
  587. package/ui/js/Places.js +265 -0
  588. package/ui/js/PreviewAsk.js +21 -0
  589. package/ui/js/PreviewKeys.js +155 -0
  590. package/ui/js/PreviewSettle.js +29 -0
  591. package/ui/js/PreviewSwap.js +101 -0
  592. package/ui/js/PropertyFacts.js +144 -0
  593. package/ui/js/Protocols.js +296 -0
  594. package/ui/js/QuickLookKinds.js +27 -0
  595. package/ui/js/QuickLookRect.js +24 -0
  596. package/ui/js/RailDrop.js +51 -0
  597. package/ui/js/RailKeys.js +87 -0
  598. package/ui/js/RailMenu.js +133 -0
  599. package/ui/js/Recent.js +135 -0
  600. package/ui/js/RecentMode.js +156 -0
  601. package/ui/js/Reload.js +60 -0
  602. package/ui/js/Renderer.js +9 -0
  603. package/ui/js/RunFile.js +143 -0
  604. package/ui/js/Scripts.js +28 -0
  605. package/ui/js/Scroll.js +304 -0
  606. package/ui/js/ScrollOff.js +69 -0
  607. package/ui/js/Search.js +478 -0
  608. package/ui/js/Selection.js +97 -0
  609. package/ui/js/Settings.js +476 -0
  610. package/ui/js/SettingsAbout.js +97 -0
  611. package/ui/js/SettingsShelf.js +52 -0
  612. package/ui/js/SheetKeys.js +42 -0
  613. package/ui/js/SheetQuery.js +281 -0
  614. package/ui/js/ShelfPile.js +27 -0
  615. package/ui/js/SlowClick.js +53 -0
  616. package/ui/js/SlowOp.js +6 -0
  617. package/ui/js/Sort.js +134 -0
  618. package/ui/js/Startup.js +63 -0
  619. package/ui/js/StateWords.js +17 -0
  620. package/ui/js/Status.js +238 -0
  621. package/ui/js/Swap.js +166 -0
  622. package/ui/js/TabMove.js +39 -0
  623. package/ui/js/Tabs.js +751 -0
  624. package/ui/js/Tags.js +134 -0
  625. package/ui/js/Taildrop.js +128 -0
  626. package/ui/js/Tap.js +180 -0
  627. package/ui/js/TextSize.js +107 -0
  628. package/ui/js/Thumbs.js +158 -0
  629. package/ui/js/Transfer.js +172 -0
  630. package/ui/js/Trash.js +84 -0
  631. package/ui/js/TrashDates.js +47 -0
  632. package/ui/js/TrashDrop.js +64 -0
  633. package/ui/js/UiState.js +438 -0
  634. package/ui/js/Unlock.js +152 -0
  635. package/ui/js/Update.js +130 -0
  636. package/ui/js/UserDirs.js +56 -0
  637. package/ui/qmldir +230 -0
@@ -0,0 +1,358 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "js/Eject.js" as Eject
4
+ import "js/Format.js" as Format
5
+ import "js/TabMove.js" as TabMove
6
+
7
+ // One rail row, shared by the Favorites, Network and Devices groups so the three read alike; see
8
+ // ui/Sidebar.qml "The rail" for the entry shape each group feeds this delegate.
9
+ Item {
10
+ id: root
11
+
12
+ required property int index
13
+ required property var modelData
14
+ // Current-place identity stays separate from the keyboard's visual highlight, including over IPC.
15
+ property bool lit: false
16
+ property bool highlighted: root.lit
17
+ property bool cursor: false
18
+ property bool focused: false
19
+ // A drop cue replaces the trailing detail and reserves its caption's width.
20
+ property Item trailingLabel: null
21
+ // The keyboard is on this row's eject mark, which then draws its own frame in the foreground at its hit box.
22
+ property bool markFocused: false
23
+ // Network only, driven from ui/Sidebar.qml's renamingIndex; swaps the label for the editor.
24
+ property bool renaming: false
25
+
26
+ signal activated(int index)
27
+ // A click on the eject mark releases the row at once, the same Eject or Unmount the
28
+ // menu row and Ctrl+E take; carrying the index, because the rail rebuilds on its poll
29
+ // and a position taken later can name a different row.
30
+ signal ejectRequested(int index)
31
+ // Right click asks the rail to raise the menu over this row, carrying the point it opens at.
32
+ // The rail decides what the menu offers and opens none on a row with nothing to release. It is
33
+ // ui/Pane.qml's own single ui/ContextMenu.qml: a second instance in this tree took the keyboard
34
+ // away from the list, see AGENTS.md "A second ContextMenu instance breaks the whole window's
35
+ // keyboard focus", which is why the rail had no menu at all until now.
36
+ signal menuRequested(int index, var scenePosition)
37
+ // Middle click: the row's folder in a new tab; ui/js/PlaceMenu.js openTabAt decides which rows have one.
38
+ signal tabRequested(int index)
39
+ signal renameCommitted(int index, string text)
40
+ signal renameCancelled(int index)
41
+ // Favourites reorder by drag; a favourite carries its store index, others leave -1.
42
+ property int dragFrom: -1
43
+ property int lineCount: 0
44
+ signal moved(int to)
45
+ signal reorderAt(int line)
46
+
47
+ // A share or a removable volume carries a mount-state dot; the internal disk is always there
48
+ // and always mounted, so a dot on it would say nothing, and a favourite is not a mount at all.
49
+ readonly property var placesState: ViewState.state.places || ({})
50
+ // The eject mark's accessible name, one whole sentence per kind of row, each filled by Format.fill.
51
+ readonly property var ejectWords: ({ eject: "Eject %1", unmount: "Unmount %1" })
52
+ readonly property string detail: root.modelData.kind === "trash"
53
+ ? (root.placesState.trashCount === true && root.modelData.count > 0 ? String(root.modelData.count) : "")
54
+ : (root.modelData.group === "device" || root.modelData.volume === true) && root.placesState.driveSize === true && root.modelData.size !== null
55
+ ? Format.size(root.modelData.size) : ""
56
+ // PhoneMark: a phone is a volume, so its row carries the same mount-state square a removable
57
+ // disk and a share carry, in the same fixed slot.
58
+ readonly property bool showsDot: (root.modelData.group === "network" && root.modelData.kind !== "dropbox")
59
+ || (root.modelData.group === "device"
60
+ && (root.modelData.kind === "volume" || root.modelData.kind === "phone"))
61
+ // The Trash row draws its count where every other row draws its indicator, and never both.
62
+ readonly property bool countIsIndicator: root.modelData.kind === "trash" && root.detail.length > 0
63
+ // Small and fixed: a status dot is not part of the type or icon scale.
64
+ readonly property int dotSize: 6
65
+ // The canvas's own value for a bookmark nothing has mounted yet.
66
+ readonly property real unmountedOpacity: 0.5
67
+
68
+ // The favourite under the pointer while its reorder drag runs; it ghosts the way a dragged tab does, the bar says where it lands.
69
+ property bool held: false
70
+ opacity: root.held ? Theme.disabledOpacity : 1
71
+
72
+ width: parent ? parent.width : 0
73
+ // The rail reads denser than the list it sits beside; see Theme.qml's railRowHeight comment.
74
+ height: Theme.railRowHeight
75
+
76
+ Accessible.role: Accessible.ListItem
77
+ Accessible.name: root.modelData.label
78
+
79
+ // The rail rounds nothing: a lit place is the list row's square full-bleed fill, see ui/Row.qml.
80
+ Rectangle {
81
+ anchors.fill: parent
82
+ color: root.highlighted
83
+ ? (root.modelData.kind === "trash" ? Style.selectedAccentFill : root.focused ? Style.selectedFill : Style.normalFill)
84
+ : "transparent"
85
+ }
86
+
87
+ // The eject mark's hover lift, the board's 8% rung; the mark itself lifts to foreground below.
88
+ Rectangle {
89
+ anchors.fill: parent
90
+ visible: ejectLoader.item !== null && ejectLoader.item.hovered
91
+ color: Theme.color.foreground
92
+ opacity: Theme.washHover
93
+ }
94
+
95
+ Rectangle {
96
+ visible: root.highlighted
97
+ width: Theme.spacing.hairline * 2
98
+ height: parent.height
99
+ color: Theme.color.accent
100
+ }
101
+
102
+ // The TAGS section hands its rows their own swatch mark; every other row keeps the glyph.
103
+ property Component tagMark: null
104
+
105
+ Loader {
106
+ id: mark
107
+ anchors.left: parent.left
108
+ anchors.leftMargin: Style.spacing.rowPaddingX
109
+ anchors.verticalCenter: parent.verticalCenter
110
+ width: Theme.railIconSize
111
+ height: Theme.railIconSize
112
+ sourceComponent: root.modelData.kind === "dropbox" ? dropboxMark : root.tagMark !== null ? root.tagMark : glyphMark
113
+ onLoaded: if (root.tagMark !== null) item.entry = root.modelData
114
+ }
115
+
116
+ // ThemeRoles.html gives every rail label and glyph the foreground role, selected rows included:
117
+ // the cursor reads through the fill and the accent edge above, never by dimming the rows it is not on.
118
+ Component {
119
+ id: glyphMark
120
+ Glyph {
121
+ name: root.modelData.glyph
122
+ color: root.highlighted && root.modelData.kind === "trash" ? Theme.color.accent : Theme.color.foreground
123
+ }
124
+ }
125
+
126
+ // The brand marks are reproductions, so they take their own component rather than Glyph sizing.
127
+ Component {
128
+ id: dropboxMark
129
+ DropboxMark {
130
+ iconSize: Theme.railIconSize
131
+ color: Theme.color.foreground
132
+ }
133
+ }
134
+
135
+ Text {
136
+ id: label
137
+ visible: !root.renaming
138
+ anchors.left: mark.right
139
+ anchors.leftMargin: Style.spacing.rowGap
140
+ // The label ends one gap before any trailing number, square or mark.
141
+ anchors.right: root.trailingLabel ? parent.right : root.detail.length > 0 ? detailText.left : dot.left
142
+ anchors.rightMargin: root.trailingLabel ? Math.min(root.width - label.x,
143
+ Theme.spacing.rowPaddingX + root.trailingLabel.implicitWidth + Theme.spacing.gap)
144
+ : root.keepsTrailingGap ? Style.spacing.rowGap : 0
145
+ anchors.verticalCenter: parent.verticalCenter
146
+ text: root.modelData.label
147
+ color: root.modelData.error ? Theme.color.error : Theme.color.foreground
148
+ font.family: Theme.font.family
149
+ font.pixelSize: Theme.font.body
150
+ // A label too long for the rail keeps its start and ends in an ellipsis.
151
+ elide: Text.ElideRight
152
+ clip: root.trailingLabel !== null
153
+ textFormat: Text.PlainText
154
+ }
155
+
156
+ // The label's slot, holding the product's one editor, ui/RenameField.qml, in rail type.
157
+ Loader {
158
+ id: renameLoader
159
+ active: root.renaming
160
+ anchors.left: mark.right
161
+ anchors.leftMargin: Style.spacing.rowGap
162
+ anchors.right: root.detail.length > 0 ? detailText.left : dot.left
163
+ anchors.rightMargin: root.keepsTrailingGap ? Style.spacing.rowGap : 0
164
+ // The editor owns its height, one line box; the rail row centres it on whole pixels.
165
+ y: Math.round((root.height - renameLoader.height) / 2)
166
+ sourceComponent: RenameField {
167
+ height: implicitHeight
168
+ name: root.modelData.label
169
+ onCommitted: function (newName) { root.renameCommitted(root.index, newName) }
170
+ onAbandoned: root.renameCancelled(root.index)
171
+ }
172
+ }
173
+
174
+ // What the editor holds right now, for tests through ui/Ipc.qml's railRenameEditorText.
175
+ readonly property string editorText: renameLoader.item ? renameLoader.item.current : ""
176
+ readonly property bool editorShown: renameLoader.item !== null && renameLoader.item.visible
177
+ // The rail's editor as ui/Row.qml hands its own, so a test measures every host's frame the same way.
178
+ readonly property Item editorField: renameLoader.item as Item
179
+ // RailEject: a mounted row draws the eject mark in place of the square.
180
+ readonly property bool showsEject: Eject.releasable(root.modelData)
181
+ readonly property real ejectMarkSize: Theme.font.caption
182
+ // The keyboard frame on the eject mark, read by tests/keyreach.qml.
183
+ readonly property Item markFrameItem: ejectLoader.item ? ejectLoader.item.frame : null
184
+ // The rail's real trailing indicator slot, so ui/Ipc.qml measures this dot instead of recomputing it.
185
+ readonly property Item indicatorSlot: dot
186
+ readonly property Item detailItem: root.trailingLabel || detailText
187
+ readonly property Item labelItem: label
188
+ readonly property bool indicatorVisible: root.showsDot && root.trailingLabel === null
189
+ // One gap before any trailing number, square or mark; detail covers the Trash count's zero-width dot.
190
+ readonly property bool keepsTrailingGap: root.detail.length > 0 || dot.width > 0
191
+
192
+ Text {
193
+ id: detailText
194
+ visible: root.trailingLabel === null
195
+ anchors.right: dot.left
196
+ anchors.rightMargin: dot.width > 0 ? Style.spacing.rowGap : 0
197
+ anchors.verticalCenter: parent.verticalCenter
198
+ text: root.detail
199
+ color: Theme.color.muted
200
+ font.family: Theme.font.family
201
+ font.pixelSize: Theme.font.caption
202
+ font.features: { "tnum": 1 }
203
+ horizontalAlignment: Text.AlignRight
204
+ textFormat: Text.PlainText
205
+ }
206
+
207
+ // Every right-aligned mark in the rail is centred in a caption-wide slot, so this dot and the
208
+ // NETWORK header's "+" share one centre line whatever their ink does: align by slot, never by ink.
209
+ Item {
210
+ id: dot
211
+ visible: root.trailingLabel === null
212
+ anchors.right: parent.right
213
+ anchors.rightMargin: Style.spacing.rowPaddingX
214
+ anchors.verticalCenter: parent.verticalCenter
215
+ // RailDetails rules 1 and 3 with their 2026-09-14 amendment: a drive size is a number, so
216
+ // every device row ends its size on one x with this slot reserved after it, dot or no dot;
217
+ // the Trash count is an indicator rather than a size, so it sits in the slot itself, on the
218
+ // same edge as the mount dots and the NETWORK plus.
219
+ width: root.countIsIndicator ? 0 : (root.showsDot || root.detail.length > 0 ? Theme.font.caption : 0)
220
+ height: Theme.font.caption
221
+
222
+ // Green once gio mount -l lists it, muted at half strength while it is only a bookmark waiting
223
+ // to be mounted. A square, not a disc: the cut is hard corners, and the canvas draws it square.
224
+ Rectangle {
225
+ visible: root.showsDot && !root.showsEject
226
+ anchors.centerIn: parent
227
+ width: root.dotSize
228
+ height: root.dotSize
229
+ color: root.modelData.mounted ? Theme.color.executable : Theme.color.mutedFrame
230
+ opacity: root.modelData.mounted ? 1 : root.unmountedOpacity
231
+ }
232
+
233
+ // The one-click release: the eject mark in the square's own slot, muted at rest and
234
+ // foreground under the cursor or the pointer, the way a lifted row's metadata is. Built
235
+ // only on a row that releases, the way the menu builds a brand mark only on its row.
236
+ Loader {
237
+ id: ejectLoader
238
+ anchors.centerIn: parent
239
+ width: root.ejectMarkSize
240
+ height: root.ejectMarkSize
241
+ active: root.showsEject
242
+ sourceComponent: ejectMark
243
+ }
244
+ }
245
+
246
+ // The mark and its hit box, standing only while the row releases. The hit box grows to the
247
+ // WCAG floor and centres on the ink, the way the NETWORK header's own addMark does: a centre
248
+ // anchor quantises an odd size difference and leaves the two centres half a pixel apart.
249
+ Component {
250
+ id: ejectMark
251
+ Item {
252
+ property alias hit: hitBox
253
+ property alias frame: markFrame
254
+ property alias hovered: hitHover.hovered
255
+ width: root.ejectMarkSize
256
+ height: root.ejectMarkSize
257
+
258
+ Glyph {
259
+ id: ink
260
+ anchors.centerIn: parent
261
+ name: "eject"
262
+ color: root.cursor || hitHover.hovered || root.markFocused ? Theme.color.foreground : Theme.color.mutedFrame
263
+ width: root.ejectMarkSize
264
+ height: root.ejectMarkSize
265
+ }
266
+
267
+ Rectangle {
268
+ id: markFrame
269
+ anchors.fill: hitBox
270
+ color: "transparent"
271
+ border.width: Theme.spacing.hairline
272
+ border.color: Theme.color.foreground
273
+ visible: root.markFocused
274
+ }
275
+
276
+ Item {
277
+ id: hitBox
278
+ width: Math.max(Theme.hitMin, root.ejectMarkSize)
279
+ height: width
280
+ x: ink.x + (ink.width - width) / 2
281
+ y: ink.y + (ink.height - height) / 2
282
+ Accessible.role: Accessible.Button
283
+ Accessible.name: Format.fill(root.modelData.group === "device" ? root.ejectWords.eject : root.ejectWords.unmount, root.modelData.label)
284
+ Accessible.onPressAction: { if (!root.renaming) root.ejectRequested(root.index) }
285
+ HoverHandler { id: hitHover }
286
+ TapHandler {
287
+ acceptedButtons: Qt.LeftButton
288
+ gesturePolicy: TapHandler.ReleaseWithinBounds
289
+ enabled: root.showsEject && !root.renaming
290
+ onTapped: root.ejectRequested(root.index)
291
+ }
292
+ }
293
+ }
294
+ }
295
+
296
+ // Whether a scene point lands in the mark's hit box, so the row's own tap never
297
+ // answers a press the mark's tap already took. The hit box overflows the slot it is
298
+ // centred on, so the slot alone would hand its rim to the row underneath.
299
+ function ejectAt(scene) {
300
+ var target = ejectLoader.item && ejectLoader.item.hit ? ejectLoader.item.hit : dot
301
+ var p = target.mapFromItem(null, scene.x, scene.y)
302
+ return p.x >= 0 && p.y >= 0 && p.x < target.width && p.y < target.height
303
+ }
304
+
305
+ TapHandler {
306
+ acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
307
+ // Overlay taps take the grab so the covered listing cannot select the same click.
308
+ gesturePolicy: ViewState.railAutoHide ? TapHandler.ReleaseWithinBounds : TapHandler.DragThreshold
309
+ onTapped: function (eventPoint, button) {
310
+ // The field owns clicks inside itself while editing; this only covers the rest of the row.
311
+ if (root.renaming)
312
+ return
313
+ if (button === Qt.MiddleButton) {
314
+ root.tabRequested(root.index)
315
+ return
316
+ }
317
+ // The mark releases on its own left tap; the row must not activate underneath
318
+ // it, while a right tap still raises the menu it always did.
319
+ if (button === Qt.LeftButton && root.showsEject && root.ejectAt(eventPoint.scenePosition))
320
+ return
321
+ // A right click never activates, whatever the row is: it either raised a menu or the
322
+ // row had nothing to offer, and it must not mount and open a stick nobody asked to open.
323
+ if (button === Qt.RightButton) {
324
+ root.menuRequested(root.index, eventPoint.scenePosition)
325
+ return
326
+ }
327
+ root.activated(root.index)
328
+ }
329
+ }
330
+
331
+ // Only favourites build a reorder handler; the row stays fixed and Sidebar draws the boundary.
332
+ Loader {
333
+ active: root.dragFrom >= 0
334
+ anchors.fill: parent
335
+ sourceComponent: Item {
336
+ DragHandler {
337
+ target: null
338
+ xAxis.enabled: false
339
+ property real startY: 0
340
+ onActiveChanged: {
341
+ root.held = active
342
+ if (active) {
343
+ startY = persistentTranslation.y
344
+ return
345
+ }
346
+ var to = TabMove.railReorder(persistentTranslation.y - startY, root.dragFrom, Theme.railRowHeight, root.lineCount).to
347
+ root.reorderAt(-1)
348
+ if (to !== root.dragFrom)
349
+ root.moved(to)
350
+ }
351
+ onCentroidChanged: {
352
+ if (active)
353
+ root.reorderAt(TabMove.railReorder(persistentTranslation.y - startY, root.dragFrom, Theme.railRowHeight, root.lineCount).line)
354
+ }
355
+ }
356
+ }
357
+ }
358
+ }
package/ui/Spinner.qml ADDED
@@ -0,0 +1,60 @@
1
+ import QtQuick
2
+ import QtQuick.Shapes
3
+
4
+ // The Omarchy spiral as the activity mark: a stroke-dash crawl along the brand path, never a
5
+ // rotation. This and EmptyState's FleaMark are the only two places the spiral appears; rows
6
+ // and menus never draw it, per the icon-language spec.
7
+ Item {
8
+ id: root
9
+
10
+ property color color: Theme.color.mutedFrame
11
+ // The mark draws on the same 24 unit grid as every Glyph, scaled to the slot.
12
+ readonly property real grid: 24
13
+ readonly property real markScale: Math.min(root.width, root.height) / root.grid
14
+
15
+ Shape {
16
+ width: root.grid
17
+ height: root.grid
18
+ x: (root.width - root.grid * root.markScale) / 2
19
+ y: (root.height - root.grid * root.markScale) / 2
20
+ preferredRendererType: Shape.CurveRenderer
21
+ transform: Scale { xScale: root.markScale; yScale: root.markScale }
22
+
23
+ ShapePath {
24
+ id: crawl
25
+ strokeColor: root.color
26
+ fillColor: "transparent"
27
+ // A brand mark, not a cut glyph: the spiral keeps the brand's 2 and is exempt from Theme.strokeWidth on purpose.
28
+ strokeWidth: 2
29
+ capStyle: ShapePath.SquareCap
30
+ joinStyle: ShapePath.MiterJoin
31
+ strokeStyle: ShapePath.DashLine
32
+ // The spiral's centreline is 114 grid units and dash units are strokeWidth multiples,
33
+ // so 30+27=57 is exactly one period; the animation walks one period per cycle and the
34
+ // loop point is therefore invisible.
35
+ dashPattern: [30, 27]
36
+ PathSvg { path: "M21 21H3V3h18v14H7V7h10v6h-6" }
37
+ }
38
+ }
39
+
40
+ // Still for its first second on screen, so a load faster than that draws no motion; a hide puts it back to rest.
41
+ readonly property int stillMs: 1000
42
+ property bool crawling: false
43
+ onVisibleChanged: if (!root.visible) { root.crawling = false; crawl.dashOffset = 0 }
44
+ Timer {
45
+ interval: root.stillMs
46
+ running: root.visible && !root.crawling
47
+ onTriggered: root.crawling = true
48
+ }
49
+
50
+ NumberAnimation {
51
+ target: crawl
52
+ property: "dashOffset"
53
+ from: 0
54
+ to: -57
55
+ duration: 1600
56
+ loops: Animation.Infinite
57
+ // Item.visible reads effective visibility, so a hidden ancestor stops the crawl too.
58
+ running: root.visible && root.crawling
59
+ }
60
+ }
@@ -0,0 +1,89 @@
1
+ import QtQuick
2
+ import QtQml.Models
3
+
4
+ // A view's row count as a model that never changes identity, so a new count keeps the delegates that stay drawn.
5
+ DelegateModel {
6
+ id: root
7
+
8
+ required property Item view
9
+ property int total: 0
10
+ // The compositor is filled in componentComplete, so a group change before onCompleted is silently dropped.
11
+ property bool ready: false
12
+
13
+ // A move asked for inside the change's own layout is dropped, so a view that places itself does it here.
14
+ signal resized()
15
+
16
+ // Qt refuses an integer model larger than 100,000,000 rows.
17
+ readonly property int cap: 100000000
18
+ model: root.cap
19
+ groups: DelegateModelGroup { id: shown; name: "shown"; includeByDefault: false }
20
+ filterOnGroup: "shown"
21
+
22
+ // While true a view short of a viewport keeps a full layout's delegates in its reuse pool, so a count that grows takes them instead of building.
23
+ property bool warm: false
24
+ // The rows a full layout from the top builds, its cache buffer's included: the fill lays out no more, so none is left incubating.
25
+ property int warmRows: 0
26
+
27
+ // While true a count change leaves the current delegate current: Qt focuses each new current delegate, which takes the keys from an editor inside the old one.
28
+ property bool holdCurrent: false
29
+
30
+ onTotalChanged: root.resize()
31
+ onWarmChanged: if (root.warm) root.fill()
32
+ Component.onCompleted: { root.ready = true; root.resize() }
33
+
34
+ // Grows the count and shrinks it back in one turn, so no frame sees the rows and what they laid out waits pooled; a geometry change drains it.
35
+ function fill() {
36
+ var from = shown.count
37
+ var to = Math.min(root.warmRows, root.cap)
38
+ if (!root.ready || !root.view.reuseItems || to <= from)
39
+ return
40
+ // The buffer's rows lay out with the viewport's for this pass, built at once where a buffer pass would incubate them later.
41
+ var margin = root.view.displayMarginEnd
42
+ root.view.displayMarginEnd = margin + root.view.cacheBuffer + root.view.height
43
+ root.items.addGroups(from, to - from, "shown")
44
+ root.view.forceLayout()
45
+ shown.removeGroups(from, to - from, "shown")
46
+ root.view.forceLayout()
47
+ root.view.displayMarginEnd = margin
48
+ }
49
+
50
+ // Moves to the top and, unless holdCurrent, row 0 as a reset does, before the change, so only top rows lay out and a view placing itself after keeps its place.
51
+ function resize() {
52
+ var to = Math.min(Math.max(root.total, 0), root.cap)
53
+ var from = shown.count
54
+ if (!root.ready || to === from)
55
+ return
56
+ root.view.contentY = root.view.originY - root.view.topMargin
57
+ if (from > 0 && to > 0 && !root.holdCurrent)
58
+ root.view.currentIndex = 0
59
+ if (to > from)
60
+ root.items.addGroups(from, to - from, "shown")
61
+ else
62
+ shown.removeGroups(to, from - to, "shown")
63
+ // Lays out now: Qt pools a layout's removed rows only after building its inserted ones, so the next count reuses them.
64
+ root.view.forceLayout()
65
+ if (to > 0 && root.view.currentIndex < 0)
66
+ root.view.currentIndex = 0
67
+ root.resized()
68
+ if (to === 0)
69
+ root.drainHidden()
70
+ }
71
+
72
+ // True where a hidden count is rows kept for the return rather than an edit in flight, so the hide drains the pool beside them.
73
+ property bool keptRows: false
74
+ // A hidden view holds no delegates, pooled ones included; a shown one keeps its pool, parked, for the next listing.
75
+ function drainHidden() {
76
+ if (root.view.visible || shown.count > 0 && !root.keptRows || !root.view.reuseItems)
77
+ return
78
+ // Unpersist first so the pool toggle below frees the parked tiles too.
79
+ if (persistedItems.count > 0)
80
+ persistedItems.removeGroups(0, persistedItems.count, "persistedItems")
81
+ root.view.reuseItems = false
82
+ root.view.reuseItems = true
83
+ }
84
+ // A view hidden after it emptied drains here, since its count does not change again.
85
+ property Connections hiding: Connections {
86
+ target: root.view
87
+ function onVisibleChanged() { root.drainHidden() }
88
+ }
89
+ }
@@ -0,0 +1,84 @@
1
+ import QtQuick
2
+ import qs.Commons
3
+ import "js/Errors.js" as Errors
4
+ import "js/Filter.js" as Filter
5
+ import "js/Format.js" as Format
6
+
7
+ // The one thing a pane shows instead of rows, and it carries all three parts the States board gives
8
+ // a pane state: the mark, then one sentence, then the detail the system can prove. The sentence used
9
+ // to live in the status bar about 1300px away while the mode string sat here alone. The empty state
10
+ // has its own overlay in ui/shell.qml, so this yields to it there.
11
+ Item {
12
+ id: root
13
+
14
+ property string message: ""
15
+ property bool active: true
16
+ property string listingState: "loading"
17
+ property int total: 0
18
+ // The filter narrows rows already listed, so a query that matches none leaves a ready listing
19
+ // with nothing drawn in it; shown is -1 while no filter is up.
20
+ property string filterQuery: ""
21
+ property int shown: -1
22
+ // The st_mode of the directory the listing was denied. Zero whenever the backend could not stat
23
+ // it either, which draws no line rather than a mode string that would be false.
24
+ property int lockedMode: 0
25
+
26
+ readonly property bool locked: root.listingState === "locked"
27
+ // A listing past its wait is the Error state too, so the sentence draws with the alert mark.
28
+ readonly property bool failed: root.locked || root.listingState === "error" || root.listingState === "waiting"
29
+ readonly property bool nothingMatched: root.filterQuery.length > 0 && root.shown === 0 && root.total > 0
30
+ // The detail is the directory's own mode, which only a locked state has and only when the
31
+ // backend could stat it; everything else proves nothing extra and draws nothing.
32
+ readonly property string detail: root.locked ? Errors.lockedLine(root.lockedMode)
33
+ : root.nothingMatched ? Filter.noMatch(root.total) : ""
34
+
35
+ // The mark and lines at their unwrapped width, so ui/PaneStates.qml can tell whether they clear the listed columns.
36
+ readonly property real naturalWidth: Math.max(Theme.stateMarkSize, sentence.implicitWidth,
37
+ root.detail.length > 0 ? detailLine.implicitWidth : 0)
38
+
39
+ visible: root.active && (root.nothingMatched
40
+ || (root.total === 0 && root.message.length > 0 && root.listingState !== "empty"))
41
+
42
+ Column {
43
+ anchors.centerIn: parent
44
+ spacing: Theme.spacing.gap
45
+
46
+ // corner: "lock" must reach ui/js/Icons.js before any pane can reach the locked state, because Icons.pathFor falls back to the file mark in silence.
47
+ Glyph {
48
+ anchors.horizontalCenter: parent.horizontalCenter
49
+ visible: root.failed || root.nothingMatched
50
+ // A failure mark stands alone rather than beside a row's text, so it opts in to the
51
+ // pane-state ceiling; States.dc.html draws Locked and Error at 40 and the row mark is 19.
52
+ maxSize: Theme.stateMarkSize
53
+ width: Theme.stateMarkSize
54
+ height: Theme.stateMarkSize
55
+ name: root.locked ? "lock" : root.nothingMatched ? "search" : "alert"
56
+ // Only a failure takes the urgent role, and only on the mark; the sentence stays readable.
57
+ color: root.nothingMatched ? Theme.color.mutedFrame : Theme.color.error
58
+ }
59
+
60
+ Text {
61
+ id: sentence
62
+ width: root.width
63
+ text: root.nothingMatched ? Format.fill(Filter.WORDS.nothingMatched, root.filterQuery) : root.message
64
+ color: Theme.color.foreground
65
+ font.family: Theme.font.family
66
+ font.pixelSize: Theme.font.body
67
+ horizontalAlignment: Text.AlignHCenter
68
+ wrapMode: Text.Wrap
69
+ textFormat: Text.PlainText
70
+ }
71
+
72
+ Text {
73
+ id: detailLine
74
+ width: root.width
75
+ visible: root.detail.length > 0
76
+ text: root.detail
77
+ color: Theme.color.muted
78
+ font.family: Theme.font.family
79
+ font.pixelSize: Theme.font.caption
80
+ horizontalAlignment: Text.AlignHCenter
81
+ textFormat: Text.PlainText
82
+ }
83
+ }
84
+ }