Remove desktop platform support from documentation
This commit is contained in:
@@ -25,7 +25,7 @@ lib/
|
||||
noo/ # the Noo design-system component kit - see
|
||||
# styling.md's catalog
|
||||
details/ # the file-details bottom sheet and its tabs
|
||||
shell/ # pieces shared by the mobile/desktop app shell
|
||||
shell/ # pieces shared by the phone/tablet app shell
|
||||
settings/ # Settings' section widgets
|
||||
tabs/ # loading/error/empty slivers + grouping helpers
|
||||
# shared by Recent/Activity/Trash/Shares
|
||||
@@ -237,7 +237,7 @@ added - an existing saved tab order from before a new tab existed), so
|
||||
adding a tab to the `AppTab` enum needs no extra migration. Only the (up
|
||||
to) 5 pinned tabs (`settings.visibleTabs`) become bottom-nav/sidebar
|
||||
destinations; the rest sit in the "More" section of the drawer (mobile) or
|
||||
sidebar (desktop) - see below.
|
||||
sidebar (wide tablet) - see below.
|
||||
Each tab keeps its own `ScrollController` (survives tab switches via
|
||||
`IndexedStack`'s built-but-hidden trees) and tapping the already-active tab
|
||||
scrolls it back to top (`tapTabToScrollTop` setting). `MainShellView` also
|
||||
@@ -276,7 +276,7 @@ bare system prompt gives no context on its own.
|
||||
`MainShellView` builds its chrome from the Noo nav kit
|
||||
(`widgets/noo/nav/`) and switches between two layouts on
|
||||
`NooLayout.isDesktop` (width >= 900dp *and* shortest side >= 600dp, so a
|
||||
phone in landscape keeps the mobile layout and only tablet-class windows get
|
||||
phone in landscape keeps the mobile layout and only tablet-class viewports get
|
||||
the sidebar):
|
||||
|
||||
- **Mobile:** `AppTopBar` (`widgets/app_top_bar.dart`) wraps `NooTopBar`
|
||||
@@ -295,7 +295,7 @@ the sidebar):
|
||||
native "floating" app bar behavior, tied to that tab's own
|
||||
`ScrollController`: scrolls away as the list scrolls down and reappears
|
||||
the moment the drag reverses, not only once scrolled back to the top).
|
||||
`topBar` is null (no top bar rendered) on desktop and while picking,
|
||||
`topBar` is null (no top bar rendered) on wide tablet and while picking,
|
||||
matching `Scaffold.appBar`'s old `pickRequest == null` guard - see
|
||||
`buildAppTabView`'s doc comment. It sits above each tab's own pinned
|
||||
in-content header (the sort/filter controls row, or Files/Photos'
|
||||
@@ -314,7 +314,7 @@ the sidebar):
|
||||
the avatar button opens `showAvatarMenu` (`widgets/avatar_menu.dart`)
|
||||
instead, a dropdown holding the same hidden-tabs + Settings content -
|
||||
see `styling.md`'s Gotchas for the wiring.
|
||||
- **Desktop:** a `NooSidebar` (account card, pinned tabs, divider,
|
||||
- **Wide tablet:** a `NooSidebar` (account card, pinned tabs, divider,
|
||||
remaining tabs, storage meter, Settings) sits beside a `NooToolbar`
|
||||
(tab title, search, an "Upload" action on Files/Photos) over the same
|
||||
`IndexedStack`, both built inline in `main.dart` rather than as separate
|
||||
@@ -331,7 +331,7 @@ pinned or another "More" tab. `widgets/shell/shell_common.dart` holds the
|
||||
pieces both layouts share: account/storage formatting, `openSettings`/
|
||||
`openSearch`, `showAccountSwitcher` (the saved-accounts list behind the
|
||||
drawer's chevron and the sidebar's account card - a sheet on mobile, a
|
||||
dialog on desktop), `ShellAvatarButton` and `ShellSearchLauncher`.
|
||||
dialog on wide tablet), `ShellAvatarButton` and `ShellSearchLauncher`.
|
||||
|
||||
All eight tabs used to share
|
||||
[`SyncedHeaderScaffold`](../../lib/widgets/synced_header_scaffold.dart) - a
|
||||
@@ -346,9 +346,9 @@ pinned chip. `SyncedHeaderScaffold` is now unused - the last two screens on
|
||||
it, `ShareUploadView` (the share-to-upload destination picker, pushed
|
||||
rather than a tab - see below) and `MoveCopyDestinationPicker`, are
|
||||
rebuilt too: both are a `Scaffold` with a `NooTopBar`+`NooTopBarBack`
|
||||
(mobile) / `NooToolbar` (desktop) top bar, a noo-styled
|
||||
(mobile) / `NooToolbar` (wide tablet) top bar, a noo-styled
|
||||
[`Breadcrumbs`](../../lib/widgets/breadcrumbs.dart) row + folder list
|
||||
(`NooFileRow` mobile, `NooFileTableRow` desktop - both pickers only ever
|
||||
(`NooFileRow` mobile, `NooFileTableRow` wide tablet - both pickers only ever
|
||||
browse *folders*, so the old dimmed-but-visible file rows are gone; a
|
||||
`RefreshIndicator`+`CustomScrollView`) for a body, and a `colors.surface`
|
||||
bottom bar with a top `line` (no more rounded-top elevated `Material`
|
||||
@@ -393,14 +393,14 @@ per-item conflict follow-up, if any, is
|
||||
`SearchView`, `AccountView` (Settings), the file-details sheet
|
||||
(`DetailsSheet`), and the share sheet (`ShareSheet`) are pushed on top via
|
||||
`Navigator`/`showNooSheet`/`showNooDialog` rather than being tabs (the two
|
||||
per-item sheets pick between the mobile sheet and the desktop dialog via
|
||||
per-item sheets pick between the mobile sheet and the wide tablet dialog via
|
||||
`NooLayout.isDesktop`, same as every other overlay in the app;
|
||||
`showGradualBottomSheet`, the custom drag-to-resize sheet they used before,
|
||||
has no remaining callers). On mobile, `ShellAvatarButton`
|
||||
(`widgets/shell/shell_common.dart`,
|
||||
shown in `AppTopBar`'s trailing actions on every tab, and reused directly by
|
||||
`ShareUploadView`) opens Settings on tap and cycles between saved accounts
|
||||
on a vertical swipe. Desktop has no avatar in the
|
||||
on a vertical swipe. Wide tablet has no avatar in the
|
||||
toolbar; `NooSidebarAccount`'s account card opens the full switcher instead
|
||||
(`showAccountSwitcher`, the same one behind the mobile drawer's chevron).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Noo Design System
|
||||
|
||||
Noo is a Nextcloud client for iOS, Android, macOS and Windows. ("Noo" is a placeholder name.)
|
||||
Noo is a Nextcloud client for iOS and Android. ("Noo" is a placeholder name.)
|
||||
Its visual language is warm neutrals with one violet accent, flat surfaces, pill-shaped controls, and no gradients.
|
||||
|
||||
**Platform rule:** keep one visual language everywhere. Adapt only the navigation chrome (status bar, top bar, bottom bar, window controls) to each platform. Content components look the same on every platform.
|
||||
@@ -9,8 +9,8 @@ Reference files in this project:
|
||||
- `Noo Screens.dc.html` has every screen on every platform, in light and dark.
|
||||
- `Noo Design System.dc.html` is the visual component sheet.
|
||||
- `noo-kit.js` holds the tokens (`TH`), the icon set (`SVG`/`ic`), file-type mapping (`KIND`) and mock data.
|
||||
- `Mobile Screen.dc.html` and `Desktop Screen.dc.html` are the reference builds for each screen.
|
||||
- [Noo — Missing Screens](https://claude.ai/artifact/3AGPqqMdkLSC2ypCh2CQs4) is a live design canvas (Claude Design, not a static file in this repo) covering pieces this doc originally had no recipe for: Media viewer, Search, the Upload/Move/Copy destination picker, the Details sheet's tab switch, and the Selection action bar (mobile + desktop). It has both an iOS row (built first, ready for later) and an Android row (built to match right now) - same content, chrome adapted per the platform rule above. §4 below is the written-up version of what's approved there; go back to the canvas for pixel-level layout, not just the summary.
|
||||
- `Mobile Screen.dc.html` is the reference build for each screen.
|
||||
- [Noo — Missing Screens](https://claude.ai/artifact/3AGPqqMdkLSC2ypCh2CQs4) is a live design canvas (Claude Design, not a static file in this repo) covering pieces this doc originally had no recipe for: Media viewer, Search, the Upload/Move/Copy destination picker, the Details sheet's tab switch, and the Selection action bar (mobile + wide tablet). It has both an iOS row (built first, ready for later) and an Android row (built to match right now) - same content, chrome adapted per the platform rule above. §4 below is the written-up version of what's approved there; go back to the canvas for pixel-level layout, not just the summary.
|
||||
|
||||
---
|
||||
|
||||
@@ -20,8 +20,8 @@ Reference files in this project:
|
||||
|
||||
| Token | Role | Light | Dark |
|
||||
|---|---|---|---|
|
||||
| `bg` | App background, desktop sidebar | `#F3EFE6` warm off-white | `#0E0D0B` |
|
||||
| `surface` (`sf`) | Cards, rows, bars, sheets, desktop main pane | `#FFFFFF` | `#25241F` |
|
||||
| `bg` | App background, wide tablet sidebar | `#F3EFE6` warm off-white | `#0E0D0B` |
|
||||
| `surface` (`sf`) | Cards, rows, bars, sheets, wide tablet main pane | `#FFFFFF` | `#25241F` |
|
||||
| `surface-2` (`sf2`) | Inputs, inset panels, secondary buttons | `#F6F5F2` | `#3D3C38` |
|
||||
| `surface-3` (`sf3`) | Progress tracks, toggle off, grabbers | `#EAE8E2` | `#5A5852` |
|
||||
| `line` (`ln`) | Dividers, 1px borders | `#EAE8E2` | `#3D3C38` |
|
||||
@@ -54,7 +54,7 @@ Rules:
|
||||
| image | info-soft | info | `image` |
|
||||
| archive | surface-3 | fg-2 | `file-archive` |
|
||||
|
||||
Tile sizes: 40px/r12 for mobile rows, 30px/r9 for desktop rows, 44px/r12 for the share header, 32px/r10 for activity. The icon is half the tile size (20, 16, 24, 16).
|
||||
Tile sizes: 40px/r12 for mobile rows, 30px/r9 for wide tablet rows, 44px/r12 for the share header, 32px/r10 for activity. The icon is half the tile size (20, 16, 24, 16).
|
||||
|
||||
### 1.3 Typography
|
||||
Fonts (Google Fonts): **Schibsted Grotesk** for headings (weights 500/600) and **Instrument Sans** for UI (weights 400/500/600). Load them with `https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;500;600&family=Schibsted+Grotesk:wght@500;600&display=swap`. Don't use italics, all-caps or wide tracking.
|
||||
@@ -62,30 +62,30 @@ Fonts (Google Fonts): **Schibsted Grotesk** for headings (weights 500/600) and *
|
||||
| Style | Font | Size / line-height | Tracking | Use |
|
||||
|---|---|---|---|---|
|
||||
| Large title | Schibsted 600 | 34 / 0.9 | −3% | iOS large title |
|
||||
| Stat | Schibsted 600 | 32 (mobile) · 28 (desktop) / 0.9 | −3% | Offline GB, counters |
|
||||
| Title | Schibsted 500 | 22 / 1 | −2% | Android top bar, desktop toolbar |
|
||||
| Stat | Schibsted 600 | 32 (mobile) · 28 (wide tablet) / 0.9 | −3% | Offline GB, counters |
|
||||
| Title | Schibsted 500 | 22 / 1 | −2% | Android top bar, wide tablet toolbar |
|
||||
| Card title | Schibsted 500 | 17–20 / 1 | −2% | Settings cards, sheet sections, account name |
|
||||
| Group heading | Schibsted 500 | 18 / 1 | −2% | Photos month |
|
||||
| Body L | Instrument 400/500 | 16 / 1.2 | 0 | Mobile row title, settings label |
|
||||
| Body | Instrument 400/500 | 14–15 / 1.3 | 0 | Desktop rows, activity text, banners |
|
||||
| Body | Instrument 400/500 | 14–15 / 1.3 | 0 | Wide tablet rows, activity text, banners |
|
||||
| Label | Instrument 600 | 13 / 1 | 0 | Section labels (fg-2), chips, table headers (12, fg-3) |
|
||||
| Meta | Instrument 400 | 13 (mobile) · 12–13 (desktop) / 1.2 | 0 | Size · date, subtitles (fg-3) |
|
||||
| Meta | Instrument 400 | 13 (mobile) · 12–13 (wide tablet) / 1.2 | 0 | Size · date, subtitles (fg-3) |
|
||||
| Nav label | Instrument 500 / 600 (active) | 12 Android · 10 iOS | 0 | Bottom bars |
|
||||
| Button | Instrument 600 | 14–16 / 1 | 0 | All buttons |
|
||||
| Mono | ui-monospace 400 | 13–14 | 0 | Share URLs, local paths |
|
||||
|
||||
### 1.4 Space, radius, elevation, motion
|
||||
- **Spacing** uses a 4px base: 4, 8, 12, 14, 16, 20, 24, 32. Mobile screen gutter is **12px** (cards) and 16px (bars). Desktop content gutter is **24px**.
|
||||
- **Spacing** uses a 4px base: 4, 8, 12, 14, 16, 20, 24, 32. Mobile screen gutter is **12px** (cards) and 16px (bars). Wide tablet content gutter is **24px**.
|
||||
- **Radius:**
|
||||
- pills (`999px`) for every button, chip, segmented control, toggle, search field and badge
|
||||
- 20px for cards and grouped lists
|
||||
- 18px for grid cards and stat cards
|
||||
- 14px for inputs and inset panels
|
||||
- 12px for desktop sidebar items and selected table rows
|
||||
- 12px for wide tablet sidebar items and selected table rows
|
||||
- 28px for the sheet top and drawer edge
|
||||
- 24px for desktop dialogs
|
||||
- 24px for wide tablet dialogs
|
||||
- screen corners are 48 on iOS and 36 on Android
|
||||
- **Elevation:** product UI is flat, with no shadows on buttons or cards. The only shadow is `0 24px 48px rgba(30,0,47,.14)`, and only on floating desktop dialogs. Separate things by surface color, not by shadow.
|
||||
- **Elevation:** product UI is flat, with no shadows on buttons or cards. The only shadow is `0 24px 48px rgba(30,0,47,.14)`, and only on floating wide tablet dialogs. Separate things by surface color, not by shadow.
|
||||
- **Motion:** use `cubic-bezier(.7,0,.15,1)` with durations of 180, 280 and 480ms. Nothing bounces. Pressing a button scales it to 0.98.
|
||||
|
||||
### 1.5 Icons
|
||||
@@ -96,7 +96,7 @@ Use **Lucide** (pinned to `lucide-static@0.460.0`) at a 1.8 stroke. Sizes are 14
|
||||
## 2. Components
|
||||
|
||||
**Button**
|
||||
- Always a pill. Heights: 52 (sheet CTA), 44 (mobile card), 40 (inline in a field), 36 (desktop toolbar), 28–32 (compact).
|
||||
- Always a pill. Heights: 52 (sheet CTA), 44 (mobile card), 40 (inline in a field), 36 (wide tablet toolbar), 28–32 (compact).
|
||||
- Variants:
|
||||
- *Primary*: accent fill, white text.
|
||||
- *Tonal*: accent-soft fill, accent-text.
|
||||
@@ -124,7 +124,7 @@ Use **Lucide** (pinned to `lucide-static@0.460.0`) at a 1.8 stroke. Sizes are 14
|
||||
|
||||
**Chip**
|
||||
- A pill, 32–34px tall, 12px horizontal padding, Label 13–14.
|
||||
- Idle: surface fill on mobile, or a 1px line border on desktop.
|
||||
- Idle: surface fill on mobile, or a 1px line border on wide tablet.
|
||||
- Selected: accent-soft fill with accent-text.
|
||||
- A trailing `chevron-down` means it opens a menu. A trailing `x` means it's an active filter.
|
||||
|
||||
@@ -134,7 +134,7 @@ Use **Lucide** (pinned to `lucide-static@0.460.0`) at a 1.8 stroke. Sizes are 14
|
||||
- Use it for the List/Grid toggle (icons only, 36×28), Shares scope, Theme, and default view.
|
||||
|
||||
**Toggle**
|
||||
- 48×28 on mobile, 44×26 on desktop, with a white knob 3px inset.
|
||||
- 48×28 on mobile, 44×26 on wide tablet, with a white knob 3px inset.
|
||||
- On: accent track. Off: surface-3 track. It looks the same on every platform.
|
||||
|
||||
**Search field**
|
||||
@@ -143,7 +143,7 @@ Use **Lucide** (pinned to `lucide-static@0.460.0`) at a 1.8 stroke. Sizes are 14
|
||||
- Placement:
|
||||
- iOS: below the large title.
|
||||
- Android: an icon in the top bar that expands.
|
||||
- Desktop: 260px wide in the toolbar.
|
||||
- Wide tablet: 260px wide in the toolbar.
|
||||
|
||||
**Grouped list (card)**
|
||||
- A surface card with radius 20 and 1px gaps showing `line`, which draws the dividers.
|
||||
@@ -156,7 +156,7 @@ Use **Lucide** (pinned to `lucide-static@0.460.0`) at a 1.8 stroke. Sizes are 14
|
||||
- The meta line is `[status icon][shared icon] size · modified`.
|
||||
- A favorite shows an accent-text star before the overflow menu.
|
||||
- Trailing icon by screen: star in Favorites, `rotate-ccw` in Trash.
|
||||
- Desktop: a table row 52px tall.
|
||||
- Wide tablet: a table row 52px tall.
|
||||
- Columns are `minmax(0,1fr) 180px 160px 120px`: Name, two data columns, then status icons and the overflow menu.
|
||||
- The header row is 36px, 12/600 in fg-3, with a sort arrow on the active column.
|
||||
- A selected row gets an accent-soft fill with radius 12.
|
||||
@@ -179,12 +179,12 @@ multi-select)
|
||||
never a second bar stacked underneath it, and never the shell's own top
|
||||
bar/toolbar, which don't change for selection.
|
||||
- A `surface` card, radius 20, in the screen's usual gutter (12 mobile, 24
|
||||
desktop) - selection reads as a distinct mode, not a bare row of buttons
|
||||
wide tablet) - selection reads as a distinct mode, not a bare row of buttons
|
||||
on `bg`.
|
||||
- Left to right: a 36px `surface-2` close circle (`x`), then "N selected"
|
||||
(17/500), then the bulk actions, trailing-anchored. Fixed width, never
|
||||
scrolls: only the first few actions show inline (3 on mobile, 4 on
|
||||
desktop - there can be up to 9: favorite, share, download, delete, copy,
|
||||
wide tablet - there can be up to 9: favorite, share, download, delete, copy,
|
||||
move, rename, sync, details); the rest sit behind a trailing "More"
|
||||
button that opens the same grouped-list sheet a file row's own overflow
|
||||
menu (`ellipsis`/`ellipsis-vertical`) already uses. Which actions land in
|
||||
@@ -193,20 +193,20 @@ multi-select)
|
||||
- Mobile: inline actions are plain 20px accent-text icons, no fill; "More"
|
||||
is the same 40px `NooOverflowButton` treatment (`ellipsis`/
|
||||
`ellipsis-vertical`, fg-3) file rows use for their own overflow menu.
|
||||
- Desktop: inline actions are labelled tonal pills (accent-soft/
|
||||
accent-text), danger-soft/danger for the one labelled "Delete" - desktop
|
||||
- Wide tablet: inline actions are labelled tonal pills (accent-soft/
|
||||
accent-text), danger-soft/danger for the one labelled "Delete" - wide tablet
|
||||
has the room for labels, and the app's other toolbar actions are already
|
||||
labelled buttons rather than bare icons. "More" is a secondary pill
|
||||
(surface-2/fg-1) with a trailing `chevron-down`, so it reads as "opens a
|
||||
menu" rather than another bulk action.
|
||||
|
||||
**Grid card**
|
||||
- Surface fill, radius 18. Mobile uses 2 columns with a 10px gap; desktop uses 5 columns with a 16px gap.
|
||||
- Surface fill, radius 18. Mobile uses 2 columns with a 10px gap; wide tablet uses 5 columns with a 16px gap.
|
||||
- The thumbnail area is 104–118px tall, filled with the file-type soft color and a 32px icon. Real thumbnails replace it when they exist.
|
||||
- Below it: the name (14/500) with an overflow menu, then the meta (12).
|
||||
|
||||
**Photo grid**
|
||||
- Square tiles with a 2px gap on mobile (3 columns, edge to edge) and a 4px gap on desktop (8 columns).
|
||||
- Square tiles with a 2px gap on mobile (3 columns, edge to edge) and a 4px gap on wide tablet (8 columns).
|
||||
- Tiles are grouped by month, with the group heading on the left and the count on the right.
|
||||
- Videos get a badge in the bottom-right: a `play` icon and the duration on `rgba(14,13,11,.7)`.
|
||||
|
||||
@@ -215,7 +215,7 @@ multi-select)
|
||||
- Time in meta style. The file tile (32) goes on the right.
|
||||
|
||||
**Banner / summary card**
|
||||
- A surface card with radius 20 (surface-2 on desktop) and padding of 14–18.
|
||||
- A surface card with radius 20 (surface-2 on wide tablet) and padding of 14–18.
|
||||
- The action sits on its own row below the description text, not squeezed
|
||||
onto the same line - a long retention message/caption and the action
|
||||
used to fight for the same row's width.
|
||||
@@ -236,7 +236,7 @@ multi-select)
|
||||
**Settings row**
|
||||
- 52px tall, or 60px with a subtitle.
|
||||
- Left to right: an optional 20px icon in fg-2, then the label (16) with an optional subtitle (13, fg-3), then a trailing control.
|
||||
- Trailing control is one of: a toggle, a value in fg-3 with a chevron (desktop uses a 32px dropdown with radius 10), a segmented control, a pill button, or a status badge.
|
||||
- Trailing control is one of: a toggle, a value in fg-3 with a chevron (wide tablet uses a 32px dropdown with radius 10), a segmented control, a pill button, or a status badge.
|
||||
- A destructive row uses danger text.
|
||||
- Exception: a segmented control with 3+ labelled segments (Theme's
|
||||
System/Light/Dark) gets its own row below the label instead of a
|
||||
@@ -247,14 +247,14 @@ multi-select)
|
||||
control and Photos' filter-sheet type control already use.
|
||||
|
||||
**Tab order row**
|
||||
- A grip icon (`grip-vertical`, fg-3), the tab icon, the label, then a pin button: a 36px circle (30 on desktop) that is accent-soft with `pin` when pinned, or surface-2 with `pin-off` when not.
|
||||
- A grip icon (`grip-vertical`, fg-3), the tab icon, the label, then a pin button: a 36px circle (30 on wide tablet) that is accent-soft with `pin` when pinned, or surface-2 with `pin-off` when not.
|
||||
- Allow at most 5 pinned tabs.
|
||||
|
||||
**Sheet** (mobile)
|
||||
- Surface fill, radius 28 at the top. A 36×5 grabber in surface-3. Padding 20, with 22px between sections.
|
||||
- It sits on a scrim.
|
||||
|
||||
**Dialog** (desktop)
|
||||
**Dialog** (wide tablet)
|
||||
- 540px wide, radius 24, padding 24, sitting on a scrim.
|
||||
- Header: file tile, title "Share "<name>"", and a close button (32px circle, surface-2).
|
||||
|
||||
@@ -282,7 +282,7 @@ Mobile always has **5 pinned tabs in the bottom bar**. The rest go in the drawer
|
||||
| Status bar | 54px, Dynamic Island | 40px |
|
||||
| Top bar | 44px row: `menu` on the left; `plus` and avatar on the right (all accent-text). Then a 34px large title, then the search field. | 64px: `menu`, 22px title, avatar - see "Search" below for what replaces `search` there, and "Navigation menu" for `menu` |
|
||||
| Bottom bar | Surface fill, 1px top line. Icon 24 above a 10px label. Active: accent-text. Idle: fg-3. 34px home indicator below. | Surface fill, 80px. Icon 24 above a 12px label (label space is always reserved, just invisible when idle, so nothing shifts on selection). The active icon sits inside a 56×32 accent-soft pill that slides between tabs as one shared indicator, rather than popping in/out per tab. 20px gesture bar below. |
|
||||
| Bottom bar - floating (Settings → Appearance → "Bottom bar", both platforms) | Same content, inset 16px from both side edges and clear of the bottom safe area instead of edge to edge, radius 28 (the sheet-top/drawer-edge radius) rather than square corners. Product UI otherwise stays flat (see 1.4), but this is the one other place - besides desktop dialogs - that gets the app's one shadow: a 1px `line` border plus the dialog shadow, since a bar that's genuinely floating above scrolling content needs to read as elevated. Row height drops (iOS 50, same as attached; Android 64 vs 80) to suit. Android's idle tabs drop their reserved label space in this mode - the icon just centers in the button and renders a touch bigger (25 vs 24px) - rather than sitting high with a gap held open under it. `Scaffold.extendBody: true` while floating, so the body scrolls behind the bar's transparent margin instead of stopping short of it - which means every tab's scrollable list has to pad its own bottom enough to clear the bar's footprint, since nothing does that for it automatically once the body draws behind the bar. The Android FAB stays fully round in this mode (see "Upload" below), consistent with the bar's own rounder shape. |
|
||||
| Bottom bar - floating (Settings → Appearance → "Bottom bar", both platforms) | Same content, inset 16px from both side edges and clear of the bottom safe area instead of edge to edge, radius 28 (the sheet-top/drawer-edge radius) rather than square corners. Product UI otherwise stays flat (see 1.4), but this is the one other place - besides wide tablet dialogs - that gets the app's one shadow: a 1px `line` border plus the dialog shadow, since a bar that's genuinely floating above scrolling content needs to read as elevated. Row height drops (iOS 50, same as attached; Android 64 vs 80) to suit. Android's idle tabs drop their reserved label space in this mode - the icon just centers in the button and renders a touch bigger (25 vs 24px) - rather than sitting high with a gap held open under it. `Scaffold.extendBody: true` while floating, so the body scrolls behind the bar's transparent margin instead of stopping short of it - which means every tab's scrollable list has to pad its own bottom enough to clear the bar's footprint, since nothing does that for it automatically once the body draws behind the bar. The Android FAB stays fully round in this mode (see "Upload" below), consistent with the bar's own rounder shape. |
|
||||
| Bottom bar - "Search in bottom bar" (Settings → Appearance, either bar style) | Adds a Search entry that's never highlighted (tapping it pushes Search, same as the top bar's own search action, which this replaces so there's only one entry point on screen) - the row's last item when attached (same styling as a real tab, just permanently idle), or its own separate, always fully round satellite circle beside the bar when floating. Costs one regular tab: `SettingsController.maxVisibleTabs` drops from 5 to 4 while this is on. |
|
||||
| Search (top bar, when not in the bottom bar) | A real inline search field (`NooSearchField`, non-editable launcher) below the large title | A search-field-styled launcher takes the title's own flexible slot instead of a bare `search` icon beside it - no second row to put it under the way iOS has |
|
||||
| Navigation menu (Settings → Appearance → "Navigation menu", both platforms) | `drawer` (default): the `menu` icon opens the left `Drawer` (hidden tabs + Settings), unchanged. `avatarMenu`: no `menu` icon at all - the avatar button opens a dropdown instead (`showAvatarMenu`), anchored under the top bar, full width minus the same 16px gutter every content row uses, with the same hidden-tabs + Settings content the drawer holds (not its storage bar - this is a quick menu, not the drawer's full account summary). The avatar sits in the exact same (right-end) position either way, and the dropdown's own header repeats it there too, so the open menu reads as having grown out of the button that opened it. Not a mandatory replacement: this halves the top-corner surface a thumb has to reach (from `menu` + avatar down to avatar alone) without costing any permanent screen width the way an earlier side-rail exploration would have. |
|
||||
@@ -291,9 +291,9 @@ Mobile always has **5 pinned tabs in the bottom bar**. The rest go in the drawer
|
||||
| Settings | Pushed screen with a "‹ Files" back button and a large title. No bottom bar. | Pushed screen with a back arrow and a title. No bottom bar. |
|
||||
| Biometric label | "Lock with Face ID" | "Lock with fingerprint" |
|
||||
|
||||
### Desktop
|
||||
### Wide tablet
|
||||
|
||||
Desktop has a 256px sidebar in `bg` and a main pane in `surface`, separated by a 1px line.
|
||||
Wide tablet has a 256px sidebar in `bg` and a main pane in `surface`, separated by a 1px line.
|
||||
|
||||
**Sidebar**, top to bottom:
|
||||
- account switcher card
|
||||
@@ -312,14 +312,7 @@ Sidebar items are 38px tall with radius 12, an 18px icon and a 14/500 label. The
|
||||
- the search field
|
||||
- context actions: List/Grid toggle and Upload in Files, Upload in Photos, Empty trash in Trash, Sync now in Offline
|
||||
|
||||
| Element | macOS | Windows |
|
||||
|---|---|---|
|
||||
| Window | Radius 12 | Radius 8 |
|
||||
| Controls | Traffic lights at the top of the sidebar | 40px title bar with the app mark and name; minimize, maximize and close buttons 46px wide |
|
||||
| Navigation | Back and forward chevrons at the start of the toolbar | Not shown in the toolbar |
|
||||
| Biometric | "Touch ID" | "Windows Hello" |
|
||||
| Local path | `~/Noo/…` | `C:\Users\…\Noo` |
|
||||
| Swipe setting | "Trackpad swipe on a file" | "Touch swipe on a file" |
|
||||
|
||||
|
||||
---
|
||||
|
||||
@@ -327,7 +320,7 @@ Sidebar items are 38px tall with radius 12, an 18px icon and a 14/500 label. The
|
||||
|
||||
- **Files:**
|
||||
- Toolbar: sort chip (`Name ↑`), type filter chip, List/Grid segmented toggle.
|
||||
- Desktop adds Modified and Shared filter chips, an active-filter chip, and an item count.
|
||||
- Wide tablet adds Modified and Shared filter chips, an active-filter chip, and an item count.
|
||||
- Content: a list, or a grid when the toggle is set.
|
||||
- **Photos:** a sort chip and a filter chip (mirroring Files' own controls
|
||||
row - no List/Grid toggle, the grid is the only view). The type filter
|
||||
@@ -342,7 +335,7 @@ Sidebar items are 38px tall with radius 12, an 18px icon and a 14/500 label. The
|
||||
Files' old checkmark list or Photos' own always-labelled track. Then the
|
||||
photo grid grouped by month.
|
||||
- **Favorites:** a file list with a star as the trailing icon.
|
||||
- **Offline:** a summary card (or 4 stat cards on desktop), then a list whose rows show sync status icons and status meta.
|
||||
- **Offline:** a summary card (or 4 stat cards on wide tablet), then a list whose rows show sync status icons and status meta.
|
||||
- **Shares:** a segmented control (With you, By you, Links), then a list. The
|
||||
meta reads "Owner · Permission". No per-row overflow menu on any of the
|
||||
three scopes - tapping a row (file or folder) opens the full Share sheet
|
||||
@@ -352,8 +345,8 @@ Sidebar items are 38px tall with radius 12, an 18px icon and a 14/500 label. The
|
||||
copying a link or removing access lives, so a second, row-local menu here
|
||||
was redundant.
|
||||
- **Recent:** a list grouped into Today, Yesterday and This week. The meta is the action plus the location.
|
||||
- **Activity:** the feed grouped by day. Desktop limits it to 760px wide.
|
||||
- **Trash:** a retention banner, then a list. Mobile rows get a restore icon; desktop rows get a tonal "Restore" pill.
|
||||
- **Activity:** the feed grouped by day. Wide tablet limits it to 760px wide.
|
||||
- **Trash:** a retention banner, then a list. Mobile rows get a restore icon; wide tablet rows get a tonal "Restore" pill.
|
||||
- **Settings:** sections in this order:
|
||||
1. Account card
|
||||
2. Accounts (list, then "Add account")
|
||||
@@ -365,7 +358,7 @@ Sidebar items are 38px tall with radius 12, an 18px icon and a 14/500 label. The
|
||||
8. Action bar - a reorder-only list (no pin/hide, unlike Tabs): the
|
||||
priority order for the Selection action bar's bulk actions (favorite,
|
||||
share, download, delete, copy, move, rename, sync, details) - the
|
||||
first few (3 mobile / 4 desktop) land in the bar's fixed inline
|
||||
first few (3 mobile / 4 wide tablet) land in the bar's fixed inline
|
||||
slots, the rest sit behind "More". See §2 "Selection action bar".
|
||||
9. Swipe on a file
|
||||
|
||||
@@ -383,7 +376,7 @@ Sidebar items are 38px tall with radius 12, an 18px icon and a 14/500 label. The
|
||||
`collapsible` param) so the page could at least be collapsed down. Both
|
||||
scrolled the *same* page to or past an anchor; a genuinely separate
|
||||
pushed screen per category removes the scroll-depth problem outright
|
||||
instead of just working around it. Desktop is unchanged: a 2-column grid
|
||||
instead of just working around it. Wide tablet is unchanged: a 2-column grid
|
||||
of cards with a 1px line and radius 20, wide enough to see most sections
|
||||
without scrolling, so it gets neither a menu nor collapsing.
|
||||
- **Share sheet / dialog:** sections in this order:
|
||||
@@ -431,7 +424,7 @@ Sidebar items are 38px tall with radius 12, an 18px icon and a 14/500 label. The
|
||||
(not the inset-panel text-field shape - a search field is always the pill,
|
||||
except the one named iOS-inline exception) taking over the top row,
|
||||
autofocus, a clear button once there's a query. Below it: a file list
|
||||
(mobile rows / desktop table, same as Files), or a centered icon + short
|
||||
(mobile rows / wide tablet table, same as Files), or a centered icon + short
|
||||
sentence-case message for the empty ("Search your files") and no-results
|
||||
states.
|
||||
- **Upload / Move / Copy destination picker:** a pushed screen (outside the
|
||||
|
||||
@@ -1,340 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="./support.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<x-dc>
|
||||
<helmet>
|
||||
<script src="noo-kit.js"></script>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;500;600&family=Schibsted+Grotesk:wght@500;600&display=swap">
|
||||
<style>
|
||||
body{margin:0}
|
||||
a{color:#8D0DE3;text-decoration:none}
|
||||
a:hover{color:#6E08B3}
|
||||
</style>
|
||||
</helmet>
|
||||
<sc-if value="{{ ready }}" hint-placeholder-val="{{ false }}">
|
||||
<div style="{{ root }}">
|
||||
|
||||
<sc-if value="{{ win }}">
|
||||
<div style="height:40px;flex:none;display:flex;align-items:center;background:var(--bg);color:var(--fg2)">
|
||||
<div style="display:flex;align-items:center;gap:10px;padding:0 16px;flex:1;font:400 12px/1 var(--ft)"><div style="width:16px;height:16px;border-radius:4px;background:var(--ac)"></div>Noo</div>
|
||||
<div style="width:46px;height:40px;display:flex;align-items:center;justify-content:center"><span style="{{ i16.minus }}"></span></div>
|
||||
<div style="width:46px;height:40px;display:flex;align-items:center;justify-content:center"><span style="{{ i14.square }}"></span></div>
|
||||
<div style="width:46px;height:40px;display:flex;align-items:center;justify-content:center"><span style="{{ i16.x }}"></span></div>
|
||||
</div>
|
||||
</sc-if>
|
||||
|
||||
<div style="flex:1;min-height:0;display:flex">
|
||||
<div style="width:256px;flex:none;background:var(--bg);display:flex;flex-direction:column;padding:12px 12px 16px;box-sizing:border-box;gap:2px">
|
||||
<sc-if value="{{ mac }}">
|
||||
<div style="height:32px;display:flex;align-items:center;gap:8px;padding:0 8px 8px"><div style="width:12px;height:12px;border-radius:999px;background:#FF5F57"></div><div style="width:12px;height:12px;border-radius:999px;background:#FEBC2E"></div><div style="width:12px;height:12px;border-radius:999px;background:#28C840"></div></div>
|
||||
</sc-if>
|
||||
<div style="display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:14px;background:var(--sf);margin-bottom:14px">
|
||||
<div style="width:32px;height:32px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;justify-content:center;font:600 12px/1 var(--ft);flex:none">MR</div>
|
||||
<div style="flex:1;min-width:0;display:flex;flex-direction:column;gap:4px"><div style="font:600 14px/1 var(--ft)">Marina Rocha</div><div style="font:400 12px/1 var(--ft);color:var(--fg3)">cloud.rocha.family</div></div>
|
||||
<span style="{{ chevG }}"></span>
|
||||
</div>
|
||||
<sc-for list="{{ navA }}" as="n" hint-placeholder-count="5">
|
||||
<sc-if value="{{ n.on }}"><div style="height:38px;border-radius:12px;padding:0 12px;display:flex;align-items:center;gap:12px;background:var(--acs);color:var(--act);font:600 14px/1 var(--ft)"><span style="{{ n.ico }}"></span><div style="flex:1">{{ n.label }}</div><div style="font:500 12px/1 var(--ft)">{{ n.count }}</div></div></sc-if>
|
||||
<sc-if value="{{ n.off }}"><div style="height:38px;border-radius:12px;padding:0 12px;display:flex;align-items:center;gap:12px;color:var(--fg1);font:500 14px/1 var(--ft)"><span style="{{ n.icoG }}"></span><div style="flex:1">{{ n.label }}</div><div style="font:500 12px/1 var(--ft);color:var(--fg3)">{{ n.count }}</div></div></sc-if>
|
||||
</sc-for>
|
||||
<div style="height:1px;background:var(--ln);margin:8px 12px"></div>
|
||||
<sc-for list="{{ navB }}" as="n" hint-placeholder-count="3">
|
||||
<sc-if value="{{ n.on }}"><div style="height:38px;border-radius:12px;padding:0 12px;display:flex;align-items:center;gap:12px;background:var(--acs);color:var(--act);font:600 14px/1 var(--ft)"><span style="{{ n.ico }}"></span><div style="flex:1">{{ n.label }}</div><div style="font:500 12px/1 var(--ft)">{{ n.count }}</div></div></sc-if>
|
||||
<sc-if value="{{ n.off }}"><div style="height:38px;border-radius:12px;padding:0 12px;display:flex;align-items:center;gap:12px;color:var(--fg1);font:500 14px/1 var(--ft)"><span style="{{ n.icoG }}"></span><div style="flex:1">{{ n.label }}</div><div style="font:500 12px/1 var(--ft);color:var(--fg3)">{{ n.count }}</div></div></sc-if>
|
||||
</sc-for>
|
||||
<div style="flex:1"></div>
|
||||
<div style="display:flex;flex-direction:column;gap:8px;padding:12px 12px 14px">
|
||||
<div style="display:flex;justify-content:space-between;font:400 12px/1 var(--ft);color:var(--fg2)"><span style="font-weight:500;color:var(--fg1)">Storage</span><span>38.2 of 100 GB</span></div>
|
||||
<div style="height:6px;border-radius:999px;background:var(--sf3);overflow:hidden"><div style="width:38%;height:100%;background:var(--ac)"></div></div>
|
||||
</div>
|
||||
<sc-if value="{{ setOn }}"><div style="height:38px;border-radius:12px;padding:0 12px;display:flex;align-items:center;gap:12px;background:var(--acs);color:var(--act);font:600 14px/1 var(--ft)"><span style="{{ i18.settings }}"></span>Settings</div></sc-if>
|
||||
<sc-if value="{{ setOff }}"><div style="height:38px;border-radius:12px;padding:0 12px;display:flex;align-items:center;gap:12px;color:var(--fg1);font:500 14px/1 var(--ft)"><span style="{{ setIcoG }}"></span>Settings</div></sc-if>
|
||||
</div>
|
||||
|
||||
<div style="flex:1;min-width:0;background:var(--sf);display:flex;flex-direction:column;position:relative;border-left:1px solid var(--ln)">
|
||||
<div style="height:64px;flex:none;display:flex;align-items:center;gap:12px;padding:0 20px 0 24px;border-bottom:1px solid var(--ln)">
|
||||
<sc-if value="{{ mac }}"><div style="display:flex;gap:4px;color:var(--fg3);margin-right:4px"><span style="{{ i20.chevL }}"></span><span style="{{ i20.chevR }}"></span></div></sc-if>
|
||||
<div style="display:flex;align-items:center;gap:8px;font:500 22px/1 var(--fd);letter-spacing:-0.02em">{{ title }}<sc-if value="{{ s.files }}"><span style="{{ chevG }}"></span><span style="font:400 15px/1 var(--ft);letter-spacing:0;color:var(--fg2);white-space:nowrap">All files</span></sc-if></div>
|
||||
<div style="flex:1"></div>
|
||||
<sc-if value="{{ notSettings }}"><div style="width:260px;height:36px;border-radius:999px;background:var(--sf2);display:flex;align-items:center;gap:8px;padding:0 14px;color:var(--fg3);font:400 14px/1 var(--ft)"><span style="{{ i16.search }}"></span>Search in {{ title }}</div></sc-if>
|
||||
<sc-if value="{{ s.files }}">
|
||||
<div style="display:flex;padding:3px;border-radius:999px;background:var(--sf2);gap:2px"><div style="{{ segL }}"><span style="{{ i16.list }}"></span></div><div style="{{ segG }}"><span style="{{ i16.grid }}"></span></div></div>
|
||||
<div style="height:36px;padding:0 16px 0 12px;border-radius:999px;background:var(--ac);color:#FFFFFF;display:flex;align-items:center;gap:8px;font:600 14px/1 var(--ft);white-space:nowrap"><span style="{{ i18.plus }}"></span>Upload</div>
|
||||
</sc-if>
|
||||
<sc-if value="{{ s.photos }}"><div style="height:36px;padding:0 16px 0 12px;border-radius:999px;background:var(--ac);color:#FFFFFF;display:flex;align-items:center;gap:8px;font:600 14px/1 var(--ft);white-space:nowrap"><span style="{{ i18.upload }}"></span>Upload</div></sc-if>
|
||||
<sc-if value="{{ s.trash }}"><div style="height:36px;padding:0 16px;border-radius:999px;background:var(--dgs);color:var(--dg);display:flex;align-items:center;gap:8px;font:600 14px/1 var(--ft);white-space:nowrap"><span style="{{ i16.trash }}"></span>Empty trash</div></sc-if>
|
||||
<sc-if value="{{ s.offline }}"><div style="height:36px;padding:0 16px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;gap:8px;font:600 14px/1 var(--ft);white-space:nowrap"><span style="{{ i16.sync }}"></span>Sync now</div></sc-if>
|
||||
</div>
|
||||
|
||||
<div style="flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column;padding:0 24px">
|
||||
|
||||
<sc-if value="{{ s.files }}">
|
||||
<div style="flex:none;display:flex;align-items:center;gap:8px;padding:14px 0 10px">
|
||||
<div style="height:32px;padding:0 12px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft);white-space:nowrap"><span style="{{ i14.filter }}"></span>All types<span style="{{ i14.chevD }}"></span></div>
|
||||
<div style="height:32px;padding:0 12px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft);white-space:nowrap">Modified<span style="{{ i14.chevD }}"></span></div>
|
||||
<div style="height:32px;padding:0 12px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft);white-space:nowrap">Shared<span style="{{ i14.chevD }}"></span></div>
|
||||
<div style="height:32px;padding:0 12px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;gap:6px;font:600 13px/1 var(--ft);white-space:nowrap"><span style="{{ i14.offline }}"></span>Available offline<span style="{{ i14.x }}"></span></div>
|
||||
<div style="flex:1"></div>
|
||||
<div style="font:400 13px/1 var(--ft);color:var(--fg3)">10 items · 440 MB</div>
|
||||
</div>
|
||||
</sc-if>
|
||||
<sc-if value="{{ s.trash }}">
|
||||
<div style="flex:none;margin:16px 0 4px;padding:12px 16px;border-radius:14px;background:var(--sf2);display:flex;gap:10px;align-items:center;color:var(--fg2);font:400 14px/1.2 var(--ft)"><span style="{{ i18.info }}"></span>Items here are deleted for good after 30 days.</div>
|
||||
</sc-if>
|
||||
<sc-if value="{{ s.offline }}">
|
||||
<div style="flex:none;display:grid;grid-template-columns:minmax(0,2fr) repeat(3,minmax(0,1fr));gap:12px;padding:18px 0 8px">
|
||||
<div style="padding:16px 18px;border-radius:18px;background:var(--sf2);display:flex;flex-direction:column;gap:10px"><div style="display:flex;justify-content:space-between;align-items:baseline"><div style="font:600 28px/0.9 var(--fd);letter-spacing:-0.03em">2.4 GB</div><div style="font:400 13px/1 var(--ft);color:var(--fg3)">of 5 GB limit</div></div><div style="height:6px;border-radius:999px;background:var(--sf3);overflow:hidden"><div style="width:48%;height:100%;background:var(--ac)"></div></div></div>
|
||||
<div style="padding:16px 18px;border-radius:18px;background:var(--sf2);display:flex;flex-direction:column;gap:8px"><div style="font:600 28px/0.9 var(--fd);letter-spacing:-0.03em">142</div><div style="font:400 13px/1 var(--ft);color:var(--fg2)">Files up to date</div></div>
|
||||
<div style="padding:16px 18px;border-radius:18px;background:var(--sf2);display:flex;flex-direction:column;gap:8px"><div style="font:600 28px/0.9 var(--fd);letter-spacing:-0.03em;color:var(--act)">6</div><div style="font:400 13px/1 var(--ft);color:var(--fg2)">Syncing now</div></div>
|
||||
<div style="padding:16px 18px;border-radius:18px;background:var(--dgs);display:flex;flex-direction:column;gap:8px"><div style="font:600 28px/0.9 var(--fd);letter-spacing:-0.03em;color:var(--dg)">1</div><div style="font:400 13px/1 var(--ft);color:var(--dg)">Needs attention</div></div>
|
||||
</div>
|
||||
</sc-if>
|
||||
<sc-if value="{{ s.shares }}">
|
||||
<div style="flex:none;display:flex;padding:14px 0 8px"><div style="display:flex;padding:3px;border-radius:999px;background:var(--sf2);gap:2px">
|
||||
<div style="height:32px;padding:0 16px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;font:600 13px/1 var(--ft);white-space:nowrap">With you</div>
|
||||
<div style="height:32px;padding:0 16px;display:flex;align-items:center;font:500 13px/1 var(--ft);color:var(--fg2)">By you</div>
|
||||
<div style="height:32px;padding:0 16px;display:flex;align-items:center;font:500 13px/1 var(--ft);color:var(--fg2)">Links</div>
|
||||
</div></div>
|
||||
</sc-if>
|
||||
|
||||
<sc-if value="{{ showTable }}">
|
||||
<sc-for list="{{ groups }}" as="g" hint-placeholder-count="1">
|
||||
<sc-if value="{{ g.hasLabel }}"><div style="padding:18px 12px 6px;font:600 13px/1 var(--ft);color:var(--fg2)">{{ g.label }}</div></sc-if>
|
||||
<div style="display:grid;grid-template-columns:minmax(0,1fr) 180px 160px 120px;align-items:center;height:36px;padding:0 12px;border-bottom:1px solid var(--ln);font:600 12px/1 var(--ft);color:var(--fg3)">
|
||||
<div style="display:flex;align-items:center;gap:4px">{{ c0 }}<sc-if value="{{ sortable }}"><span style="{{ i14.up }}"></span></sc-if></div><div>{{ c1 }}</div><div>{{ c2 }}</div><div></div>
|
||||
</div>
|
||||
<sc-for list="{{ g.rows }}" as="f" hint-placeholder-count="8">
|
||||
<div style="{{ f.rs }}">
|
||||
<div style="display:flex;align-items:center;gap:12px;min-width:0"><div style="{{ f.tile }}"><span style="{{ f.ico }}"></span></div><div style="font:500 14px/1.2 var(--ft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">{{ f.name }}</div></div>
|
||||
<div style="font:400 13px/1.2 var(--ft);color:var(--fg2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">{{ f.a }}</div>
|
||||
<div style="display:flex;align-items:center;gap:6px;font:400 13px/1.2 var(--ft);color:var(--fg2);white-space:nowrap;overflow:hidden"><sc-if value="{{ f.bInline }}"><span style="{{ f.badge }}"></span></sc-if>{{ f.b }}</div>
|
||||
<div style="display:flex;align-items:center;justify-content:flex-end;gap:10px;color:var(--fg3)">
|
||||
<sc-if value="{{ f.bIcon }}"><span style="{{ f.badge }}"></span></sc-if>
|
||||
<sc-if value="{{ f.shared }}"><span style="{{ i16.users }}"></span></sc-if>
|
||||
<sc-if value="{{ f.fav }}"><span style="{{ starSm }}"></span></sc-if>
|
||||
<sc-if value="{{ restore }}"><div style="height:28px;padding:0 12px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;gap:6px;font:600 12px/1 var(--ft);white-space:nowrap"><span style="{{ i14.restore }}"></span>Restore</div></sc-if>
|
||||
<span style="{{ i18.moreH }}"></span>
|
||||
</div>
|
||||
</div>
|
||||
</sc-for>
|
||||
</sc-for>
|
||||
</sc-if>
|
||||
|
||||
<sc-if value="{{ showGrid }}">
|
||||
<div style="display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:16px;padding-top:6px">
|
||||
<sc-for list="{{ gridRows }}" as="f" hint-placeholder-count="10">
|
||||
<div style="border:1px solid var(--ln);border-radius:18px;overflow:hidden;display:flex;flex-direction:column;background:var(--sf)">
|
||||
<div style="{{ f.thumb }}"><span style="{{ f.icoL }}"></span></div>
|
||||
<div style="padding:10px 10px 12px 14px;display:flex;flex-direction:column;gap:5px">
|
||||
<div style="display:flex;align-items:center;gap:4px"><div style="flex:1;min-width:0;font:500 14px/1.2 var(--ft);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">{{ f.name }}</div><span style="{{ moreSm }}"></span></div>
|
||||
<div style="display:flex;align-items:center;gap:5px;font:400 12px/1.2 var(--ft);color:var(--fg3)"><sc-if value="{{ f.hasBadge }}"><span style="{{ f.badge }}"></span></sc-if>{{ f.meta }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</sc-for>
|
||||
</div>
|
||||
</sc-if>
|
||||
|
||||
<sc-if value="{{ s.photos }}">
|
||||
<div style="flex:none;display:flex;gap:8px;padding:14px 0 4px">
|
||||
<div style="height:32px;padding:0 14px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;font:600 13px/1 var(--ft);white-space:nowrap">All</div>
|
||||
<div style="height:32px;padding:0 14px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;font:500 13px/1 var(--ft);white-space:nowrap">Photos</div>
|
||||
<div style="height:32px;padding:0 14px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;font:500 13px/1 var(--ft);white-space:nowrap">Videos</div>
|
||||
<div style="height:32px;padding:0 14px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft);white-space:nowrap"><span style="{{ i14.camera }}"></span>Camera uploads</div>
|
||||
</div>
|
||||
<sc-for list="{{ photoGroups }}" as="g" hint-placeholder-count="2">
|
||||
<div style="display:flex;justify-content:space-between;align-items:baseline;padding:16px 0 10px"><div style="font:500 18px/1 var(--fd);letter-spacing:-0.02em">{{ g.label }}</div><div style="font:400 13px/1 var(--ft);color:var(--fg3)">{{ g.count }}</div></div>
|
||||
<div style="display:grid;grid-template-columns:repeat(8,minmax(0,1fr));gap:4px">
|
||||
<sc-for list="{{ g.tiles }}" as="t" hint-placeholder-count="16">
|
||||
<div style="{{ t.s }}"><sc-if value="{{ t.vid }}"><div style="position:absolute;right:6px;bottom:6px;height:20px;padding:0 7px 0 5px;border-radius:999px;background:rgba(14,13,11,0.7);color:#FFFFFF;display:flex;align-items:center;gap:3px;font:600 11px/1 var(--ft)"><span style="{{ i14.play }}"></span>{{ t.dur }}</div></sc-if></div>
|
||||
</sc-for>
|
||||
</div>
|
||||
</sc-for>
|
||||
</sc-if>
|
||||
|
||||
<sc-if value="{{ s.activity }}">
|
||||
<div style="max-width:760px;width:100%;display:flex;flex-direction:column">
|
||||
<sc-for list="{{ act }}" as="g" hint-placeholder-count="2">
|
||||
<div style="padding:20px 0 8px;font:600 13px/1 var(--ft);color:var(--fg2)">{{ g.label }}</div>
|
||||
<sc-for list="{{ g.items }}" as="a" hint-placeholder-count="3">
|
||||
<div style="display:flex;gap:14px;padding:14px 0;align-items:center;border-bottom:1px solid var(--ln)">
|
||||
<div style="{{ a.av }}">{{ a.who }}</div>
|
||||
<div style="flex:1;min-width:0;font:400 14px/1.3 var(--ft)"><span style="font-weight:600">{{ a.name }}</span> {{ a.verb }} <span style="font-weight:600">{{ a.obj }}</span> {{ a.tail }}</div>
|
||||
<div style="{{ a.tile }}"><span style="{{ a.ico }}"></span></div>
|
||||
<div style="width:48px;text-align:right;font:400 13px/1 var(--ft);color:var(--fg3)">{{ a.time }}</div>
|
||||
</div>
|
||||
</sc-for>
|
||||
</sc-for>
|
||||
</div>
|
||||
</sc-if>
|
||||
|
||||
<sc-if value="{{ s.settings }}">
|
||||
<div style="display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;padding:20px 0;align-items:start">
|
||||
<div style="display:flex;flex-direction:column;gap:16px">
|
||||
<div style="padding:20px;border-radius:20px;border:1px solid var(--ln);display:flex;flex-direction:column;gap:16px">
|
||||
<div style="display:flex;gap:14px;align-items:center"><div style="width:52px;height:52px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;justify-content:center;font:600 18px/1 var(--ft);flex:none">MR</div><div style="flex:1;display:flex;flex-direction:column;gap:5px"><div style="font:500 20px/1 var(--fd);letter-spacing:-0.02em">Marina Rocha</div><div style="font:400 14px/1 var(--ft);color:var(--fg2)">marina@rocha.family</div></div><div style="height:24px;padding:0 10px;border-radius:999px;background:var(--oks);color:var(--ok);display:flex;align-items:center;font:600 12px/1 var(--ft);white-space:nowrap">Connected</div></div>
|
||||
<div style="display:grid;grid-template-columns:auto minmax(0,1fr);gap:10px 16px;font:400 14px/1.2 var(--ft)"><span style="color:var(--fg3)">Server</span><span>cloud.rocha.family</span><span style="color:var(--fg3)">Version</span><span>Nextcloud 30.0.2</span><span style="color:var(--fg3)">Storage</span><div style="display:flex;align-items:center;gap:10px"><div style="flex:1;height:6px;border-radius:999px;background:var(--sf3);overflow:hidden"><div style="width:38%;height:100%;background:var(--ac)"></div></div><span style="color:var(--fg2)">38.2 of 100 GB</span></div></div>
|
||||
<div style="display:flex;gap:8px"><div style="height:36px;padding:0 16px;border-radius:999px;background:var(--sf2);display:flex;align-items:center;gap:8px;font:600 14px/1 var(--ft);white-space:nowrap"><span style="{{ i14.external }}"></span>Manage on web</div><div style="height:36px;padding:0 16px;border-radius:999px;background:var(--dgs);color:var(--dg);display:flex;align-items:center;gap:8px;font:600 14px/1 var(--ft);white-space:nowrap"><span style="{{ i14.logout }}"></span>Log out</div></div>
|
||||
</div>
|
||||
<div style="padding:8px 20px 12px;border-radius:20px;border:1px solid var(--ln);display:flex;flex-direction:column">
|
||||
<div style="padding:12px 0 8px;font:500 17px/1 var(--fd);letter-spacing:-0.02em">Accounts</div>
|
||||
<div style="display:flex;align-items:center;gap:12px;height:56px;border-bottom:1px solid var(--ln)"><div style="width:32px;height:32px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;justify-content:center;font:600 12px/1 var(--ft)">MR</div><div style="flex:1;display:flex;flex-direction:column;gap:4px"><div style="font:500 14px/1 var(--ft)">Marina Rocha</div><div style="font:400 12px/1 var(--ft);color:var(--fg3)">cloud.rocha.family</div></div><span style="{{ checkA }}"></span></div>
|
||||
<div style="display:flex;align-items:center;gap:12px;height:56px;border-bottom:1px solid var(--ln)"><div style="width:32px;height:32px;border-radius:999px;background:#85D1BD;color:#0E0D0B;display:flex;align-items:center;justify-content:center;font:600 12px/1 var(--ft)">MR</div><div style="flex:1;display:flex;flex-direction:column;gap:4px"><div style="font:500 14px/1 var(--ft)">Marina · Work</div><div style="font:400 12px/1 var(--ft);color:var(--fg3)">files.acme-studio.com</div></div><div style="font:600 13px/1 var(--ft);color:var(--act)">Switch</div></div>
|
||||
<div style="display:flex;align-items:center;gap:12px;height:48px;color:var(--act);font:600 14px/1 var(--ft)"><div style="width:32px;display:flex;justify-content:center"><span style="{{ i18.plus }}"></span></div>Add account</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:column;gap:16px">
|
||||
<div style="padding:8px 20px 8px;border-radius:20px;border:1px solid var(--ln);display:flex;flex-direction:column">
|
||||
<div style="padding:12px 0 8px;font:500 17px/1 var(--fd);letter-spacing:-0.02em">Security</div>
|
||||
<div style="display:flex;align-items:center;gap:14px;min-height:60px;border-bottom:1px solid var(--ln)"><span style="{{ bioIco }}"></span><div style="flex:1;display:flex;flex-direction:column;gap:4px"><div style="font:400 14px/1.1 var(--ft)">{{ bioLabel }}</div><div style="font:400 12px/1.2 var(--ft);color:var(--fg3)">Needed every time you open Noo</div></div><div style="width:44px;height:26px;border-radius:999px;background:var(--ac);padding:3px;box-sizing:border-box;display:flex;justify-content:flex-end;flex:none"><div style="width:20px;height:20px;border-radius:999px;background:#FFFFFF"></div></div></div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:52px"><span style="{{ i18.timer }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Lock after</div><div style="height:32px;padding:0 10px 0 12px;border-radius:10px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft)">5 minutes idle<span style="{{ i14.chevD }}"></span></div></div>
|
||||
</div>
|
||||
<div style="padding:8px 20px 8px;border-radius:20px;border:1px solid var(--ln);display:flex;flex-direction:column">
|
||||
<div style="padding:12px 0 8px;font:500 17px/1 var(--fd);letter-spacing:-0.02em">File sync</div>
|
||||
<div style="display:flex;align-items:center;gap:14px;min-height:60px;border-bottom:1px solid var(--ln)"><span style="{{ i18.folder }}"></span><div style="flex:1;display:flex;flex-direction:column;gap:4px"><div style="font:400 14px/1.1 var(--ft)">Local sync folder</div><div style="font:400 12px/1.2 var(--ft);color:var(--fg3);font-family:ui-monospace,Menlo,monospace">{{ syncPath }}</div></div><div style="height:32px;padding:0 12px;border-radius:999px;background:var(--sf2);display:flex;align-items:center;font:600 13px/1 var(--ft);white-space:nowrap">Change</div></div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:52px;border-bottom:1px solid var(--ln)"><span style="{{ i18.sync }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Sync automatically</div><div style="width:44px;height:26px;border-radius:999px;background:var(--ac);padding:3px;box-sizing:border-box;display:flex;justify-content:flex-end;flex:none"><div style="width:20px;height:20px;border-radius:999px;background:#FFFFFF"></div></div></div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:52px;border-bottom:1px solid var(--ln)"><span style="{{ i18.download }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Download files on demand</div><div style="width:44px;height:26px;border-radius:999px;background:var(--ac);padding:3px;box-sizing:border-box;display:flex;justify-content:flex-end;flex:none"><div style="width:20px;height:20px;border-radius:999px;background:#FFFFFF"></div></div></div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:52px"><span style="{{ i18.wifi }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Pause on metered networks</div><div style="width:44px;height:26px;border-radius:999px;background:var(--sf3);padding:3px;box-sizing:border-box;display:flex;justify-content:flex-start;flex:none"><div style="width:20px;height:20px;border-radius:999px;background:#FFFFFF"></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</sc-if>
|
||||
|
||||
<sc-if value="{{ s.settings2 }}">
|
||||
<div style="display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:16px;padding:20px 0;align-items:start">
|
||||
<div style="display:flex;flex-direction:column;gap:16px">
|
||||
<div style="padding:8px 20px 8px;border-radius:20px;border:1px solid var(--ln);display:flex;flex-direction:column">
|
||||
<div style="padding:12px 0 8px;font:500 17px/1 var(--fd);letter-spacing:-0.02em">Files cache</div>
|
||||
<div style="display:flex;flex-direction:column;gap:10px;padding:10px 0 14px;border-bottom:1px solid var(--ln)"><div style="display:flex;justify-content:space-between;font:400 14px/1 var(--ft)"><span>Cache in use</span><span style="color:var(--fg2)">1.2 of 2 GB</span></div><div style="height:6px;border-radius:999px;background:var(--sf3);overflow:hidden"><div style="width:60%;height:100%;background:var(--ac)"></div></div></div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:52px;border-bottom:1px solid var(--ln)"><span style="{{ i18.database }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Cache limit</div><div style="height:32px;padding:0 10px 0 12px;border-radius:10px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft)">2 GB<span style="{{ i14.chevD }}"></span></div></div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:52px"><span style="{{ i18.trash }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Clear cached files</div><div style="height:32px;padding:0 14px;border-radius:999px;background:var(--dgs);color:var(--dg);display:flex;align-items:center;font:600 13px/1 var(--ft);white-space:nowrap">Clear cache</div></div>
|
||||
</div>
|
||||
<div style="padding:8px 20px 8px;border-radius:20px;border:1px solid var(--ln);display:flex;flex-direction:column">
|
||||
<div style="padding:12px 0 8px;font:500 17px/1 var(--fd);letter-spacing:-0.02em">Appearance</div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:56px;border-bottom:1px solid var(--ln)"><span style="{{ i18.palette }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Theme</div><div style="display:flex;padding:3px;border-radius:999px;background:var(--sf2);gap:2px"><div style="height:28px;padding:0 12px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;font:600 13px/1 var(--ft);white-space:nowrap">System</div><div style="height:28px;padding:0 12px;display:flex;align-items:center;font:500 13px/1 var(--ft);color:var(--fg2)">Light</div><div style="height:28px;padding:0 12px;display:flex;align-items:center;font:500 13px/1 var(--ft);color:var(--fg2)">Dark</div></div></div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:56px;border-bottom:1px solid var(--ln)"><span style="{{ i18.grid }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Default file view</div><div style="display:flex;padding:3px;border-radius:999px;background:var(--sf2);gap:2px"><div style="height:28px;padding:0 12px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;gap:6px;font:600 13px/1 var(--ft);white-space:nowrap"><span style="{{ i14.list }}"></span>List</div><div style="height:28px;padding:0 12px;display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft);color:var(--fg2)"><span style="{{ i14.grid }}"></span>Grid</div></div></div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:52px"><span style="{{ i18.hidden }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Show hidden files</div><div style="width:44px;height:26px;border-radius:999px;background:var(--sf3);padding:3px;box-sizing:border-box;display:flex;justify-content:flex-start;flex:none"><div style="width:20px;height:20px;border-radius:999px;background:#FFFFFF"></div></div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:column;gap:16px">
|
||||
<div style="padding:8px 20px 12px;border-radius:20px;border:1px solid var(--ln);display:flex;flex-direction:column">
|
||||
<div style="padding:12px 0 4px;display:flex;justify-content:space-between;align-items:baseline"><div style="font:500 17px/1 var(--fd);letter-spacing:-0.02em">Sidebar tabs</div><div style="font:400 12px/1 var(--ft);color:var(--fg3)">Drag to reorder</div></div>
|
||||
<div style="padding:4px 0 8px;font:400 12px/1.3 var(--ft);color:var(--fg3)">Pinned tabs show at the top of the sidebar, and in the bottom bar on mobile.</div>
|
||||
<sc-for list="{{ tabRows }}" as="t" hint-placeholder-count="8">
|
||||
<div style="display:flex;align-items:center;gap:12px;height:44px;border-bottom:1px solid var(--ln)"><span style="{{ gripS }}"></span><span style="{{ t.ico }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">{{ t.label }}</div><div style="{{ t.pinS }}"><span style="{{ t.pinI }}"></span></div></div>
|
||||
</sc-for>
|
||||
</div>
|
||||
<div style="padding:8px 20px 8px;border-radius:20px;border:1px solid var(--ln);display:flex;flex-direction:column">
|
||||
<div style="padding:12px 0 8px;font:500 17px/1 var(--fd);letter-spacing:-0.02em">{{ swipeTitle }}</div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:52px;border-bottom:1px solid var(--ln)"><span style="{{ i18.swipe }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Swipe left</div><div style="height:32px;padding:0 10px 0 12px;border-radius:10px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft);color:var(--dg)"><span style="{{ i14.trash }}"></span>Delete<span style="{{ i14.chevD }}"></span></div></div>
|
||||
<div style="display:flex;align-items:center;gap:14px;height:52px"><span style="{{ i18.swipe }}"></span><div style="flex:1;font:400 14px/1 var(--ft)">Swipe right</div><div style="height:32px;padding:0 10px 0 12px;border-radius:10px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft);color:var(--act)"><span style="{{ i14.star }}"></span>Favorite<span style="{{ i14.chevD }}"></span></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</sc-if>
|
||||
|
||||
</div>
|
||||
|
||||
<sc-if value="{{ share }}">
|
||||
<div style="position:absolute;inset:0;background:var(--scrim);display:flex;align-items:center;justify-content:center">
|
||||
<div style="width:540px;background:var(--sf);border-radius:24px;padding:24px;box-sizing:border-box;display:flex;flex-direction:column;gap:20px;box-shadow:0 24px 48px rgba(30,0,47,0.14)">
|
||||
<div style="display:flex;gap:12px;align-items:center">
|
||||
<div style="{{ shareTile }}"><span style="{{ i20.doc }}"></span></div>
|
||||
<div style="flex:1;min-width:0;display:flex;flex-direction:column;gap:5px"><div style="font:500 19px/1 var(--fd);letter-spacing:-0.02em">Share “Q3 Planning.pdf”</div><div style="font:400 13px/1 var(--ft);color:var(--fg3)">2.4 MB · Documents</div></div>
|
||||
<div style="width:32px;height:32px;border-radius:999px;background:var(--sf2);display:flex;align-items:center;justify-content:center"><span style="{{ i16.x }}"></span></div>
|
||||
</div>
|
||||
<div style="display:flex;flex-direction:column;gap:12px">
|
||||
<div style="font:500 16px/1 var(--fd);letter-spacing:-0.02em">Share with people</div>
|
||||
<div style="display:flex;gap:8px"><div style="flex:1;height:42px;border-radius:12px;background:var(--sf2);display:flex;align-items:center;gap:10px;padding:0 12px;color:var(--fg3);font:400 14px/1 var(--ft)"><span style="{{ i18.userPlus }}"></span>Name, email or group</div><div style="height:42px;padding:0 10px 0 14px;border-radius:12px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 13px/1 var(--ft)">Can edit<span style="{{ i14.chevD }}"></span></div></div>
|
||||
<div style="display:flex;align-items:center;gap:12px;height:44px"><div style="{{ avYou }}">MR</div><div style="flex:1;display:flex;flex-direction:column;gap:4px"><div style="font:500 14px/1 var(--ft)">You</div><div style="font:400 12px/1 var(--ft);color:var(--fg3)">marina@rocha.family</div></div><div style="font:500 13px/1 var(--ft);color:var(--fg3)">Owner</div></div>
|
||||
<div style="display:flex;align-items:center;gap:12px;height:44px"><div style="{{ avAna }}">AS</div><div style="flex:1;display:flex;flex-direction:column;gap:4px"><div style="font:500 14px/1 var(--ft)">Ana Souza</div><div style="font:400 12px/1 var(--ft);color:var(--fg3)">ana@rocha.family</div></div><div style="height:28px;padding:0 8px 0 12px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;gap:4px;font:500 12px/1 var(--ft);white-space:nowrap">Can edit<span style="{{ i14.chevD }}"></span></div></div>
|
||||
<div style="display:flex;align-items:center;gap:12px;height:44px"><div style="width:32px;height:32px;border-radius:999px;background:var(--sf2);color:var(--fg2);display:flex;align-items:center;justify-content:center;flex:none"><span style="{{ i16.users }}"></span></div><div style="flex:1;display:flex;flex-direction:column;gap:4px"><div style="font:500 14px/1 var(--ft)">Design team</div><div style="font:400 12px/1 var(--ft);color:var(--fg3)">Group · 6 people</div></div><div style="height:28px;padding:0 8px 0 12px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;gap:4px;font:500 12px/1 var(--ft);white-space:nowrap">Can view<span style="{{ i14.chevD }}"></span></div></div>
|
||||
</div>
|
||||
<div style="height:1px;background:var(--ln)"></div>
|
||||
<div style="display:flex;flex-direction:column;gap:12px">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center"><div style="display:flex;flex-direction:column;gap:5px"><div style="font:500 16px/1 var(--fd);letter-spacing:-0.02em">Share link</div><div style="font:400 12px/1 var(--ft);color:var(--fg3)">Anyone with the link can view</div></div><div style="width:44px;height:26px;border-radius:999px;background:var(--ac);padding:3px;box-sizing:border-box;display:flex;justify-content:flex-end;flex:none"><div style="width:20px;height:20px;border-radius:999px;background:#FFFFFF"></div></div></div>
|
||||
<div style="border-radius:14px;background:var(--sf2);padding:5px 5px 5px 14px;display:flex;gap:10px;align-items:center;color:var(--fg2)"><span style="{{ i16.link }}"></span><div style="flex:1;min-width:0;font:400 13px/1 ui-monospace,Menlo,monospace;color:var(--fg1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis">https://cloud.rocha.family/s/k7Pq2xW</div><div style="height:34px;padding:0 14px;border-radius:999px;background:var(--ac);color:#FFFFFF;display:flex;align-items:center;gap:6px;font:600 13px/1 var(--ft);white-space:nowrap"><span style="{{ i14.copy }}"></span>Copy link</div></div>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
||||
<div style="height:30px;padding:0 12px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 12px/1 var(--ft);white-space:nowrap"><span style="{{ i14.eye }}"></span>Can view<span style="{{ i14.chevD }}"></span></div>
|
||||
<div style="height:30px;padding:0 12px;border-radius:999px;background:var(--acs);color:var(--act);display:flex;align-items:center;gap:6px;font:600 12px/1 var(--ft);white-space:nowrap"><span style="{{ i14.calendar }}"></span>Expires Oct 24</div>
|
||||
<div style="height:30px;padding:0 12px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 12px/1 var(--ft);white-space:nowrap"><span style="{{ i14.lock }}"></span>Add password</div>
|
||||
<div style="height:30px;padding:0 12px;border-radius:999px;border:1px solid var(--ln);display:flex;align-items:center;gap:6px;font:500 12px/1 var(--ft);white-space:nowrap"><span style="{{ i14.download }}"></span>Allow download</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:1px;background:var(--ln)"></div>
|
||||
<div style="display:flex;align-items:center;gap:12px">
|
||||
<div style="flex:1;font:400 12px/1.3 var(--ft);color:var(--fg3)">Sends a copy through another app. Link settings don’t apply.</div>
|
||||
<div style="height:38px;padding:0 16px;border-radius:999px;border:1.5px solid var(--sf3);display:flex;align-items:center;gap:8px;font:600 14px/1 var(--ft);white-space:nowrap"><span style="{{ i16.send }}"></span>Send file directly</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</sc-if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</sc-if>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script data-props="{"$preview":{"width":1280,"height":800},"os":{"editor":"enum","options":["mac","windows"],"default":"mac","tsType":"'mac'|'windows'"},"screen":{"editor":"enum","options":["files","filesGrid","photos","favorites","offline","shares","recent","activity","trash","share","settings","settings2"],"default":"files","tsType":"string"},"theme":{"editor":"enum","options":["light","dark"],"default":"light","tsType":"'light'|'dark'"}}">
|
||||
class Component extends DCLogic {
|
||||
componentDidMount() {
|
||||
if (!window.NK) this._t = setInterval(() => { if (window.NK) { clearInterval(this._t); this.forceUpdate(); } }, 40);
|
||||
}
|
||||
componentWillUnmount() { clearInterval(this._t); }
|
||||
renderVals() {
|
||||
const K = window.NK;
|
||||
if (!K) return { ready: false };
|
||||
const { I, ic, D, row, TH, tile, tiles, avatar } = K;
|
||||
const mac = this.props.os !== 'windows', win = !mac;
|
||||
const sc = this.props.screen || 'files';
|
||||
const theme = this.props.theme === 'dark' ? 'dark' : 'light';
|
||||
const share = sc === 'share', grid = sc === 'filesGrid';
|
||||
const base = (share || grid) ? 'files' : sc;
|
||||
const settings = base.startsWith('settings');
|
||||
const s = {}; ['files','photos','activity','trash','favorites','offline','shares','recent','settings','settings2'].forEach(k => s[k] = base === k);
|
||||
const RS = sel => ({ display: 'grid', gridTemplateColumns: 'minmax(0,1fr) 180px 160px 120px', alignItems: 'center', height: 52, padding: '0 12px', borderBottom: '1px solid var(--ln)', background: sel ? 'var(--acs)' : 'transparent', borderRadius: sel ? 12 : 0 });
|
||||
const mk = (list, fn, o = {}) => list.map((f, i) => { const r = row(f, { tile: 30, r: 9, ico: 16, ...o }); Object.assign(r, fn(f)); r.rs = RS(o.sel === i); return r; });
|
||||
let groups = [], cols = ['Name', 'Size', 'Modified'];
|
||||
const split = f => { const p = (f.meta || '').split(' · '); return { a: p[0], b: p[1] || '' }; };
|
||||
if (base === 'files') groups = [{ rows: mk(D.files, f => ({ a: f.size, b: f.mod, bIcon: !!f.off }), { noSwipe: 1, sel: 3 }) }];
|
||||
if (base === 'favorites') groups = [{ rows: mk(D.favorites, f => ({ a: f.size, b: f.mod, bIcon: !!f.off, fav: true })) }];
|
||||
if (base === 'offline') { cols = ['Name', 'Size', 'Status']; groups = [{ rows: mk(D.offline, f => ({ a: f.size, b: split(f).a, bInline: true })) }]; }
|
||||
if (base === 'shares') { cols = ['Name', 'Shared by', 'Permission']; groups = [{ rows: mk(D.shares, f => ({ a: f.by, b: f.perm })) }]; }
|
||||
if (base === 'recent') { cols = ['Name', 'Activity', 'Location']; groups = D.recent.map(g => ({ label: g.label, rows: mk(g.rows, f => ({ ...split(f), bIcon: !!f.off })) })); }
|
||||
if (base === 'trash') { cols = ['Name', 'Original location', 'Deleted']; groups = [{ rows: mk(D.trash, f => ({ a: f.from, b: f.del })) }]; }
|
||||
groups = groups.map(g => ({ ...g, hasLabel: !!g.label }));
|
||||
const title = settings ? 'Settings' : D.titles[base];
|
||||
const seg = on => ({ width: 34, height: 30, borderRadius: 999, display: 'flex', alignItems: 'center', justifyContent: 'center', background: on ? 'var(--acs)' : 'transparent', color: on ? 'var(--act)' : 'var(--fg3)' });
|
||||
const counts = { trash: '12', offline: '1', shares: '3' };
|
||||
const navItem = ([label, ico, key]) => ({ label, ico: I[18][ico], icoG: ic(ico, 18, 'var(--fg2)'), on: key === base, off: key !== base, count: counts[key] || '' });
|
||||
return {
|
||||
ready: true, mac, win, s, title, groups, c0: cols[0], c1: cols[1], c2: cols[2], share, notSettings: !settings,
|
||||
sortable: base === 'files' || base === 'favorites',
|
||||
restore: base === 'trash',
|
||||
root: { ...TH[theme], width: 1280, height: 800, borderRadius: mac ? 12 : 8, overflow: 'hidden', position: 'relative', display: 'flex', flexDirection: 'column', background: 'var(--bg)', color: 'var(--fg1)', fontFamily: 'var(--ft)', border: '1px solid var(--ln)', boxSizing: 'border-box' },
|
||||
i14: I[14], i16: I[16], i18: I[18], i20: I[20], i24: I[24],
|
||||
showTable: groups.length > 0 && !grid, showGrid: grid,
|
||||
gridRows: D.files.map(f => row(f, { noSwipe: 1, thumbH: 118 })).map(r => ({ ...r, meta: `${r.size} · ${r.mod}` })),
|
||||
segL: seg(!grid), segG: seg(grid),
|
||||
navA: D.pinned.map(navItem), navB: D.menu.map(navItem),
|
||||
setOn: settings, setOff: !settings, setIcoG: ic('settings', 18, 'var(--fg2)'),
|
||||
starSm: ic('star', 16, 'var(--act)'), moreSm: ic('moreH', 16, 'var(--fg3)'),
|
||||
checkA: ic('check', 18, 'var(--act)'), chevG: ic('chevR', 16, 'var(--fg3)'), gripS: ic('grip', 16, 'var(--fg3)'),
|
||||
photoGroups: [{ label: 'September 2026', count: '38 items', tiles: tiles(24, 0, [2, 9, 13, 20]) }, { label: 'August 2026', count: '112 items', tiles: tiles(16, 3, [4, 11]) }],
|
||||
act: D.activity.map(g => ({ label: g.label, items: g.items.map(a => ({ ...a, av: avatar(a.col, 36), tile: tile(a.kind, 30, 9), ico: I[16][K.KIND[a.kind][2]] })) })),
|
||||
tabRows: [...D.pinned.map(([label, ico]) => ({ label, ico: I[18][ico], p: 1 })), ...D.menu.map(([label, ico]) => ({ label, ico: I[18][ico], p: 0 }))].map(t => ({ ...t,
|
||||
pinS: { width: 30, height: 30, borderRadius: 999, display: 'flex', alignItems: 'center', justifyContent: 'center', background: t.p ? 'var(--acs)' : 'var(--sf2)', color: t.p ? 'var(--act)' : 'var(--fg3)' },
|
||||
pinI: I[14][t.p ? 'pin' : 'pinOff'] })),
|
||||
bioLabel: mac ? 'Lock with Touch ID' : 'Lock with Windows Hello', bioIco: I[18][mac ? 'fingerprint' : 'face'],
|
||||
syncPath: mac ? '~/Noo/rocha.family' : 'C:\\Users\\Marina\\Noo',
|
||||
swipeTitle: mac ? 'Trackpad swipe on a file' : 'Touch swipe on a file',
|
||||
shareTile: tile('pdf', 40, 12), avYou: avatar('#CBA5FD', 32), avAna: avatar('#DA9AC7', 32)
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -130,7 +130,7 @@ a:hover{color:#6E08B3}
|
||||
</div>
|
||||
|
||||
<div style="display:flex;flex-direction:column;gap:12px">
|
||||
<div style="font:600 13px/1 var(--ft);color:var(--fg2)">Navigation · iOS tab bar / Android navigation bar / desktop sidebar</div>
|
||||
<div style="font:600 13px/1 var(--ft);color:var(--fg2)">Navigation · iOS tab bar / Android navigation bar / tablet sidebar</div>
|
||||
<div style="display:flex;background:var(--sf);border-radius:20px;padding:10px 0">
|
||||
<sc-for list="{{ nav }}" as="n" hint-placeholder-count="5">
|
||||
<sc-if value="{{ n.on }}"><div style="flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;color:var(--act);font:600 10px/1 var(--ft)"><span style="{{ n.ico }}"></span>{{ n.label }}</div></sc-if>
|
||||
|
||||
@@ -20,7 +20,7 @@ a:hover{color:#6E08B3}
|
||||
<div style="padding:96px;display:flex;flex-direction:column;gap:120px;font-family:'Instrument Sans',system-ui,sans-serif;color:#0E0D0B;width:max-content">
|
||||
<div style="display:flex;flex-direction:column;gap:20px;max-width:1100px">
|
||||
<div style="font:600 96px/0.9 'Schibsted Grotesk',system-ui,sans-serif;letter-spacing:-0.03em">Noo</div>
|
||||
<div style="font:400 28px/1.3 'Instrument Sans',system-ui,sans-serif;color:#5A5852;text-wrap:pretty">A Nextcloud client for iOS, Android, macOS and Windows. One brand language, navigation adapted per platform. Light and dark shown for every screen.</div>
|
||||
<div style="font:400 28px/1.3 'Instrument Sans',system-ui,sans-serif;color:#5A5852;text-wrap:pretty">A Nextcloud client for iOS and Android. One brand language, navigation adapted per platform. Light and dark shown for every screen.</div>
|
||||
<div style="display:flex;gap:12px;font:600 20px/1 'Instrument Sans',system-ui,sans-serif"><a href="Noo Design System.dc.html" style="height:52px;padding:0 24px;border-radius:999px;background:#8D0DE3;color:#FFFFFF;display:flex;align-items:center;white-space:nowrap">Open the design system</a><a href="DESIGN_SYSTEM.md" style="height:52px;padding:0 24px;border-radius:999px;background:#FFFFFF;display:flex;align-items:center;white-space:nowrap">DESIGN_SYSTEM.md</a></div>
|
||||
</div>
|
||||
|
||||
@@ -47,44 +47,20 @@ a:hover{color:#6E08B3}
|
||||
</section>
|
||||
</sc-for>
|
||||
|
||||
<sc-for list="{{ desktop }}" as="p" hint-placeholder-count="2">
|
||||
<section style="display:flex;flex-direction:column;gap:40px">
|
||||
<div style="display:flex;align-items:baseline;gap:24px;border-bottom:2px solid #0E0D0B;padding-bottom:20px"><div style="font:600 72px/0.9 'Schibsted Grotesk',system-ui,sans-serif;letter-spacing:-0.03em">{{ p.name }}</div><div style="font:400 24px/1.2 'Instrument Sans',system-ui,sans-serif;color:#5A5852;white-space:nowrap">{{ p.note }}</div></div>
|
||||
<div style="display:flex;gap:160px">
|
||||
<sc-for list="{{ p.themes }}" as="t" hint-placeholder-count="2">
|
||||
<div style="display:flex;flex-direction:column;gap:32px">
|
||||
<div style="font:500 36px/1 'Schibsted Grotesk',system-ui,sans-serif;letter-spacing:-0.02em">{{ t.label }}</div>
|
||||
<div style="display:grid;grid-template-columns:repeat(3,1280px);gap:72px 64px">
|
||||
<sc-for list="{{ screensD }}" as="sc" hint-placeholder-count="12">
|
||||
<div style="display:flex;flex-direction:column;gap:14px">
|
||||
<div style="display:flex;gap:10px;align-items:baseline;font:500 20px/1 'Instrument Sans',system-ui,sans-serif"><span style="color:#7C7A72">{{ sc.n }}</span><span style="white-space:nowrap">{{ sc.label }}</span></div>
|
||||
<div style="width:1280px;height:800px;border-radius:12px;box-shadow:0 24px 48px rgba(30,0,47,0.12)">
|
||||
<dc-import name="Desktop Screen" os="{{ p.id }}" screen="{{ sc.id }}" theme="{{ t.id }}" hint-size="1280px,800px"></dc-import>
|
||||
</div>
|
||||
</div>
|
||||
</sc-for>
|
||||
</div>
|
||||
</div>
|
||||
</sc-for>
|
||||
</div>
|
||||
</section>
|
||||
</sc-for>
|
||||
</div>
|
||||
</x-dc>
|
||||
<script type="text/x-dc" data-dc-script data-props="{"platforms":{"editor":"enum","options":["all","ios","android","mac","windows"],"default":"all","tsType":"string"},"themes":{"editor":"enum","options":["both","light","dark"],"default":"both","tsType":"string"}}">
|
||||
|
||||
<script type="text/x-dc" data-dc-script data-props="{"platforms":{"editor":"enum","options":["all","ios","android"],"default":"all","tsType":"string"},"themes":{"editor":"enum","options":["both","light","dark"],"default":"both","tsType":"string"}}">
|
||||
class Component extends DCLogic {
|
||||
renderVals() {
|
||||
const pf = this.props.platforms || 'all';
|
||||
const th = this.props.themes || 'both';
|
||||
const themes = [{ id: 'light', label: 'Light' }, { id: 'dark', label: 'Dark' }].filter(t => th === 'both' || th === t.id);
|
||||
const M = [['files','Files · list'],['filesGrid','Files · grid'],['photos','Photos'],['favorites','Favorites'],['offline','Offline'],['shares','Shares'],['recent','Recent'],['activity','Activity'],['trash','Trash'],['drawer','Menu (unpinned tabs)'],['share','Share sheet'],['settings','Settings · account & security'],['settings2','Settings · sync, cache, appearance'],['settings3','Settings · tabs & swipe']];
|
||||
const Dk = [['files','Files · list'],['filesGrid','Files · grid'],['photos','Photos'],['favorites','Favorites'],['offline','Offline'],['shares','Shares'],['recent','Recent'],['activity','Activity'],['trash','Trash'],['share','Share dialog'],['settings','Settings · account, security, sync'],['settings2','Settings · cache, appearance, tabs, swipe']];
|
||||
const num = a => a.map(([id, label], i) => ({ id, label, n: String(i + 1).padStart(2, '0') }));
|
||||
const keep = id => pf === 'all' || pf === id;
|
||||
return {
|
||||
screensM: num(M), screensD: num(Dk),
|
||||
mobile: [{ id: 'ios', name: 'iOS', note: 'Large titles, tab bar, “+” upload in the nav bar.', themes }, { id: 'android', name: 'Android', note: 'Top app bar, navigation bar with pill indicator, Upload FAB.', themes }].filter(p => keep(p.id)),
|
||||
desktop: [{ id: 'mac', name: 'macOS', note: 'Traffic lights in the sidebar, back/forward in the toolbar.', themes }, { id: 'windows', name: 'Windows', note: 'Title bar with caption buttons, same sidebar and toolbar.', themes }].filter(p => keep(p.id))
|
||||
screensM: num(M),
|
||||
mobile: [{ id: 'ios', name: 'iOS', note: 'Large titles, tab bar, “+” upload in the nav bar.', themes }, { id: 'android', name: 'Android', note: 'Top app bar, navigation bar with pill indicator, Upload FAB.', themes }].filter(p => keep(p.id))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ widgets. Key points:
|
||||
|
||||
- **Material 3**, seed-color based. `AppTheme.seedColors` is the picker list
|
||||
users choose from; `defaultNextcloudBlue` (`#0082C9`) is the fallback.
|
||||
- **Dynamic color** (Android 12+ Material You / desktop accent color) is
|
||||
- **Dynamic color** (Android 12+ Material You) is
|
||||
supported via `package:dynamic_color`'s `DynamicColorBuilder` wrapping the
|
||||
whole app in `main.dart`. When available and `useDynamicColor` is on, the
|
||||
OS-provided `ColorScheme` wins over the seed color — always thread both
|
||||
@@ -81,7 +81,7 @@ Catalog:
|
||||
|---|---|
|
||||
| `core/` | `NooButton`, `NooFab`, `NooChip`, `NooSegmentedControl`, `NooToggle`, `NooSearchField`, `NooAvatar`, `NooBadge`, `NooProgressBar` |
|
||||
| `lists/` | `NooGroupedList`, `NooSettingsRow`, `NooTabOrderRow`, `NooBanner`, `NooInfoNote` (tinted info callout; `SettingsSection(notice:)`), `NooSummaryCard`, `NooSelectionBar` |
|
||||
| `files/` | `NooFileKind` (spec §1.2 tiles; `NooFileKind.from(name:, mimeType:, isDirectory:)`), `NooFileTile`, `NooStatusIcon`/`NooSyncStatus`, `NooFileRow` (mobile 64px), `NooFileTableHeader`/`NooFileTableRow` (desktop), `NooSwipeAction` |
|
||||
| `files/` | `NooFileKind` (spec §1.2 tiles; `NooFileKind.from(name:, mimeType:, isDirectory:)`), `NooFileTile`, `NooStatusIcon`/`NooSyncStatus`, `NooFileRow` (mobile 64px), `NooFileTableHeader`/`NooFileTableRow` (wide tablet), `NooSwipeAction` |
|
||||
| `media/` | `NooGridCard`, `NooPhotoTile` (video badge, selection), `NooPhotoGroupHeader`/`NooPhotoGrid` (sliver, or `.box`), `NooActivityItem`, `NooStatCard` |
|
||||
| `nav/` | `NooBottomBar`, `NooTopBar` (a `PreferredSizeWidget`) with `NooTopBarButton`/`NooTopBarBack`, `NooDrawer` with its `Account`/`Storage`/`Item`/`Link` parts, `NooSidebar` with `NooSidebarItem`/`Divider`/`Account`/`Storage`, `NooToolbar` (floating rounded card with margin; `NooToolbar.outerHeight` for `appBar` sizing) |
|
||||
| `overlays/` | `showNooSheet`, `showNooDialog`/`NooDialog`, `NooOverlayHeader`, `NooTextField`, and the share parts `NooShareSection`, `NooPersonAccessRow`, `NooPermissionPill` |
|
||||
@@ -102,8 +102,6 @@ Gotchas:
|
||||
trigger it) but also fires it directly if the drag goes far enough (past
|
||||
1.8x the block's width) before release - a full swipe-through does delete
|
||||
in one gesture, it's not tap-only anymore.
|
||||
- Window chrome (macOS traffic lights, the Windows 40px title bar) isn't
|
||||
built yet. `NooSidebar.windowControls` is the slot for it.
|
||||
- Always read colors through `context.nooColors`, never
|
||||
`Theme.of(context).colorScheme` - the latter is Flutter's own Material 3
|
||||
scheme, reseeded by the user's accent color choice (`AppTheme.light`/
|
||||
@@ -156,7 +154,7 @@ blocks are noted where they matter:
|
||||
`settings_dialogs.dart`'s `confirmRemoveAccount`.
|
||||
`lib/widgets/shell/shell_common.dart` — account/storage formatting,
|
||||
`openSettings`/`openSearch`, `showAccountSwitcher`, `ShellAvatarButton`,
|
||||
`ShellSearchLauncher`, shared by the mobile and desktop shell chrome.
|
||||
`ShellSearchLauncher`, shared by the mobile and wide tablet shell chrome.
|
||||
- [`getItemIcon`/`getIconColor`/`ItemThumbnail`](../../lib/widgets/item_icon.dart)
|
||||
— `getItemIcon`/`getIconColor` are superseded by `NooFileKind` in
|
||||
rebuilt screens; `ItemThumbnail` is still reused as-is, fed into
|
||||
@@ -362,13 +360,13 @@ Markdown files (`.md`/`.markdown`) in `MediaTextPreview` open rendered via `flut
|
||||
|
||||
`ShareSheet`: focusing the people search field does not scroll; once the user types, `_revealPeopleSection` animates the "Share with people" section (keyed by `_peopleKey` on the `NooShareSection`, not the inner column) to just below the sheet's top edge with a small gap.
|
||||
|
||||
## Desktop/tablet layout notes
|
||||
## Wide tablet layout notes
|
||||
|
||||
- The desktop branch in `main.dart` is wrapped in `SafeArea` so tablets keep
|
||||
- The wide tablet branch in `main.dart` is wrapped in `SafeArea` so tablets keep
|
||||
system bars clear of the sidebar; the sidebar has no divider between pinned
|
||||
and hidden tabs.
|
||||
- Desktop Settings is the same two-level menu as mobile (centered 640px column, back button in the floating toolbar); the
|
||||
pushed category screens render the desktop card layout.
|
||||
- Wide tablet Settings is the same two-level menu as mobile (centered 640px column, back button in the floating toolbar); the
|
||||
pushed category screens render the wide tablet card layout.
|
||||
- Settings that don't apply in wide-tablet (Appearance nav options,
|
||||
Swipe on a file) show a `NooInfoNote` via `SettingsSection.notice`.
|
||||
- Mobile-layout grids (Files, Favorites, move/copy picker, share upload,
|
||||
|
||||
@@ -40,7 +40,7 @@ Website: <https://noo.ayushya.dev>
|
||||
Prerequisites:
|
||||
|
||||
- [Flutter](https://docs.flutter.dev/get-started/install) (SDK `^3.12.2`)
|
||||
- An Android device or emulator, an iOS device, or Windows
|
||||
- An Android device or emulator, or an iOS device or simulator
|
||||
- A Nextcloud server with Login Flow v2 enabled (on by default since
|
||||
Nextcloud 15)
|
||||
|
||||
@@ -57,7 +57,6 @@ finish signing in.
|
||||
```bash
|
||||
flutter build apk # Android (debug-signed unless you configure a key)
|
||||
flutter build ios # iOS
|
||||
flutter build windows # Windows
|
||||
```
|
||||
|
||||
Release builds read signing details from `android/key.properties` or from
|
||||
|
||||
@@ -14,8 +14,6 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.2+5
|
||||
|
||||
environment:
|
||||
|
||||
Reference in New Issue
Block a user