Commit graph

1170 commits

Author SHA1 Message Date
Paulo Castellano
80c478541e
Merge pull request #199 from trypostit/fix/youtube-shorts-3-minutes
fix: raise YouTube Shorts max duration to 3 minutes
2026-07-23 12:24:05 -03:00
Paulo Castellano
8964dda8f2 fix: raise YouTube Shorts max duration to 3 minutes
YouTube Shorts now allow videos up to 3 minutes. The dashboard media rules still capped uploads at 60s (API/MCP already had no duration gate), so align the frontend validation, content-type copy, and unit test.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 12:06:15 -03:00
Paulo Castellano
71df3bf801
Merge pull request #198 from trypostit/fix/chunked-upload-unicode-filename
fix: allow unicode filenames in chunked asset uploads
2026-07-23 12:00:01 -03:00
Paulo Castellano
246022e9bc test: cover ChunkedAssetReceiver and ChunkReceipt paths
Adds dedicated tests for local assemble, multipart complete/progress, MediaResource response shape, and orphan R2 cleanup when media registration fails.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:51:13 -03:00
Paulo Castellano
a4f5c35ead fix: refresh assets gallery after deleting an upload
The uploads grid is client-fetched, so an Inertia delete with preserveState left the stale list on screen until a hard refresh.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:38:29 -03:00
Paulo Castellano
c1b28159b2 refactor: split HasMedia path storage into image vs stream helpers
Keep the image-normalize vs binary-stream split, but move each path into a focused private method so addMediaFromPath stays linear.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:23:05 -03:00
Paulo Castellano
66dbf438ee style: use interpolated medias/{$filename} paths
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:21:52 -03:00
Paulo Castellano
2ba5ce2b3f refactor: pull chunked upload orchestration out of AssetController
Controller only authorizes and returns ChunkReceipt. Multipart vs local assemble lives in ChunkedAssetReceiver; JSON shape comes from MediaResource.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:18:10 -03:00
Paulo Castellano
08ce75d2ec refactor: harden chunked cloud uploads after full PR review
Fix real edge cases: enforce 5MiB non-final parts, track offsets for ordered/idempotent chunks, size from bytes received, delete orphaned R2 objects if Media create fails, and split the controller into clearer paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:16:39 -03:00
Paulo Castellano
3c59dce349 test: cover chunked uploads across local, public, and S3 disks
Dataset for multipart strategy selection plus HTTP paths for assemble (local/public/images) and multipart (s3/r2/spaces videos).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:09:44 -03:00
Paulo Castellano
d4be085642 refactor: clarify multipart is an object-storage fast path, not a disk limit
Local/public already used the assemble-then-store flow. Rename supports() so it is obvious every filesystem disk works; multipart only kicks in for S3-compatible remote disks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:07:11 -03:00
Paulo Castellano
cd79554cfb fix: multipart chunked video uploads directly to R2
The last chunk was reassembling the full file locally and pushing ~185MB to R2 in one request (53s+). Videos/PDFs now upload each chunk as an S3 multipart part so finalize only completes the upload.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 11:04:52 -03:00
Paulo Castellano
005d3c9dd6 fix: stream chunked video finalize to object storage
Unicode filename encoding was correct, but large videos still died on the last chunk: the whole file was loaded into memory and uploaded to R2 via Guzzle within PHP-FPM's 30s limit. Stream non-images with writeStream and lift the time limit on finalize.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 10:55:57 -03:00
Paulo Castellano
f4513efc70 fix: allow unicode filenames in chunked asset uploads
X-File-Name is an HTTP header, so raw en-dashes/emoji blow up fetch() before the request leaves the browser. Percent-encode on the client and rawurldecode on the server.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 10:46:48 -03:00
Paulo Castellano
3194ec2069
Merge pull request #190 from trypostit/feat/release-changelog-thumbnail
feat(release): render a branded changelog thumbnail in the release ritual
2026-07-18 17:06:49 -03:00
Paulo Castellano
805a628f66 feat(release): render a branded changelog thumbnail in the release ritual
Add a 1200x630 changelog thumbnail as a fourth release artifact, generated
from a shared brand template that mirrors the marketing-site hero / OG image:
warm cream to lavender wash, ink dot-grid, an Instrument Serif headline with a
hand-drawn violet squiggle, a segmented 'CHANGELOG | <version>' sticker badge,
and colored ink-bordered theme chips with solid offset shadows.

- .claude/release-assets/: render-thumbnail.mjs (Playwright renderer),
  thumbnail.template.html (brand template), logo.png (TryPost wordmark)
- .claude/commands/release.md: new Step 5b renders the thumbnail; it is
  versioned in the artifacts PR alongside the changelog and email
- releases/v1.0.6/thumbnail.png: image for the latest release
2026-07-18 16:56:38 -03:00
Paulo Castellano
501de51327
Merge pull request #189 from trypostit/chore/release-v1.0.6-artifacts
chore(release): v1.0.6 changelog + customer email artifacts
2026-07-18 16:24:04 -03:00
Paulo Castellano
2894b388b8 chore(release): make the /release command English-only 2026-07-18 16:21:27 -03:00
Paulo Castellano
32bee12086 chore(release): always version release artifacts via a PR in the /release command 2026-07-18 16:20:47 -03:00
Paulo Castellano
47c8224083 chore(release): add v1.0.6 changelog + customer email artifacts 2026-07-18 16:18:12 -03:00
Paulo Castellano
60c4c5324d
Merge pull request #188 from trypostit/feat/onboarding-referral-source
feat(onboarding): add "where you found us" referral-source step
2026-07-18 16:11:56 -03:00
Paulo Castellano
a78f5a96ae feat(onboarding): add "where you found us" referral-source step
Adds a single-select referral-source step between the goals and connect
steps of onboarding. The choice is stored on users.referral_source and
mirrored to PostHog, mirroring the existing persona and goals steps.

- ReferralSource enum (12 sources) + nullable users.referral_source column
- referralSource()/storeReferralSource() controller actions with the same
  self-hosted, subscribed, persona and goals guards as the sibling steps
- connect() now requires a referral source before rendering
- Single-select ReferralSource.vue page mirroring the goals step
- Localized across all 15 locales
2026-07-18 16:07:11 -03:00
Paulo Castellano
7b37190358
Merge pull request #128 from dantaspaulo/feat/ai-brand-colors-toggle
feat(ai-create): let users choose brand colors or free AI colors for images
2026-07-18 15:17:44 -03:00
Paulo Castellano
2c2ab69e68 Merge main + finalize AI brand-colors toggle
Resolves the AiPostWizard conflict and completes the feature:
- i18n parity: brand_colors_label + brand_colors_description in all 15 locales
  (was en/es/pt-BR only, which broke LocalizationParityTest).
- Reworked the two-button toggle into a Switch with an explanatory description
  (matches the settings Switch/card pattern).
- Only shown for templates that honor the flag: added appliesBrandVisuals() to
  the AiContentTemplate contract (ImageCard=true, tweet cards=false), exposed as
  applies_brand_visuals in the create-page DTO, and gated the toggle on it — so
  it no longer appears (as a no-op) for tweet-card styles.
- Tests: TemplateContractTest covers appliesBrandVisuals for all templates.
2026-07-18 15:12:26 -03:00
Paulo Castellano
d0c32751d7
Merge pull request #147 from dantaspaulo/feat/settings-into-user-menu
refactor(sidebar): move Settings from the sidebar footer into the user menu
2026-07-18 14:49:07 -03:00
Paulo Castellano
0544b3a915 Merge remote-tracking branch 'origin/main' into feat/settings-into-user-menu
# Conflicts:
#	resources/js/components/AppSidebar.vue
2026-07-18 14:46:09 -03:00
Paulo Castellano
e4806c7662 refactor(sidebar): show Profile before Settings in the user menu 2026-07-18 14:42:45 -03:00
Paulo Castellano
132f84f404
Merge pull request #187 from trypostit/feat/mobile-experience
Improve the mobile experience (post editor + app-wide polish)
2026-07-18 14:37:22 -03:00
Paulo Castellano
f63286efd4 fix(sidebar): open the workspace menu to the side on desktop with a matching icon
The workspace switcher now opens to the right on desktop (like the user menu)
and stays below the trigger on mobile, via useSidebar()'s isMobile. The trigger
icon follows the direction: chevron-right on desktop, an up/down selector on
mobile — for both the workspace switcher and the user menu.
2026-07-18 14:34:15 -03:00
Paulo Castellano
bc93667fcf fix(mobile): clear the hamburger and match its size on the scheduled editor banner
The scheduled-post banner in the editor now clears the floating sidebar
trigger on mobile (pl-12 md:pl-0), aligns its calendar icon to the top of
the text, and matches the hamburger's size (size-10 md:size-9). Desktop is
unchanged.
2026-07-18 14:17:18 -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
e94f2cfe96 fix(posts): hide the autosave status in the mobile switcher
It's only the autosave indicator (Draft/Saving/Saved) and it crowded the tabs.
Drop it from the mobile switcher (the desktop header still shows it) so the tabs
get the full bar.
2026-07-18 09:35:50 -03:00
Paulo Castellano
708f1adbd2 fix(posts): align the mobile switcher bar with the sidebar trigger
Use py-3 so the tabs sit at the same vertical position as the top-3 hamburger,
and rounded-md so the tab corners match the trigger.
2026-07-18 09:32:23 -03:00
Paulo Castellano
119edef5b9 fix(posts): mobile editor — taller switcher tabs and a wider Post now button
Match the switcher tab height to the sidebar trigger (h-10), and let the primary
publish button fill the footer (flex-1) on mobile while staying auto-width on desktop.
2026-07-18 09:28:07 -03:00
Paulo Castellano
da5066e43e fix(posts): merge the editor status into the mobile switcher bar
On mobile the header was a whole bar showing only the Draft/Saving/Saved status.
Move that status into the switcher bar (right side) and hide the header on mobile
(the scheduled banner still shows), reclaiming a row. The switcher clears the
floating hamburger when it's the top bar.
2026-07-18 09:20:51 -03:00
Paulo Castellano
b7351667e2 fix(posts): tidy the post-view header on mobile
Stack it into a clean back-button row and a date + status row (date left, badge
right) instead of cramming everything into one line where the date wrapped and
the badge floated.
2026-07-18 09:06:56 -03:00
Paulo Castellano
fd557fe559 fix(ui): align the mobile sidebar trigger with the header buttons
Move the floating hamburger from left-2/top-2 to left-4/top-3 so it lines up
with the header's content padding (and the calendar's nav buttons); bump the
non-header page top reserve to pt-14 to clear the taller trigger.
2026-07-18 08:59:55 -03:00
Paulo Castellano
13e5bdb761 fix(ui): match the mobile sidebar trigger to the icon button size
The floating hamburger was size-9 (36px) next to size-10 (40px) icon buttons, so
it read as too small. Bump it to size-10 to match.
2026-07-18 08:55:49 -03:00
Paulo Castellano
0716ea0bd5 fix(posts): mobile calendar header — nav + compact date on row 1, full-width New post below
Move Today up with prev/next, keep the date picker compact on the right instead
of full-width, and give New post its own full-width row.
2026-07-18 08:38:09 -03:00
Paulo Castellano
6e0d663fc7 fix(posts): redesign the mobile calendar header
Split the header into a dedicated mobile layout (< lg) and the desktop grid.
Mobile is two clean rows: prev / date picker (fills) / next, then Today +
full-width New post. Fixes the stretched, styleless Today button. Each header
owns its own controls, so the date picker and view switcher no longer need
lg:hidden / hidden lg:block toggles.
2026-07-18 08:33:17 -03:00
Paulo Castellano
3de62ec2e3 fix(posts): stack the posts index toolbar into full-width rows on mobile
Search, label filter, and New post each take their own full-width row below sm
(inline on desktop). The label filter trigger goes full-width to match.
2026-07-17 21:20:52 -03:00
Paulo Castellano
6ead4eee84 fix(analytics): full-width account selector on mobile
Matches the date-range picker below it instead of sitting content-width.
2026-07-17 21:16:43 -03:00
Paulo Castellano
07c2e7cbf3 fix(posts): tidy the mobile calendar header
- Show/hide the date picker and view switcher with Tailwind (lg:hidden /
  hidden lg:block) instead of the isMobile ref; isMobile now only drives
  effectiveView (which changes navigation behavior, not just visibility)
- Full-width buttons on mobile: prev / Today (fills) / next, and the date
  picker fills the row next to New post
2026-07-17 21:16:43 -03:00
Paulo Castellano
fe721d490b refactor(posts): render PostEditorActions once in the editor header
The scheduled and editable states each rendered their own copy; the actions
component already decides internally what to show, so it only needs one instance
pushed right with ml-auto.
2026-07-17 21:16:43 -03:00
Paulo Castellano
d3738a2ec1 fix(ui): stop the scrollable tabs list from clipping button borders
overflow-x-auto forces overflow-y to auto too, so the tab triggers' border and
shadow were clipped at the list edges (visible on the editor Preview/Channels/
Comments tabs). Drop the fixed h-10 and pad the list (p-1) so the scroll
container has room around the buttons on all sides.
2026-07-17 20:58:53 -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
2013808312 fix(ui): third-pass mobile fixes
- AutomationHeader reserves space for the floating hamburger on mobile (its full-width pages had the back button under the trigger)
- AlertDialogContent caps height + scrolls like DialogContent
- AiGenerateDialog preview wraps long tokens (break-words)
- Enlarge notification panel action buttons on the full-width mobile panel (max-sm:size-9)
- min-w-0 so the billing processing title-bar label can truncate
2026-07-17 19:41:52 -03:00
Paulo Castellano
3d33d0d380 fix(posts): enlarge the platform logo badge in the preview switcher on mobile 2026-07-17 19:27:09 -03:00
Paulo Castellano
e31116c4b7 fix(posts): scale the preview phone mockup down on mobile for side padding
The 380px mockup frame is wider than a phone viewport, so it sat edge-to-edge. Scale it to 90% below lg (origin top-center keeps it centered) so there's clean symmetric padding to the screen edges. Reverts the now-redundant px-2 container tweak back to px-4.
2026-07-17 19:24:55 -03:00
Paulo Castellano
ca42a9f0ef fix(posts): tighten preview padding to px-2 on mobile so the phone mockup fits pixel-perfect 2026-07-17 19:18:00 -03:00