mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2026-09-02 21:03:34 +03:00
Portal Editor admin: replace glyph icons with SVGs (#6999)
# Description of Changes Swaps the emoji and box glyphs in the editor deployment, pairing and storage panels for tinted icons consistent with the rest of the portal. Part of a portal (processor) UI-consistency pass, split into small focused PRs. --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [ ] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### Translations (if applicable) - [ ] I ran [`scripts/counter_translation.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/docs/counter_translation.md) ### UI Changes (if applicable) - [x] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [ ] I have run `task check` to verify linters, typechecks, and tests pass - [x] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/DeveloperGuide.md#7-testing) for more details.
This commit is contained in:
@@ -119,14 +119,13 @@ export interface EditorDeploymentResponse {
|
||||
/* ──────────────────────────────────────────────────────────────────────── */
|
||||
|
||||
export interface TargetMeta {
|
||||
icon: string;
|
||||
tone: "neutral" | "blue" | "purple";
|
||||
}
|
||||
|
||||
export const TARGET_META: Record<TargetKind, TargetMeta> = {
|
||||
cloud: { icon: "☁", tone: "blue" },
|
||||
docker: { icon: "▣", tone: "neutral" },
|
||||
kubernetes: { icon: "⎈", tone: "purple" },
|
||||
cloud: { tone: "blue" },
|
||||
docker: { tone: "neutral" },
|
||||
kubernetes: { tone: "purple" },
|
||||
};
|
||||
|
||||
export const INSTANCE_STATUS_TONE: Record<
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CloudQueueRounded from "@mui/icons-material/CloudQueueRounded";
|
||||
import HubRounded from "@mui/icons-material/HubRounded";
|
||||
import Inventory2Rounded from "@mui/icons-material/Inventory2Rounded";
|
||||
import { Button, Card, CodeBlock, StatusBadge } from "@app/ui";
|
||||
import { TARGET_META, type DeploymentTarget } from "@portal/api/editorDeploy";
|
||||
import {
|
||||
TARGET_META,
|
||||
type DeploymentTarget,
|
||||
type TargetKind,
|
||||
} from "@portal/api/editorDeploy";
|
||||
import { useTier } from "@portal/contexts/TierContext";
|
||||
|
||||
const TARGET_ICON: Record<TargetKind, typeof CloudQueueRounded> = {
|
||||
cloud: CloudQueueRounded,
|
||||
docker: Inventory2Rounded,
|
||||
kubernetes: HubRounded,
|
||||
};
|
||||
|
||||
const STATE_BADGE_TONE: Record<
|
||||
DeploymentTarget["state"],
|
||||
"success" | "info" | "neutral"
|
||||
@@ -36,6 +49,7 @@ export function DeploymentTargets({ targets, onUpgrade }: Props) {
|
||||
<div className="portal-editor__targets">
|
||||
{targets.map((target) => {
|
||||
const meta = TARGET_META[target.kind];
|
||||
const Icon = TARGET_ICON[target.kind];
|
||||
const locked = target.state === "locked";
|
||||
return (
|
||||
<Card
|
||||
@@ -48,7 +62,7 @@ export function DeploymentTargets({ targets, onUpgrade }: Props) {
|
||||
className={`portal-editor__target-icon portal-editor__target-icon--${meta.tone}`}
|
||||
aria-hidden
|
||||
>
|
||||
{meta.icon}
|
||||
<Icon style={{ fontSize: "1.2rem" }} />
|
||||
</span>
|
||||
<div className="portal-editor__target-titles">
|
||||
<h3 className="portal-editor__target-name">{target.label}</h3>
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CastRounded from "@mui/icons-material/CastRounded";
|
||||
import TerminalRounded from "@mui/icons-material/TerminalRounded";
|
||||
import VpnKeyRounded from "@mui/icons-material/VpnKeyRounded";
|
||||
import { Button, Card, Chip, CodeBlock } from "@app/ui";
|
||||
import type { PairingMethod, PairingOption } from "@portal/api/editorDeploy";
|
||||
|
||||
const METHOD_ICON: Record<PairingMethod, string> = {
|
||||
token: "🔑",
|
||||
shortcode: "📺",
|
||||
iac: "🧱",
|
||||
const METHOD_ICON: Record<PairingMethod, typeof VpnKeyRounded> = {
|
||||
token: VpnKeyRounded,
|
||||
shortcode: CastRounded,
|
||||
iac: TerminalRounded,
|
||||
};
|
||||
|
||||
const METHOD_TONE: Record<PairingMethod, "blue" | "purple" | "green"> = {
|
||||
token: "blue",
|
||||
shortcode: "purple",
|
||||
iac: "green",
|
||||
};
|
||||
|
||||
interface Props {
|
||||
@@ -36,6 +45,7 @@ export function PairingPanel({ pairings, onUpgrade }: Props) {
|
||||
<div className="portal-editor__pairings">
|
||||
{pairings.map((p) => {
|
||||
const isCode = p.method === "iac";
|
||||
const Icon = METHOD_ICON[p.method];
|
||||
return (
|
||||
<Card
|
||||
key={p.method}
|
||||
@@ -43,8 +53,11 @@ export function PairingPanel({ pairings, onUpgrade }: Props) {
|
||||
className="portal-editor__pairing"
|
||||
>
|
||||
<div className="portal-editor__pairing-head">
|
||||
<span className="portal-editor__pairing-icon" aria-hidden>
|
||||
{METHOD_ICON[p.method]}
|
||||
<span
|
||||
className={`portal-editor__pairing-icon portal-editor__pairing-icon--${METHOD_TONE[p.method]}`}
|
||||
aria-hidden
|
||||
>
|
||||
<Icon style={{ fontSize: "1.2rem" }} />
|
||||
</span>
|
||||
<div className="portal-editor__pairing-titles">
|
||||
<h3 className="portal-editor__pairing-name">{p.label}</h3>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { useState } from "react";
|
||||
import { useState, type ComponentType, type CSSProperties } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ArrowForwardRounded from "@mui/icons-material/ArrowForwardRounded";
|
||||
import CloudRounded from "@mui/icons-material/CloudRounded";
|
||||
import StorageRounded from "@mui/icons-material/StorageRounded";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
@@ -20,13 +23,13 @@ import {
|
||||
import { SectionHeader } from "@portal/components/infrastructure/SectionHeader";
|
||||
import { pct } from "@portal/components/infrastructure/infraFormat";
|
||||
|
||||
const PROVIDER_GLYPH: Record<
|
||||
const PROVIDER_ICON: Record<
|
||||
StorageConfig["providers"][number]["kind"],
|
||||
string
|
||||
ComponentType<{ style?: CSSProperties }>
|
||||
> = {
|
||||
stirling: "◆",
|
||||
s3: "▣",
|
||||
azure: "▤",
|
||||
stirling: StorageRounded,
|
||||
s3: CloudRounded,
|
||||
azure: CloudRounded,
|
||||
};
|
||||
|
||||
/** Storage fills past this fraction of quota are surfaced in red. */
|
||||
@@ -143,35 +146,38 @@ export function StorageTab() {
|
||||
sub={t("portal.infrastructure.storage.providers.subheading")}
|
||||
/>
|
||||
<ul className="portal-infra__providers">
|
||||
{data.providers.map((p) => (
|
||||
<li key={p.id} className="portal-infra__provider">
|
||||
<span className="portal-infra__provider-glyph" aria-hidden>
|
||||
{PROVIDER_GLYPH[p.kind]}
|
||||
</span>
|
||||
<span className="portal-infra__provider-text">
|
||||
<span className="portal-infra__cell-strong">{p.name}</span>
|
||||
<span className="portal-infra__muted">{p.detail}</span>
|
||||
</span>
|
||||
{p.connected ? (
|
||||
<span className="portal-infra__provider-meta">
|
||||
<span className="portal-infra__mono">
|
||||
{t("portal.infrastructure.storage.gbValue", {
|
||||
value: p.usedGb,
|
||||
})}
|
||||
</span>
|
||||
<StatusBadge tone="success" size="sm">
|
||||
{t("portal.infrastructure.storage.providers.connected")}
|
||||
</StatusBadge>
|
||||
{data.providers.map((p) => {
|
||||
const ProviderIcon = PROVIDER_ICON[p.kind];
|
||||
return (
|
||||
<li key={p.id} className="portal-infra__provider">
|
||||
<span className="portal-infra__provider-glyph" aria-hidden>
|
||||
<ProviderIcon style={{ fontSize: "1.2rem" }} />
|
||||
</span>
|
||||
) : (
|
||||
// TODO(backend): launch the provider OAuth/credential flow,
|
||||
// then POST /v1/infrastructure/storage/providers/{id}/connect
|
||||
<Button variant="secondary" size="sm">
|
||||
{t("portal.infrastructure.storage.providers.connect")}
|
||||
</Button>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
<span className="portal-infra__provider-text">
|
||||
<span className="portal-infra__cell-strong">{p.name}</span>
|
||||
<span className="portal-infra__muted">{p.detail}</span>
|
||||
</span>
|
||||
{p.connected ? (
|
||||
<span className="portal-infra__provider-meta">
|
||||
<span className="portal-infra__mono">
|
||||
{t("portal.infrastructure.storage.gbValue", {
|
||||
value: p.usedGb,
|
||||
})}
|
||||
</span>
|
||||
<StatusBadge tone="success" size="sm">
|
||||
{t("portal.infrastructure.storage.providers.connected")}
|
||||
</StatusBadge>
|
||||
</span>
|
||||
) : (
|
||||
// TODO(backend): launch the provider OAuth/credential flow,
|
||||
// then POST /v1/infrastructure/storage/providers/{id}/connect
|
||||
<Button variant="secondary" size="sm">
|
||||
{t("portal.infrastructure.storage.providers.connect")}
|
||||
</Button>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
@@ -205,7 +211,7 @@ export function StorageTab() {
|
||||
</span>
|
||||
</div>
|
||||
<span className="portal-infra__lifecycle-arrow" aria-hidden>
|
||||
→
|
||||
<ArrowForwardRounded style={{ fontSize: "1.2rem" }} />
|
||||
</span>
|
||||
<div className="portal-infra__lifecycle-stage">
|
||||
<span className="portal-infra__lifecycle-dot" />
|
||||
@@ -217,7 +223,7 @@ export function StorageTab() {
|
||||
</span>
|
||||
</div>
|
||||
<span className="portal-infra__lifecycle-arrow" aria-hidden>
|
||||
→
|
||||
<ArrowForwardRounded style={{ fontSize: "1.2rem" }} />
|
||||
</span>
|
||||
<div className="portal-infra__lifecycle-stage">
|
||||
<span className="portal-infra__lifecycle-dot" />
|
||||
|
||||
@@ -181,8 +181,26 @@
|
||||
}
|
||||
|
||||
.portal-editor__pairing-icon {
|
||||
font-size: 1.125rem;
|
||||
line-height: 1.4;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
flex-shrink: 0;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.portal-editor__pairing-icon--blue {
|
||||
background: var(--color-blue-light);
|
||||
color: var(--color-blue);
|
||||
}
|
||||
.portal-editor__pairing-icon--purple {
|
||||
background: var(--color-purple-light);
|
||||
color: var(--color-purple);
|
||||
}
|
||||
.portal-editor__pairing-icon--green {
|
||||
background: var(--color-green-light);
|
||||
color: var(--color-green);
|
||||
}
|
||||
|
||||
.portal-editor__pairing-titles {
|
||||
|
||||
Reference in New Issue
Block a user