Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8e18113
feat(web-api-contract): add desktop organization branding contract
richiemcilroy May 6, 2026
41573b9
feat(web): add desktop organization branding server helpers
richiemcilroy May 6, 2026
acb7ad2
test(web): add desktop organization branding unit tests
richiemcilroy May 6, 2026
0a6789c
feat(web): extend desktop API CORS and PATCH export
richiemcilroy May 6, 2026
ca65402
feat(web): implement desktop organization branding endpoints
richiemcilroy May 6, 2026
05fe41f
feat(tauri): extend organization payload and org cache metadata
richiemcilroy May 6, 2026
5398565
feat(desktop): add organization branding client utilities
richiemcilroy May 6, 2026
6abb3e1
test(desktop): add organization branding utility tests
richiemcilroy May 6, 2026
5395523
feat(desktop): add brand colors dropdown control
richiemcilroy May 6, 2026
a6399c5
feat(desktop): add brand swatches to hex color input
richiemcilroy May 6, 2026
44cacf4
feat(desktop): add organization picker dropdown
richiemcilroy May 6, 2026
6aff2a0
feat(desktop): add brand colors to gradient editor
richiemcilroy May 6, 2026
98df995
feat(desktop): use brand swatches in captions and keyboard tabs
richiemcilroy May 6, 2026
142357e
feat(desktop): wire brand swatches into editor config sidebar
richiemcilroy May 6, 2026
41ae83d
feat(desktop): add organization dropdown to editor header
richiemcilroy May 6, 2026
9f15799
feat(desktop): sync export org picker with branding selection
richiemcilroy May 6, 2026
53f75cc
style(ui): refresh shared button variants
richiemcilroy May 6, 2026
f3e5f00
style(web): refine global typography and surfaces
richiemcilroy May 6, 2026
e514041
feat(web): add design system preview route
richiemcilroy May 6, 2026
ac129a4
feat(web): redesign marketing site navbar
richiemcilroy May 6, 2026
13f39d4
feat(web): refresh homepage marketing sections
richiemcilroy May 6, 2026
73a9157
chore(web): update workflow v1 manifest
richiemcilroy May 6, 2026
0c8c560
Revert "feat(web): add design system preview route"
richiemcilroy May 6, 2026
aba2981
Revert "feat(web): refresh homepage marketing sections"
richiemcilroy May 6, 2026
f2d3a4c
Revert "feat(web): redesign marketing site navbar"
richiemcilroy May 6, 2026
bccb2f8
Revert "style(web): refine global typography and surfaces"
richiemcilroy May 6, 2026
3911c55
Revert "style(ui): refresh shared button variants"
richiemcilroy May 6, 2026
9652fd1
refactor(desktop): import organization brand color keys from utils
richiemcilroy May 6, 2026
fc691e8
perf(desktop): avoid quadratic string concat in encodeFileAsBase64
richiemcilroy May 6, 2026
ef935f1
feat(desktop): cache organization branding updates locally
richiemcilroy May 6, 2026
972de6d
perf(web): check base64 length before decoding logo upload
richiemcilroy May 6, 2026
455ae73
fix(web): apply organization logo upload before persisting db row
richiemcilroy May 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions apps/desktop/src-tauri/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,12 +293,33 @@ pub async fn desktop_video_progress(
Ok(())
}

#[derive(Serialize, Deserialize, Type, Debug, Clone, Default)]
#[serde(rename_all = "camelCase")]
pub struct OrganizationBrandColors {
pub primary: Option<String>,
pub secondary: Option<String>,
pub accent: Option<String>,
pub background: Option<String>,
}

fn default_organization_role() -> String {
"member".to_string()
}

#[derive(Serialize, Deserialize, Type, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Organization {
pub id: String,
pub name: String,
pub owner_id: String,
#[serde(default = "default_organization_role")]
pub role: String,
#[serde(default)]
pub can_edit_brand: bool,
#[serde(default)]
pub icon_url: Option<String>,
#[serde(default)]
pub brand_colors: OrganizationBrandColors,
}

pub async fn signal_recording_complete(
Expand Down
3 changes: 3 additions & 0 deletions apps/desktop/src-tauri/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub struct AuthStore {
pub plan: Option<Plan>,
#[serde(default)]
pub organizations: Vec<Organization>,
#[serde(default)]
pub organizations_updated_at: Option<i32>,
}

#[derive(Serialize, Deserialize, Type, Debug)]
Expand Down Expand Up @@ -101,6 +103,7 @@ impl AuthStore {
auth.organizations = api::fetch_organizations(app)
.await
.map_err(|e| e.to_string())?;
auth.organizations_updated_at = Some(chrono::Utc::now().timestamp() as i32);

Self::set(app, Some(auth))?;

Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3139,6 +3139,7 @@ async fn check_upgraded_and_update(app: AppHandle) -> Result<bool, String> {
last_checked: chrono::Utc::now().timestamp() as i32,
}),
organizations: auth.organizations,
organizations_updated_at: auth.organizations_updated_at,
};
println!("Updating auth store with new pro status");
AuthStore::set(&app, Some(updated_auth)).map_err(|e| e.to_string())?;
Expand Down
77 changes: 77 additions & 0 deletions apps/desktop/src/routes/editor/BrandColorsDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { DropdownMenu as KDropdownMenu } from "@kobalte/core/dropdown-menu";
import { cx } from "cva";
import { For, Show } from "solid-js";
import type { OrganizationBrandColorSwatch } from "~/utils/organization-branding";
import IconCapChevronDown from "~icons/cap/chevron-down";
import { getColorPreviewBorderColor } from "./color-utils";
import { DropdownItem, PopperContent, topLeftAnimateClasses } from "./ui";

export function BrandColorsDropdown(props: {
swatches: OrganizationBrandColorSwatch[];
onSelect: (color: string) => void;
disabled?: boolean;
class?: string;
}) {
return (
<Show when={props.swatches.length > 0}>
<KDropdownMenu gutter={6} placement="bottom-start">
<KDropdownMenu.Trigger
disabled={props.disabled}
class={cx(
"flex h-8 w-full items-center gap-2 rounded-lg border border-gray-3 bg-gray-2 px-2 text-sm text-gray-12 transition-colors hover:border-gray-4 hover:bg-gray-3 disabled:pointer-events-none disabled:opacity-50",
props.class,
)}
>
<span class="min-w-0 flex-1 truncate text-left">Brand colours</span>
<span class="flex shrink-0 -space-x-1">
<For each={props.swatches.slice(0, 4)}>
{(swatch) => (
<span
class="size-4 rounded-full border border-gray-1"
style={{
"background-color": swatch.color,
"box-shadow": `inset 0 0 0 1px ${getColorPreviewBorderColor(
swatch.color,
)}`,
}}
/>
)}
</For>
</span>
<IconCapChevronDown class="size-4 shrink-0 text-gray-10" />
</KDropdownMenu.Trigger>
<KDropdownMenu.Portal>
<PopperContent<typeof KDropdownMenu.Content>
as={KDropdownMenu.Content}
class={cx("w-56", topLeftAnimateClasses)}
>
<div class="p-1.5">
<For each={props.swatches}>
{(swatch) => (
<DropdownItem
class="h-9 gap-2"
onSelect={() => props.onSelect(swatch.color)}
>
<span
class="size-5 shrink-0 rounded-md"
style={{
"background-color": swatch.color,
"box-shadow": `inset 0 0 0 1px ${getColorPreviewBorderColor(
swatch.color,
)}`,
}}
/>
<span class="min-w-0 flex-1 truncate">{swatch.label}</span>
<span class="text-xs text-gray-10 tabular-nums">
{swatch.color}
</span>
</DropdownItem>
)}
</For>
</div>
</PopperContent>
</KDropdownMenu.Portal>
</KDropdownMenu>
</Show>
);
}
8 changes: 7 additions & 1 deletion apps/desktop/src/routes/editor/CaptionsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import toast from "solid-toast";
import { Toggle } from "~/components/Toggle";
import Tooltip from "~/components/Tooltip";
import { defaultCaptionSettings } from "~/store/captions";
import type { OrganizationBrandColorSwatch } from "~/utils/organization-branding";
import type { CaptionSettings } from "~/utils/tauri";
import { commands, events } from "~/utils/tauri";
import IconCapChevronDown from "~icons/cap/chevron-down";
Expand Down Expand Up @@ -132,7 +133,9 @@ const LANGUAGE_OPTIONS: LanguageOption[] = [
{ code: "ta", label: "Tamil" },
];

export function CaptionsTab() {
export function CaptionsTab(props: {
brandColorSwatches: OrganizationBrandColorSwatch[];
}) {
const { project, setProject, editorInstance, editorState, setEditorState } =
useEditorContext();

Expand Down Expand Up @@ -763,6 +766,7 @@ export function CaptionsTab() {
<span class="text-gray-11 text-sm">Text Color</span>
<HexColorInput
value={getSetting("color")}
brandColorSwatches={props.brandColorSwatches}
onChange={(value) => updateCaptionSetting("color", value)}
/>
</div>
Expand All @@ -775,6 +779,7 @@ export function CaptionsTab() {
<span class="text-gray-11 text-sm">Background Color</span>
<HexColorInput
value={getSetting("backgroundColor")}
brandColorSwatches={props.brandColorSwatches}
onChange={(value) =>
updateCaptionSetting("backgroundColor", value)
}
Expand Down Expand Up @@ -856,6 +861,7 @@ export function CaptionsTab() {
<span class="text-gray-11 text-sm">Highlight Color</span>
<HexColorInput
value={getSetting("highlightColor")}
brandColorSwatches={props.brandColorSwatches}
onChange={(value) =>
updateCaptionSetting("highlightColor", value)
}
Expand Down
Loading
Loading