Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions apps/desktop/src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { loadInstalledExtensions } from "./lib/extensions/extension-manager";
// Aliased as getHostServiceManager to minimize diff with fork's quit lifecycle code
import { getHostServiceCoordinator as getHostServiceManager } from "./lib/host-service-coordinator";
import { closeLocalDb, localDb } from "./lib/local-db";
import { requestLocalNetworkAccess } from "./lib/local-network-permission";
import { ensureProjectIconsDir, getProjectIconPath } from "./lib/project-icons";
import { reportError } from "./lib/report-error";
import { initSentry } from "./lib/sentry";
Expand Down Expand Up @@ -617,6 +618,7 @@ if (!gotTheLock) {
await app.whenReady();
registerWithMacOSNotificationCenter();
requestAppleEventsAccess();
requestLocalNetworkAccess();
initializeBrowserIdentityManager();
initializeBrowserWebviewCompat();
browserSitePermissionManager.initialize();
Expand Down
30 changes: 10 additions & 20 deletions apps/desktop/src/main/lib/dock-icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,20 @@ import { app, nativeImage } from "electron";
import { env } from "main/env.main";
import { prerelease } from "semver";
import { getWorkspaceName } from "shared/env.shared";
import twColors from "tailwindcss/colors";

type RGB = [number, number, number];

type Bounds = { top: number; left: number; bottom: number; right: number };

/**
* Deterministic workspace-name → RGB picker using Tailwind's 500-level palette.
* Deterministic workspace-name → RGB picker. Hashes the name to a hue via the
* golden angle (137.508°) so successive workspaces land far apart on the color
* wheel, then converts a fixed-lightness/chroma OKLCH point to sRGB.
*/
const pickWorkspaceColor = (() => {
const FALLBACK: RGB = [59, 130, 246]; // blue-500

function parseOklch(str: string): { l: number; c: number; h: number } | null {
const m = str.match(/oklch\(([\d.]+)%\s+([\d.]+)\s+([\d.]+)\)/);
return m
? { l: Number(m[1]) / 100, c: Number(m[2]), h: Number(m[3]) }
: null;
}
const L = 0.68;
const C = 0.18;
const GOLDEN_ANGLE = 137.508;

function oklchToRgb(l: number, c: number, h: number): RGB {
const hRad = (h * Math.PI) / 180;
Expand All @@ -47,14 +43,6 @@ const pickWorkspaceColor = (() => {
];
}

const skip = new Set(["inherit", "current", "transparent", "black", "white"]);
const palette: RGB[] = [];
for (const [name, val] of Object.entries(twColors)) {
if (skip.has(name) || typeof val !== "object" || !("500" in val)) continue;
const parsed = parseOklch((val as Record<string, string>)["500"]);
if (parsed) palette.push(oklchToRgb(parsed.l, parsed.c, parsed.h));
}

function hash(seed: string): number {
let h = 0;
for (let i = 0; i < seed.length; i++) {
Expand All @@ -64,8 +52,10 @@ const pickWorkspaceColor = (() => {
return Math.abs(h);
}

return (workspaceName: string): RGB =>
palette[hash(workspaceName) % palette.length] ?? FALLBACK;
return (workspaceName: string): RGB => {
const hue = (hash(workspaceName) * GOLDEN_ANGLE) % 360;
return oklchToRgb(L, C, hue);
};
})();

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip";
import { cn } from "@superset/ui/utils";
import { useMatchRoute, useNavigate } from "@tanstack/react-router";
import { HiOutlineClipboardDocumentList } from "react-icons/hi2";
import { LuFolderPlus, LuLayers, LuPlus } from "react-icons/lu";
import { GATED_FEATURES, usePaywall } from "renderer/components/Paywall";
import { useHotkeyDisplay } from "renderer/hotkeys";
import { OrganizationDropdown } from "renderer/routes/_authenticated/_dashboard/components/TopBar/components/OrganizationDropdown";
import { useTasksFilterStore } from "renderer/routes/_authenticated/_dashboard/tasks/stores/tasks-filter-state";
import { STROKE_WIDTH_THICK } from "renderer/screens/main/components/WorkspaceSidebar/constants";
import { useOpenNewWorkspaceModal } from "renderer/stores/new-workspace-modal";

Expand All @@ -18,12 +21,30 @@ export function DashboardSidebarHeader({
const shortcutText = useHotkeyDisplay("NEW_WORKSPACE").text;
const navigate = useNavigate();
const matchRoute = useMatchRoute();
const { gateFeature } = usePaywall();
const isWorkspacesListOpen = !!matchRoute({ to: "/v2-workspaces" });
const isTasksOpen = !!matchRoute({ to: "/tasks", fuzzy: true });

const {
tab: lastTab,
assignee: lastAssignee,
search: lastSearch,
} = useTasksFilterStore();

const handleWorkspacesClick = () => {
navigate({ to: "/v2-workspaces" });
};

const handleTasksClick = () => {
gateFeature(GATED_FEATURES.TASKS, () => {
const search: Record<string, string> = {};
if (lastTab !== "all") search.tab = lastTab;
if (lastAssignee) search.assignee = lastAssignee;
if (lastSearch) search.search = lastSearch;
navigate({ to: "/tasks", search });
});
};

if (isCollapsed) {
return (
<div className="flex flex-col items-center gap-2 border-b border-border py-2">
Expand All @@ -47,6 +68,24 @@ export function DashboardSidebarHeader({
<TooltipContent side="right">Workspaces</TooltipContent>
</Tooltip>

<Tooltip delayDuration={300}>
<TooltipTrigger asChild>
<button
type="button"
onClick={handleTasksClick}
className={cn(
"flex size-8 items-center justify-center rounded-md transition-colors",
isTasksOpen
? "bg-accent text-foreground"
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
)}
>
<HiOutlineClipboardDocumentList className="size-4" />
</button>
</TooltipTrigger>
<TooltipContent side="right">Tasks</TooltipContent>
</Tooltip>

<Tooltip delayDuration={300}>
<TooltipTrigger asChild>
<button
Expand Down Expand Up @@ -110,6 +149,20 @@ export function DashboardSidebarHeader({
<span className="flex-1 text-left">Workspaces</span>
</button>

<button
type="button"
onClick={handleTasksClick}
className={cn(
"flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm font-medium transition-colors",
isTasksOpen
? "bg-accent text-foreground"
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
)}
>
<HiOutlineClipboardDocumentList className="size-4 shrink-0" />
<span className="flex-1 text-left">Tasks</span>
</button>

<button
type="button"
onClick={() => openModal()}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { alert } from "@superset/ui/atoms/Alert";
import { toast } from "@superset/ui/sonner";
import { useNavigate } from "@tanstack/react-router";
import { useState } from "react";
import { apiTrpcClient } from "renderer/lib/api-trpc-client";
import { useDashboardSidebarState } from "renderer/routes/_authenticated/hooks/useDashboardSidebarState";
Expand All @@ -14,6 +15,7 @@ export function useDashboardSidebarProjectSectionActions({
project,
}: UseDashboardSidebarProjectSectionActionsOptions) {
const openModal = useOpenNewWorkspaceModal();
const navigate = useNavigate();
const {
createSection,
deleteSection,
Expand Down Expand Up @@ -57,7 +59,10 @@ export function useDashboardSidebarProjectSectionActions({
};

const handleOpenSettings = () => {
toast.info("Project settings are coming soon");
navigate({
to: "/settings/project/$projectId",
params: { projectId: project.id },
});
};

const confirmRemoveFromSidebar = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,14 @@ export function ProjectPickerPill({
<HiChevronUpDown className="size-3 shrink-0 text-muted-foreground" />
</PromptInputButton>
</PopoverTrigger>
<PopoverContent align="start" className="w-60 p-0">
<PopoverContent
align="start"
className="w-60 p-0"
onWheel={(event) => event.stopPropagation()}
>
Comment thread
MocA-Love marked this conversation as resolved.
<Command>
<CommandInput placeholder="Search projects..." />
<CommandList>
<CommandList className="max-h-[min(320px,var(--radix-popover-content-available-height))]">
<CommandEmpty>No projects found.</CommandEmpty>
<CommandGroup>
{recentProjects.map((project) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ export function WorkspaceHoverCardContent({
<div className="space-y-3">
<div className="space-y-1.5">
{hasCustomAlias && (
<div className="text-sm font-medium">{workspaceAlias}</div>
<div className="text-sm font-medium break-words line-clamp-2">
{workspaceAlias}
</div>
)}
{branchName && (
<div className="space-y-0.5">
Expand Down
1 change: 1 addition & 0 deletions apps/marketing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@paper-design/shaders-react": "^0.0.76",
"@react-three/drei": "^10.7.6",
"@react-three/fiber": "^9.4.0",
"@sentry/nextjs": "^10.36.0",
Expand Down
47 changes: 4 additions & 43 deletions apps/marketing/src/app/components/CTAButtons/HeaderCTA.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
"use client";

import { DOWNLOAD_URL_MAC_ARM64 } from "@superset/shared/constants";
import { Download } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { HiMiniClock } from "react-icons/hi2";
import { track } from "@/lib/analytics";
import { usePlatform } from "../../hooks/useOS";
import { DownloadButton } from "../DownloadButton";
import { WaitlistModal } from "../WaitlistModal";

Expand All @@ -16,16 +11,13 @@ interface HeaderCTAProps {
}

export function HeaderCTA({ isLoggedIn, dashboardUrl }: HeaderCTAProps) {
const { os, isMobile } = usePlatform();
const [isWaitlistOpen, setIsWaitlistOpen] = useState(false);
const portalRef = useRef<HTMLElement | null>(null);

useEffect(() => {
portalRef.current = document.body;
}, []);

const showDownload = !isMobile && (os === "macos" || os === "unknown");

const dashboardLink = isLoggedIn && (
<a
href={dashboardUrl}
Expand All @@ -45,44 +37,13 @@ export function HeaderCTA({ isLoggedIn, dashboardUrl }: HeaderCTAProps) {
)
: null;

if (isMobile) {
return (
<>
{dashboardLink}
<DownloadButton
size="sm"
onJoinWaitlist={() => setIsWaitlistOpen(true)}
/>
{waitlistModal}
</>
);
}

return (
<>
{dashboardLink}
{showDownload ? (
<a
href={DOWNLOAD_URL_MAC_ARM64}
className="px-4 py-2 text-sm font-normal bg-foreground text-background hover:bg-foreground/90 transition-colors flex items-center justify-center gap-2"
onClick={() => track("download_clicked")}
>
Download for macOS
<Download className="size-4" aria-hidden="true" />
</a>
) : (
<button
type="button"
className="px-4 py-2 text-sm font-normal bg-foreground text-background hover:bg-foreground/90 transition-colors flex items-center justify-center gap-2"
onClick={() => {
track("waitlist_clicked");
setIsWaitlistOpen(true);
}}
>
Join Waitlist
<HiMiniClock className="size-4" aria-hidden="true" />
</button>
)}
<DownloadButton
size="sm"
onJoinWaitlist={() => setIsWaitlistOpen(true)}
/>
{waitlistModal}
</>
);
Expand Down
7 changes: 2 additions & 5 deletions apps/marketing/src/app/components/CTASection/CTASection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,8 @@ export function CTASection() {
<>
<section className="relative py-32 px-8 lg:px-[30px]">
<div className="max-w-7xl mx-auto flex flex-col items-center text-center">
<h2
className="text-[32px] lg:text-[40px] font-normal tracking-normal leading-[1.3em] text-foreground mb-8"
style={{ fontFamily: "var(--font-ibm-plex-mono)" }}
>
Get Superset Today
<h2 className="text-3xl sm:text-4xl xl:text-5xl font-medium tracking-tight leading-[1.1] text-foreground mb-8">
Try Superset now.
</h2>
<div>
<DownloadButton onJoinWaitlist={() => setIsWaitlistOpen(true)} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function DownloadButton({
? "px-2 sm:px-4 py-2 text-sm"
: "px-3 sm:px-6 py-2 sm:py-3 text-sm sm:text-base";

const buttonClasses = `bg-foreground text-background ${sizeClasses} font-normal hover:bg-foreground/80 transition-colors flex items-center gap-2 ${className}`;
const buttonClasses = `bg-brand/10 text-[#ff8c3a] border border-brand/20 ${sizeClasses} font-normal hover:bg-brand/15 hover:border-brand/35 transition-colors flex items-center gap-2 ${className}`;

if (isMobile) {
const appleIcon = (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"use client";

import { MeshGradient } from "@superset/ui/mesh-gradient";
import type { ReactNode } from "react";
import { DitheredBackground } from "./components/DitheredBackground";

interface FeatureDemoProps {
children: ReactNode;
Expand All @@ -16,12 +14,12 @@ export function FeatureDemo({
}: FeatureDemoProps) {
return (
<div
className={`relative w-full min-h-[300px] lg:aspect-4/3 rounded overflow-hidden ${className}`}
className={`relative w-full min-h-[300px] lg:aspect-4/3 overflow-hidden ${className}`}
>
{/* Background gradient */}
<MeshGradient
<DitheredBackground
colors={colors}
className="absolute inset-0 w-full h-full rounded"
className="absolute inset-0 w-full h-full"
/>

{/* Content overlay */}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"use client";

import { lazy, Suspense } from "react";

const Dithering = lazy(() =>
import("@paper-design/shaders-react").then((mod) => ({
default: mod.Dithering,
})),
);

interface DitheredBackgroundProps {
colors: readonly [string, string, string, string];
className?: string;
}

export function DitheredBackground({
colors,
className = "",
}: DitheredBackgroundProps) {
return (
<div
className={`${className} pointer-events-none opacity-30 mix-blend-screen`}
>
<Suspense fallback={null}>
<Dithering
colorBack="#00000000"
colorFront={colors[0]}
shape="warp"
type="4x4"
speed={0.15}
className="size-full"
minPixelRatio={1}
/>
</Suspense>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DitheredBackground } from "./DitheredBackground";
Loading
Loading