Browse Source

style(sub): match the subscription page to the panel theme

The sub page ran its own violet/cyan palette, an animated aurora
backdrop, a grid overlay and a glass card, so it looked unrelated to
every other panel page. It now uses the panel shell background and card
colors for light, dark and ultra-dark, the panel's antd theme (blue
primary) unmodified, and antd tokens for dividers, tiles and rows.
MHSanaei 17 hours ago
parent
commit
fd6c5925ce
2 changed files with 41 additions and 273 deletions
  1. 40 229
      frontend/src/pages/sub/SubPage.css
  2. 1 44
      frontend/src/pages/sub/SubPage.tsx

+ 40 - 229
frontend/src/pages/sub/SubPage.css

@@ -1,78 +1,18 @@
 .subscription-page {
-  /* --sub-grad-* paints graphics, --sub-ink-* paints text: the cyan end darkens
-     so text clears 4.5:1. --sub-accent is ACCENT.primary in SubPage.tsx. */
-  --sub-grad-from: #8b5cf6;
-  --sub-grad-to: #06b6d4;
-  --sub-ink-from: #6d28d9;
-  --sub-ink-to: #0e7490;
-  --sub-accent: #7c3aed;
-  --bg-page: linear-gradient(135deg, #e9e4ff 0%, #ddeefc 52%, #e2f7f2 100%);
-  --sub-card-bg: rgba(255, 255, 255, 0.72);
-  --sub-card-border: rgba(255, 255, 255, 0.7);
-  --sub-card-shadow: 0 1px 3px rgba(15, 23, 42, 0.05), 0 20px 56px rgba(124, 58, 237, 0.16);
-  --sub-card-sheen: linear-gradient(
-    135deg,
-    rgba(255, 255, 255, 0.75),
-    rgba(255, 255, 255, 0) 42%,
-    rgba(124, 58, 237, 0.22) 88%
-  );
-  --sub-blob-1: rgba(139, 92, 246, 0.55);
-  --sub-blob-2: rgba(6, 182, 212, 0.45);
-  --sub-grid: rgba(124, 58, 237, 0.06);
-  --sub-hairline: linear-gradient(90deg, rgba(139, 92, 246, 0.4), rgba(6, 182, 212, 0.4));
-  --sub-tile-bg: rgba(124, 58, 237, 0.05);
-  --sub-tile-border: rgba(124, 58, 237, 0.12);
-  --sub-row-bg: rgba(124, 58, 237, 0.045);
-  --sub-row-border: rgba(124, 58, 237, 0.11);
-  --sub-row-bg-hover: rgba(124, 58, 237, 0.09);
-  --sub-row-border-hover: rgba(124, 58, 237, 0.3);
-  --sub-row-glow: rgba(124, 58, 237, 0.28);
-  --sub-glass-bg: rgba(255, 255, 255, 0.6);
-
-  position: relative;
+  --bg-page: #e6e8ec;
+  --bg-card: #ffffff;
   min-height: 100vh;
   background: var(--bg-page);
 }
 
 .subscription-page.is-dark {
-  --sub-grad-from: #a78bfa;
-  --sub-grad-to: #22d3ee;
-  --sub-ink-from: #c4b5fd;
-  --sub-ink-to: #67e8f9;
-  --sub-accent: #a78bfa;
-  --bg-page: radial-gradient(ellipse 120% 90% at 18% -10%, #1f1740 0%, #16171d 52%, #101116 100%);
-  --sub-card-bg: rgba(35, 37, 43, 0.62);
-  --sub-card-border: rgba(255, 255, 255, 0.08);
-  --sub-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 24px 64px rgba(109, 40, 217, 0.24);
-  --sub-card-sheen: linear-gradient(
-    135deg,
-    rgba(255, 255, 255, 0.16),
-    rgba(255, 255, 255, 0) 42%,
-    rgba(167, 139, 250, 0.4) 88%
-  );
-  --sub-blob-1: rgba(139, 92, 246, 0.4);
-  --sub-blob-2: rgba(34, 211, 238, 0.26);
-  --sub-grid: rgba(255, 255, 255, 0.035);
-  --sub-hairline: linear-gradient(90deg, rgba(167, 139, 250, 0.45), rgba(34, 211, 238, 0.45));
-  --sub-tile-bg: rgba(167, 139, 250, 0.07);
-  --sub-tile-border: rgba(167, 139, 250, 0.14);
-  --sub-row-bg: rgba(167, 139, 250, 0.06);
-  --sub-row-border: rgba(167, 139, 250, 0.12);
-  --sub-row-bg-hover: rgba(167, 139, 250, 0.12);
-  --sub-row-border-hover: rgba(167, 139, 250, 0.35);
-  --sub-row-glow: rgba(139, 92, 246, 0.45);
-  --sub-glass-bg: rgba(255, 255, 255, 0.06);
+  --bg-page: #1a1b1f;
+  --bg-card: #23252b;
 }
 
 .subscription-page.is-dark.is-ultra {
-  --bg-page: radial-gradient(ellipse 120% 90% at 18% -10%, #120a2b 0%, #050509 55%, #000 100%);
-  --sub-card-bg: rgba(16, 16, 19, 0.68);
-  --sub-card-border: rgba(255, 255, 255, 0.055);
-  --sub-card-shadow: 0 1px 3px rgba(0, 0, 0, 0.6), 0 24px 64px rgba(88, 28, 135, 0.3);
-  --sub-blob-1: rgba(139, 92, 246, 0.22);
-  --sub-blob-2: rgba(34, 211, 238, 0.14);
-  --sub-grid: rgba(255, 255, 255, 0.022);
-  --sub-glass-bg: rgba(255, 255, 255, 0.04);
+  --bg-page: #000;
+  --bg-card: #101013;
 }
 
 .subscription-page .ant-layout,
@@ -80,72 +20,6 @@
   background: transparent;
 }
 
-/* aurora backdrop */
-.sub-aurora {
-  position: fixed;
-  inset: 0;
-  z-index: 0;
-  overflow: hidden;
-  pointer-events: none;
-}
-
-.sub-aurora-grid {
-  position: absolute;
-  inset: 0;
-  background-image:
-    linear-gradient(var(--sub-grid) 1px, transparent 1px),
-    linear-gradient(90deg, var(--sub-grid) 1px, transparent 1px);
-  background-size: 48px 48px;
-  background-position: center;
-  -webkit-mask-image: radial-gradient(ellipse at 50% 30%, black 20%, transparent 72%);
-  mask-image: radial-gradient(ellipse at 50% 30%, black 20%, transparent 72%);
-}
-
-.sub-aurora::before,
-.sub-aurora::after {
-  content: '';
-  position: absolute;
-  width: 70vmax;
-  height: 70vmax;
-  max-width: 820px;
-  max-height: 820px;
-  border-radius: 50%;
-  filter: blur(80px);
-  will-change: transform;
-}
-
-.sub-aurora::before {
-  top: -22vmax;
-  left: -16vmax;
-  background: radial-gradient(circle, var(--sub-blob-1) 0%, transparent 65%);
-  animation: sub-blob-a 28s ease-in-out infinite alternate;
-}
-
-.sub-aurora::after {
-  bottom: -24vmax;
-  right: -18vmax;
-  background: radial-gradient(circle, var(--sub-blob-2) 0%, transparent 65%);
-  animation: sub-blob-b 34s ease-in-out infinite alternate;
-}
-
-@keyframes sub-blob-a {
-  0% {
-    transform: translate(0, 0) scale(1);
-  }
-  100% {
-    transform: translate(16vw, 14vh) scale(1.18);
-  }
-}
-
-@keyframes sub-blob-b {
-  0% {
-    transform: translate(0, 0) scale(1);
-  }
-  100% {
-    transform: translate(-14vw, -12vh) scale(1.15);
-  }
-}
-
 .sub-content {
   position: relative;
   z-index: 1;
@@ -158,35 +32,24 @@
 }
 
 .subscription-page .sub-card {
-  position: relative;
-  border-radius: 20px;
-  border: 1px solid var(--sub-card-border);
-  background: var(--sub-card-bg);
-  box-shadow: var(--sub-card-shadow);
-  -webkit-backdrop-filter: blur(24px) saturate(180%);
-  backdrop-filter: blur(24px) saturate(180%);
+  border-radius: 12px;
+  background: var(--bg-card);
+  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
 }
 
-/* Hairline gradient rim: a padded sheen layer with its own middle masked out. */
-.subscription-page .sub-card::before {
-  content: '';
-  position: absolute;
-  inset: 0;
-  z-index: 0;
-  border-radius: inherit;
-  padding: 1px;
-  background: var(--sub-card-sheen);
-  -webkit-mask:
-    linear-gradient(#000 0 0) content-box,
-    linear-gradient(#000 0 0);
-  -webkit-mask-composite: xor;
-  mask-composite: exclude;
-  pointer-events: none;
+.subscription-page.is-dark .sub-card {
+  box-shadow:
+    0 1px 2px rgba(0, 0, 0, 0.4),
+    inset 0 1px 0 rgba(255, 255, 255, 0.03);
+}
+
+.subscription-page.is-dark.is-ultra .sub-card {
+  box-shadow:
+    0 1px 2px rgba(0, 0, 0, 0.6),
+    inset 0 1px 0 rgba(255, 255, 255, 0.025);
 }
 
 .sub-card > .ant-card-body {
-  position: relative;
-  z-index: 1;
   padding: 28px;
 }
 
@@ -200,7 +63,7 @@
   font-size: 13px;
 }
 
-/* Gradient hairline shared by the header, the stats grid and the footer. */
+/* Divider shared by the header, the stats grid and the footer. */
 .sub-header::after,
 .sub-stats::before,
 .sub-footer::before {
@@ -208,8 +71,7 @@
   position: absolute;
   inset-inline: 0;
   height: 1px;
-  background: var(--sub-hairline);
-  opacity: 0.7;
+  background: var(--ant-color-border-secondary);
 }
 
 /* header */
@@ -242,8 +104,7 @@
   align-items: center;
   justify-content: center;
   border-radius: 13px;
-  background: linear-gradient(135deg, var(--sub-grad-from), var(--sub-grad-to));
-  box-shadow: 0 8px 20px -8px var(--sub-row-glow);
+  background: var(--ant-color-primary);
   color: #fff;
   font-size: 20px;
   font-weight: 600;
@@ -290,20 +151,6 @@
   font-size: 18px;
 }
 
-.subscription-page .toolbar-btn {
-  border-color: var(--sub-row-border);
-  background: var(--sub-glass-bg);
-  color: var(--sub-accent);
-  -webkit-backdrop-filter: blur(8px);
-  backdrop-filter: blur(8px);
-}
-
-.subscription-page .toolbar-btn:hover {
-  border-color: var(--sub-row-border-hover);
-  background: var(--sub-row-bg-hover);
-  color: var(--sub-accent);
-}
-
 .sub-announce {
   margin-bottom: 24px;
 }
@@ -352,11 +199,7 @@
   font-weight: 700;
   letter-spacing: -0.02em;
   font-variant-numeric: tabular-nums;
-  background: linear-gradient(135deg, var(--sub-ink-from), var(--sub-ink-to));
-  -webkit-background-clip: text;
-  background-clip: text;
-  -webkit-text-fill-color: transparent;
-  color: var(--sub-ink-from);
+  color: var(--ant-color-text);
 }
 
 .sub-big-unit {
@@ -365,8 +208,6 @@
 }
 
 .sub-hero.is-alert .sub-big-num {
-  background: none;
-  -webkit-text-fill-color: var(--ant-color-error);
   color: var(--ant-color-error);
 }
 
@@ -386,8 +227,8 @@
 .sub-stat {
   padding: 10px 12px;
   border-radius: 12px;
-  border: 1px solid var(--sub-tile-border);
-  background: var(--sub-tile-bg);
+  border: 1px solid var(--ant-color-border-secondary);
+  background: var(--ant-color-fill-quaternary);
 }
 
 .sub-stat-value {
@@ -408,20 +249,14 @@
   margin-top: 28px;
 }
 
-.sub-tabs.ant-tabs .ant-tabs-ink-bar {
-  height: 3px;
-  border-radius: 2px;
-  background: linear-gradient(90deg, var(--sub-grad-from), var(--sub-grad-to));
-}
-
 .sub-tab-count {
   margin-inline-start: 6px;
   padding: 0 7px;
   border-radius: 10px;
   font-size: 12px;
-  background: var(--sub-tile-bg);
-  border: 1px solid var(--sub-tile-border);
-  color: var(--sub-accent);
+  background: var(--ant-color-fill-quaternary);
+  border: 1px solid var(--ant-color-border-secondary);
+  color: var(--ant-color-primary);
 }
 
 .sub-rows {
@@ -437,20 +272,16 @@
   min-width: 0;
   padding: 10px 12px;
   border-radius: 12px;
-  background: var(--sub-row-bg);
-  border: 1px solid var(--sub-row-border);
+  background: var(--ant-color-fill-quaternary);
+  border: 1px solid var(--ant-color-border-secondary);
   transition:
     background 160ms ease,
-    border-color 160ms ease,
-    box-shadow 160ms ease,
-    transform 160ms ease;
+    border-color 160ms ease;
 }
 
 .sub-row:hover {
-  background: var(--sub-row-bg-hover);
-  border-color: var(--sub-row-border-hover);
-  box-shadow: 0 8px 20px -14px var(--sub-row-glow);
-  transform: translateY(-1px);
+  background: var(--ant-color-primary-bg);
+  border-color: var(--ant-color-primary-border);
 }
 
 .sub-row-tag {
@@ -481,7 +312,7 @@
 }
 
 a.sub-row-title:hover {
-  color: var(--sub-accent);
+  color: var(--ant-color-primary);
 }
 
 .sub-row-url {
@@ -554,8 +385,8 @@ a.sub-row-title:hover {
   margin-top: 8px;
   padding: 16px;
   border-radius: 14px;
-  border: 1px dashed var(--sub-row-border-hover);
-  background: var(--sub-row-bg);
+  border: 1px dashed var(--ant-color-primary-border);
+  background: var(--ant-color-fill-quaternary);
 }
 
 .sub-qr-code {
@@ -596,9 +427,9 @@ a.sub-row-title:hover {
   align-items: center;
   justify-content: center;
   border-radius: 9px;
-  border: 1px solid var(--sub-tile-border);
-  background: linear-gradient(135deg, var(--sub-row-bg-hover), var(--sub-tile-bg));
-  color: var(--sub-accent);
+  border: 1px solid var(--ant-color-border-secondary);
+  background: var(--ant-color-primary-bg);
+  color: var(--ant-color-primary);
   font-weight: 600;
 }
 
@@ -620,7 +451,7 @@ a.sub-row-title:hover {
   flex-shrink: 0;
   border-radius: 9px;
   object-fit: cover;
-  box-shadow: 0 0 0 1px var(--sub-tile-border);
+  box-shadow: 0 0 0 1px var(--ant-color-border-secondary);
 }
 
 .sub-app-name {
@@ -664,17 +495,6 @@ a.sub-row-title:hover {
   gap: 6px;
 }
 
-@media (prefers-reduced-motion: reduce) {
-  .sub-aurora::before,
-  .sub-aurora::after {
-    animation: none;
-  }
-
-  .sub-row:hover {
-    transform: none;
-  }
-}
-
 @media (max-width: 576px) {
   .sub-content {
     padding: 16px 8px;
@@ -684,15 +504,6 @@ a.sub-row-title:hover {
     padding: 16px;
   }
 
-  /* One static blob: two animated 70vmax blurs drop frames on low-end phones. */
-  .sub-aurora::before {
-    animation: none;
-  }
-
-  .sub-aurora::after {
-    display: none;
-  }
-
   .sub-hero {
     grid-template-columns: minmax(0, 1fr);
     gap: 20px;

+ 1 - 44
frontend/src/pages/sub/SubPage.tsx

@@ -60,23 +60,6 @@ const apps = buildSubApps({ subUrl, sId, subTitle });
 const initialPlatform = detectPlatform(navigator.userAgent);
 const RTL_LANGUAGES = new Set(['fa-IR', 'ar-EG']);
 
-// The sub page runs its own violet accent, so every antd control on it picks the
-// hue up instead of the panel blue useTheme pins. Mirrored in SubPage.css.
-const ACCENT = {
-  light: {
-    primary: '#7c3aed',
-    hover: '#8b5cf6',
-    active: '#6d28d9',
-    rail: 'rgba(124, 58, 237, 0.16)',
-  },
-  dark: {
-    primary: '#a78bfa',
-    hover: '#c4b5fd',
-    active: '#8b5cf6',
-    rail: 'rgba(167, 139, 250, 0.18)',
-  },
-};
-
 export default function SubPage() {
   const { t } = useTranslation();
   const { isDark, isUltra, antdThemeConfig } = useTheme();
@@ -150,36 +133,10 @@ export default function SubPage() {
     .filter(Boolean)
     .join(' ');
 
-  const themeConfig = useMemo(() => {
-    const accent = isDark ? ACCENT.dark : ACCENT.light;
-    const primary = {
-      colorPrimary: accent.primary,
-      colorPrimaryHover: accent.hover,
-      colorPrimaryActive: accent.active,
-    };
-    return {
-      ...antdThemeConfig,
-      token: {
-        ...antdThemeConfig.token,
-        ...primary,
-        colorLink: accent.primary,
-        colorInfo: accent.primary,
-      },
-      components: {
-        ...antdThemeConfig.components,
-        Button: { ...antdThemeConfig.components?.Button, ...primary },
-        Progress: { ...antdThemeConfig.components?.Progress, remainingColor: accent.rail },
-      },
-    };
-  }, [antdThemeConfig, isDark]);
-
   return (
-    <ConfigProvider theme={themeConfig} direction={direction}>
+    <ConfigProvider theme={antdThemeConfig} direction={direction}>
       {messageContextHolder}
       <Layout className={pageClass} dir={direction}>
-        <div className="sub-aurora" aria-hidden="true">
-          <span className="sub-aurora-grid" />
-        </div>
         <Layout.Content className="sub-content">
           <Card className="sub-card">
             <SubHeader