Commit graph

12 commits

Author SHA1 Message Date
Paulo Castellano
f62b4bb4a5
Unify sidebar workspace and account menus (#240)
* Unify sidebar workspace and account menus.

Merge workspace switching, profile, billing, and language into one header dropdown, move notifications beside it, pin support links to the footer, and add Workspace Settings to the nav — without MCP or onboarding residual.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Remove Workspace Settings from the sidebar nav.

Settings already lives in the unified account menu; keep the workspace group free for items like MCP later.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Cover sidebar menu role gates in browser tests.

Assert account/workspace settings visibility for owner, admin, member, and self-hosted so the unified menu stays aligned with WorkspacePolicy.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Rename sidebar wait helper to avoid Pest browser collision.

waitForTestId was already declared in MobileEditorTest, which fataled the e2e suite when listing Browser tests.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Add sidebar menu browser coverage for workspace viewers.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 21:33:16 -03:00
Paulo Castellano
2c52c90b6e fix(mobile): polish automations, dialogs, workspaces and post views
- automations: minimal back-only header on mobile for the workflow builder
  and detail tabs (extracted AutomationMobileBackHeader); open live
  automations on the metrics tab (drafts still open on workflow); full-width
  status filter + refresh on the invocations toolbar; use IconMenu2 for the
  mobile sidebar trigger
- dialogs: stack DialogFooter primary-on-top / cancel-at-bottom on mobile
- workspaces: bring the workspace picker cards into the neo-brutalist design
- posts: left-align the label filter content; wrap the post-view date/status
  header so a long status badge no longer squeezes the date; add hamburger
  clearance to the editor's mobile tab bar
2026-07-18 10:58:07 -03:00
Paulo Castellano
f9a1731073 fix(auth): stop AuthSplitLayout overflowing on mobile with wide content
The mobile grid column was implicit (auto), so it sized to content — a long
workspace name (truncate = nowrap, wide intrinsic size) stretched the form
column to its max-w-lg (512px) and overflowed a 375px viewport by ~31px on the
workspaces list. Make the column an explicit minmax(0,1fr) track and give the
grid item min-w-0 so it stays within the viewport and the name truncates.

Found by a runtime horizontal-overflow check; adds MobileOverflowTest guarding
it across the layout variants (AuthLayout, default, full-width editor, detail).
2026-07-17 20:00:13 -03:00
Paulo Castellano
5118640a9c feat(automations): mobile-safe builder with desktop notice
The node builder is gated to lg+ (its fixed side panels no longer overflow a phone); below lg it shows a 'works best on a larger screen' notice. Automation tabs scroll instead of cutting off.
2026-07-17 18:38:20 -03:00
Paulo Castellano
ccf888258d feat(assets): touch-friendly gallery card actions on mobile
Uploads/Unsplash/Giphy card actions are visible on touch instead of hover-only, without the dark scrim on small screens.
2026-07-17 18:38:20 -03:00
Paulo Castellano
b7b3809790 feat(posts): make the post editor usable on mobile
- Top switcher (Compose / Channels / Preview / Comments) reveals the panel that was hidden below lg
- Sticky bottom action bar puts schedule/publish/delete within thumb reach
- Composer media actions and comment toolbar are visible on touch (no hover needed); media grid is 3-up
- Clamp media picker and emoji picker widths to the viewport
2026-07-17 18:38:20 -03:00
Paulo Castellano
cf045f2cdb Harden per-image alt text across publishers, validation, and attach paths
Publishing:
- Only send alt text for images (isImage guards on LinkedIn, X, Discord, Mastodon); never inject altText into video/document payloads.
- X sets alt via a best-effort media/metadata call so a metadata failure no longer blocks the tweet.

Validation:
- Validate media alt_text with a closure on media.*.meta so width/height/duration/slide_* survive a post update (Laravel's excludeUnvalidatedArrayKeys was stripping them).
- Add ALT_TEXT_MAX_LENGTH constant, a proper string-type error, and a localized attribute name.

Media attach (REST + MCP):
- Support per-image alt on attach-media-from-url via structured urls: [{url, alt?}] and on the MCP upload tool via an optional alt; alt is stored only for images.
- Carry submitted meta onto hosted external-URL media so alt is no longer dropped.

Composer:
- Alt-text dialog disables Save and reddens the counter over the limit, counting code points of the trimmed value to match the backend.
- Autosave shows 'Saved' only on a successful response; the lightbox alt overlay renders for images only.

Adds unit, feature, MCP, and browser tests covering every path above.
2026-07-16 13:55:33 -03:00
Paulo Castellano
b5dfc37022 Show alt text inside the image lightbox (opt-in) 2026-07-11 13:09:34 -03:00
Paulo Castellano
6b39616be2 Cover the composer alt-text round-trip with a browser test 2026-07-11 10:52:26 -03:00
Paulo Castellano
ef81ea74a8 Add frontend unit tests and harden the cropper's test coverage
Add Vitest (test:unit) with exact-value tests for the crop math (containScale, defaultSelection, clampSelection, all resizeSelection corners, and mime/filename resolution), and wire it plus the Pest browser test into CI. The browser test now samples output pixels against a four-quadrant fixture, so it detects a blank, flipped, or wrong crop rather than only asserting a 512x512 canvas. Add composer test:all to run PHP + Vitest + browser tests locally.
2026-07-04 09:56:38 -03:00
Paulo Castellano
2549a82e9b Address review: cropper mime/zoom/error fixes, harden browser test
- Output a canvas-encodable mime (jpeg/png/webp, else png) and keep the File's
  name/extension in sync, so non-encodable input (gif/svg/heic) no longer ships
  PNG bytes mislabeled as the original type.
- Clamp zoom to a maximum (8x cover) so scrolling in can't collapse the crop to
  a sub-pixel region.
- Handle undecodable/zero-dimension images (@error + naturalWidth guard) with a
  crop_error message instead of a permanently-disabled Save.
- Replace the str_contains(static::class) Vite heuristic with a dedicated
  BrowserTestCase ($fakesVite = false).
- The browser test now decodes the dispatched blob and asserts a 512x512 image,
  and uses route(..., absolute: false) instead of a hardcoded path.
- Remove tests/Browser/ProbeTest.php (committed debug scratch).
2026-07-03 22:07:23 -03:00
Paulo Castellano
c6369a6ddb Crop the avatar/logo before upload with a dependency-free cropper
Selecting an avatar or workspace logo now opens a crop dialog (drag + zoom)
before uploading, so the image is framed the way it renders. The crop is
performed client-side and the resized 512x512 result is what gets uploaded.

This reworks the idea from #131 without its cropper dependency: vue-advanced-cropper
was last released ~2 years ago and we did not want an unmaintained package for
something this load-bearing. What we need is narrow (fixed 1:1, a circle/square
mask, fixed-size output), so a small canvas-based cropper covers it:

- imageCrop.ts: pure transform math (cover-fit, clamp, zoom, viewport->source).
- ImageCropperDialog.vue: CSS-transform preview, pointer drag, wheel/button zoom,
  a ResizeObserver to measure the modal (no requestAnimationFrame timing hacks),
  and a canvas toBlob only on save.
- PhotoUpload.vue: opens the cropper on file select; the mask shape follows the
  display shape (round avatar / square logo) instead of always being round.
- crop_* strings added to all 15 locales.

Also installs Pest browser testing (pest-plugin-browser + Playwright) and adds a
browser test for the crop flow. TestCase only calls withoutVite() for non-browser
tests, since browser tests need the real Vite assets to boot the SPA. The Pest
browser server does not parse multipart uploads, so the test asserts the crop
dispatches the correct upload request; endpoint persistence stays covered by
ProfileUpdateTest.
2026-07-03 21:46:19 -03:00