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
96 changes: 14 additions & 82 deletions apps/dashboard/src/components/app-square.tsx
Original file line number Diff line number Diff line change
@@ -1,100 +1,32 @@
import { useAdminApp } from "@/app/(main)/(protected)/projects/[projectId]/use-admin-app";
import { ALL_APPS_FRONTEND, AppFrontend, getAppPath } from "@/lib/apps-frontend";
import { ALL_APPS, AppId } from "@stackframe/stack-shared/dist/apps/apps-config";
import { typedIncludes } from "@stackframe/stack-shared/dist/utils/arrays";
import { AppIcon as SharedAppIcon, appSquarePaddingExpression, appSquareWidthExpression } from "@stackframe/stack-shared/dist/apps/apps-ui";
import { runAsynchronouslyWithAlert } from "@stackframe/stack-shared/dist/utils/promises";
import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger, cn } from "@stackframe/stack-ui";
import { Link } from "./link";

export const appSquareWidthExpression = "max(min(11vw,180px),80px)";
export const appSquarePaddingExpression = "max(min(1vw,1.5rem),0.25rem)";
export { appSquarePaddingExpression, appSquareWidthExpression };

export function AppIcon({ appId, className, disabled, style }: {
appId: AppId,
className?: string,
disabled?: boolean,
style?: React.CSSProperties,
}) {
const svgGradients = (gradients: Record<string, string[]>) => {
return (
<svg width="0" height="0">
{Object.entries(gradients).map(([id, gradient]) => {
return (
<linearGradient key={id} id={id} x1="100%" y1="100%" x2="0%" y2="0%">
{gradient.map((color, index) => {
return <stop key={index} stopColor={color} offset={`${index * 100 / (gradient.length - 1)}%`} />;
})}
</linearGradient>
);
})}
</svg>
);

};

const app = ALL_APPS[appId];
const appFrontend: AppFrontend = ALL_APPS_FRONTEND[appId];
return <div style={style} className={cn(
"relative w-24 h-24 rounded-[24.154%] overflow-hidden select-none",
!disabled && "bg-[linear-gradient(45deg,#dde,#fff)] dark:bg-[linear-gradient(45deg,#222,#666)]",
disabled && 'border-gray-400/70 border-dashed border-4',
className,
)}>
<div className={cn(
"w-full h-full isolate relative",
)}>
{appFrontend.logo ? (
<div
className="absolute inset-[20%] w-[60%] h-[60%] rounded-[24.154%] overflow-hidden flex items-center justify-center border"
style={{
opacity: disabled ? 0.6 : 1,
}}
>
<appFrontend.logo />
</div>
) : (
<>
<svg width="0" height="0">
{svgGradients({
"app-icon-gradient-light": ["#c0f", "#66f", "#4af"],
"app-icon-gradient-dark": ["#3ec", "#9af", "#a5f"],
"app-icon-gradient-light-expert": ["#f0c", "#f66", "#fa4"],
"app-icon-gradient-dark-expert": ["#f0c", "#f66", "#fa4"],
"app-icon-gradient-light-integration": ["#E5AB00", "#FFBA00", "#F8DF80"],
"app-icon-gradient-dark-integration": ["#E5AB00", "#FFBA00", "#F8DF80"],
})}
</svg>
<appFrontend.icon
opacity={disabled ? 0.75 : 1}
className={cn(
"inset-[20%] w-[60%] h-[60%] bg-clip-text text-transparent text-white absolute",
(typedIncludes(app.tags, "expert")
? "stroke-[url(#app-icon-gradient-light-expert)] dark:stroke-[url(#app-icon-gradient-dark-expert)]"
: typedIncludes(app.tags, "integration")
? "stroke-[url(#app-icon-gradient-light-integration)] dark:stroke-[url(#app-icon-gradient-dark-integration)]"
: "stroke-[url(#app-icon-gradient-light)] dark:stroke-[url(#app-icon-gradient-dark)]"
)
)}
/>
</>
)}
</div>
<div className="absolute top-0 left-[-100%] right-0 flex flex-col gap-1 [transform:_rotate(-45deg)_translateY(24px)] [transform-origin:top_center]">
{app.stage !== "stable" && (
<div className={cn(
"h-4 uppercase text-xs font-bold font-mono tracking-widest text-center",
disabled
? "bg-gray-400/80 text-white"
: app.stage === "alpha"
? "bg-red-500 text-white"
: "bg-yellow-600 text-white"
)}
>
{app.stage}
</div>
)}
</div>
</div>;

return (
<SharedAppIcon
appId={appId}
IconComponent={appFrontend.icon}
LogoComponent={appFrontend.logo}
className={className}
disabled={disabled}
style={style}
cn={cn}
/>
);
}

export function AppSquare({ appId }: {
Expand Down
Loading