refactor(frontend): move stylings out of logic into centralized file

This commit is contained in:
2026-03-03 20:28:23 +00:00
parent e2ac4495fd
commit bd0e1a9050
21 changed files with 652 additions and 320 deletions

View File

@@ -0,0 +1,42 @@
import { palette } from "./palette";
import type { StyleMap } from "./types";
export const appLayoutStyles: StyleMap = {
appHeaderWrap: {
padding: "16px 24px 0",
},
appHeaderBrandRow: {
display: "flex",
alignItems: "center",
gap: 10,
flexWrap: "wrap",
},
appTitle: {
margin: 0,
color: palette.textPrimary,
fontSize: 18,
fontWeight: 600,
},
authStatusBadge: {
padding: "3px 8px",
borderRadius: 6,
fontSize: 12,
fontWeight: 600,
fontFamily: '"IBM Plex Sans", "Noto Sans", "Liberation Sans", "Segoe UI", sans-serif',
},
authStatusSignedIn: {
border: `1px solid ${palette.statusPositiveBorder}`,
background: palette.statusPositiveBg,
color: palette.statusPositiveText,
},
authStatusSignedOut: {
border: `1px solid ${palette.statusNegativeBorder}`,
background: palette.statusNegativeBg,
color: palette.statusNegativeText,
},
};

View File

@@ -0,0 +1,92 @@
import { palette } from "./palette";
import type { StyleMap } from "./types";
export const authStyles: StyleMap = {
containerAuth: {
maxWidth: 560,
margin: "0 auto",
padding: "48px 24px",
},
headingXl: {
margin: 0,
color: palette.textPrimary,
fontSize: 28,
fontWeight: 600,
lineHeight: 1.1,
},
headingBlock: {
marginBottom: 22,
textAlign: "center",
},
mutedText: {
margin: "8px 0 0",
color: palette.textSecondary,
fontSize: 14,
},
authCard: {
padding: 28,
},
authForm: {
display: "grid",
gap: 12,
maxWidth: 380,
margin: "0 auto",
},
inputFullWidth: {
width: "100%",
maxWidth: "100%",
boxSizing: "border-box",
},
authControl: {
width: "100%",
maxWidth: "100%",
boxSizing: "border-box",
},
authErrorText: {
color: palette.dangerText,
margin: "12px auto 0",
fontSize: 14,
maxWidth: 380,
textAlign: "center",
},
authInfoText: {
color: palette.successText,
margin: "12px auto 0",
fontSize: 14,
maxWidth: 380,
textAlign: "center",
},
authSwitchRow: {
marginTop: 16,
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: 8,
flexWrap: "wrap",
},
authSwitchLabel: {
color: palette.textSecondary,
fontSize: 14,
},
authSwitchButton: {
border: "none",
background: "transparent",
color: palette.brandGreenBorder,
fontSize: 14,
fontWeight: 600,
cursor: "pointer",
padding: 0,
},
};

View File

@@ -0,0 +1,42 @@
import { palette } from "./palette";
import type { StyleMap } from "./types";
export const cardStyles: StyleMap = {
cardBase: {
background: palette.surface,
border: `1px solid ${palette.borderDefault}`,
borderRadius: 8,
padding: 14,
boxShadow: `0 1px 0 ${palette.shadowSubtle}`,
minHeight: 88,
},
cardTopRow: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
gap: 10,
},
cardLabel: {
fontSize: 12,
fontWeight: 600,
color: palette.textSecondary,
letterSpacing: "0.02em",
textTransform: "uppercase",
},
cardValue: {
fontSize: 24,
fontWeight: 700,
marginTop: 6,
letterSpacing: "-0.02em",
color: palette.textPrimary,
},
cardSubLabel: {
marginTop: 6,
fontSize: 12,
color: palette.textSecondary,
},
};

View File

@@ -0,0 +1,55 @@
import { palette } from "./palette";
import type { StyleMap } from "./types";
export const datasetStyles: StyleMap = {
sectionHeaderTitle: {
margin: 0,
color: palette.textPrimary,
fontSize: 28,
fontWeight: 600,
},
sectionHeaderSubtitle: {
margin: "8px 0 0",
color: palette.textSecondary,
fontSize: 14,
},
listNoBullets: {
listStyle: "none",
margin: 0,
padding: 0,
},
datasetListItem: {
display: "flex",
alignItems: "center",
justifyContent: "space-between",
gap: 12,
padding: "14px 16px",
borderBottom: `1px solid ${palette.borderMuted}`,
},
datasetName: {
fontWeight: 600,
color: palette.textPrimary,
},
datasetMeta: {
fontSize: 13,
color: palette.textSecondary,
marginTop: 4,
},
datasetMetaSecondary: {
fontSize: 13,
color: palette.textSecondary,
marginTop: 2,
},
subtleBodyText: {
margin: "10px 0 0",
fontSize: 13,
color: palette.textBody,
},
};

View File

@@ -0,0 +1,51 @@
import { palette } from "./palette";
import type { StyleMap } from "./types";
export const emotionalStyles: StyleMap = {
emotionalSummaryRow: {
display: "flex",
flexWrap: "wrap",
gap: 10,
fontSize: 13,
color: palette.textTertiary,
marginTop: 6,
},
emotionalTopicLabel: {
fontSize: 12,
fontWeight: 600,
color: palette.textSecondary,
letterSpacing: "0.02em",
textTransform: "uppercase",
},
emotionalTopicValue: {
fontSize: 24,
fontWeight: 800,
marginTop: 4,
lineHeight: 1.2,
},
emotionalMetricRow: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginTop: 10,
fontSize: 13,
color: palette.textSecondary,
},
emotionalMetricRowCompact: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginTop: 4,
fontSize: 13,
color: palette.textSecondary,
},
emotionalMetricValue: {
fontWeight: 600,
color: palette.textPrimary,
},
};

View File

@@ -0,0 +1,34 @@
import { palette } from "./palette";
import type { StyleMap } from "./types";
export const feedbackStyles: StyleMap = {
alertCardError: {
borderColor: palette.alertErrorBorder,
background: palette.alertErrorBg,
color: palette.alertErrorText,
fontSize: 14,
},
alertCardInfo: {
borderColor: palette.alertInfoBorder,
background: palette.surface,
color: palette.textBody,
fontSize: 14,
},
statusMessageCard: {
marginTop: 12,
boxShadow: "none",
},
dashboardMeta: {
fontSize: 13,
color: palette.textSecondary,
},
tabsRow: {
display: "flex",
gap: 8,
marginTop: 12,
},
};

View File

@@ -0,0 +1,157 @@
import { palette } from "./palette";
import type { StyleMap } from "./types";
export const foundationStyles: StyleMap = {
appShell: {
minHeight: "100vh",
background: palette.canvas,
fontFamily: '"IBM Plex Sans", "Noto Sans", "Liberation Sans", "Segoe UI", sans-serif',
color: palette.textPrimary,
},
page: {
width: "100%",
minHeight: "100vh",
padding: 20,
background: palette.canvas,
fontFamily: '"IBM Plex Sans", "Noto Sans", "Liberation Sans", "Segoe UI", sans-serif',
color: palette.textPrimary,
overflowX: "hidden",
boxSizing: "border-box",
},
container: {
maxWidth: 1240,
margin: "0 auto",
},
containerWide: {
maxWidth: 1100,
margin: "0 auto",
},
containerNarrow: {
maxWidth: 720,
margin: "0 auto",
},
card: {
background: palette.surface,
borderRadius: 8,
padding: 16,
border: `1px solid ${palette.borderDefault}`,
boxShadow: `0 1px 0 ${palette.shadowSubtle}`,
},
headerBar: {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
justifyContent: "space-between",
gap: 10,
},
controls: {
display: "flex",
gap: 8,
alignItems: "center",
},
controlsWrapped: {
display: "flex",
gap: 8,
alignItems: "center",
flexWrap: "wrap",
},
input: {
width: 280,
maxWidth: "70vw",
padding: "8px 10px",
borderRadius: 6,
border: `1px solid ${palette.borderDefault}`,
outline: "none",
fontSize: 14,
background: palette.surface,
color: palette.textPrimary,
},
buttonPrimary: {
padding: "8px 12px",
borderRadius: 6,
border: `1px solid ${palette.brandGreenBorder}`,
background: palette.brandGreen,
color: palette.surface,
fontWeight: 600,
cursor: "pointer",
boxShadow: "none",
},
buttonSecondary: {
padding: "8px 12px",
borderRadius: 6,
border: `1px solid ${palette.borderDefault}`,
background: palette.canvas,
color: palette.textPrimary,
fontWeight: 600,
cursor: "pointer",
},
grid: {
marginTop: 12,
display: "grid",
gridTemplateColumns: "repeat(12, 1fr)",
gap: 12,
},
sectionTitle: {
margin: 0,
fontSize: 17,
fontWeight: 600,
},
sectionSubtitle: {
margin: "6px 0 14px",
fontSize: 13,
color: palette.textSecondary,
},
chartWrapper: {
width: "100%",
height: 350,
},
heatmapWrapper: {
width: "100%",
height: 320,
},
topUsersList: {
display: "flex",
flexDirection: "column",
gap: 10,
},
topUserItem: {
padding: "10px 12px",
borderRadius: 8,
background: palette.canvas,
border: `1px solid ${palette.borderMuted}`,
},
topUserName: {
fontWeight: 600,
fontSize: 14,
color: palette.textPrimary,
},
topUserMeta: {
fontSize: 13,
color: palette.textSecondary,
},
scrollArea: {
maxHeight: 420,
overflowY: "auto",
},
};

View File

@@ -0,0 +1,28 @@
import { palette } from "./palette";
import type { StyleMap } from "./types";
export const modalStyles: StyleMap = {
modalRoot: {
position: "relative",
zIndex: 50,
},
modalBackdrop: {
position: "fixed",
inset: 0,
background: palette.modalBackdrop,
},
modalContainer: {
position: "fixed",
inset: 0,
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: 16,
},
modalPanel: {
width: "min(520px, 95vw)",
},
};

View File

@@ -0,0 +1,26 @@
export const palette = {
canvas: "#f6f8fa",
surface: "#ffffff",
textPrimary: "#24292f",
textSecondary: "#57606a",
textTertiary: "#4b5563",
textBody: "#374151",
borderDefault: "#d0d7de",
borderMuted: "#d8dee4",
shadowSubtle: "rgba(27, 31, 36, 0.04)",
brandGreen: "#2da44e",
brandGreenBorder: "#1f883d",
statusPositiveBorder: "#b7dfc8",
statusPositiveBg: "#edf9f1",
statusPositiveText: "#1f6f43",
statusNegativeBorder: "#f3c1c1",
statusNegativeBg: "#fff2f2",
statusNegativeText: "#9a2929",
dangerText: "#b91c1c",
successText: "#166534",
alertErrorBorder: "rgba(185, 28, 28, 0.28)",
alertErrorBg: "#fff5f5",
alertErrorText: "#991b1b",
alertInfoBorder: "rgba(0,0,0,0.06)",
modalBackdrop: "rgba(0,0,0,0.45)",
} as const;

View File

@@ -0,0 +1,3 @@
import type { CSSProperties } from "react";
export type StyleMap = Record<string, CSSProperties>;

View File

@@ -1,136 +1,22 @@
import type { CSSProperties } from "react";
import { appLayoutStyles } from "./stats/appLayout";
import { authStyles } from "./stats/auth";
import { cardStyles } from "./stats/cards";
import { datasetStyles } from "./stats/datasets";
import { emotionalStyles } from "./stats/emotional";
import { feedbackStyles } from "./stats/feedback";
import { foundationStyles } from "./stats/foundations";
import { modalStyles } from "./stats/modal";
const StatsStyling: Record<string, CSSProperties> = {
page: {
width: "100%",
minHeight: "100vh",
padding: 24,
background: "#f6f7fb",
fontFamily:
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, Arial, sans-serif',
color: "#111827",
overflowX: "hidden",
boxSizing: "border-box"
},
container: {
maxWidth: 1400,
margin: "0 auto",
},
card: {
background: "white",
borderRadius: 16,
padding: 16,
border: "1px solid rgba(0,0,0,0.06)",
boxShadow: "0 6px 20px rgba(0,0,0,0.06)",
},
headerBar: {
display: "flex",
flexWrap: "wrap",
alignItems: "center",
justifyContent: "space-between",
gap: 12,
},
controls: {
display: "flex",
gap: 10,
alignItems: "center",
},
input: {
width: 320,
maxWidth: "70vw",
padding: "10px 12px",
borderRadius: 12,
border: "1px solid rgba(0,0,0,0.12)",
outline: "none",
fontSize: 14,
background: "#fff",
color: "black"
},
buttonPrimary: {
padding: "10px 14px",
borderRadius: 12,
border: "1px solid rgba(0,0,0,0.08)",
background: "#2563eb",
color: "white",
fontWeight: 600,
cursor: "pointer",
boxShadow: "0 6px 16px rgba(37,99,235,0.25)",
},
buttonSecondary: {
padding: "10px 14px",
borderRadius: 12,
border: "1px solid rgba(0,0,0,0.12)",
background: "#fff",
color: "#111827",
fontWeight: 600,
cursor: "pointer",
},
grid: {
marginTop: 18,
display: "grid",
gridTemplateColumns: "repeat(12, 1fr)",
gap: 16,
},
sectionTitle: {
margin: 0,
fontSize: 16,
fontWeight: 700,
},
sectionSubtitle: {
margin: "6px 0 14px",
fontSize: 13,
color: "#6b7280",
},
chartWrapper: {
width: "100%",
height: 350,
},
heatmapWrapper: {
width: "100%",
height: 320,
},
topUsersList: {
display: "flex",
flexDirection: "column",
gap: 10,
},
topUserItem: {
padding: "10px 12px",
borderRadius: 12,
background: "#f9fafb",
border: "1px solid rgba(0,0,0,0.06)",
},
topUserName: {
fontWeight: 700,
fontSize: 14,
color: "black"
},
topUserMeta: {
fontSize: 13,
color: "#6b7280",
},
scrollArea: {
maxHeight: 450,
overflowY: "auto",
},
...foundationStyles,
...appLayoutStyles,
...authStyles,
...datasetStyles,
...feedbackStyles,
...cardStyles,
...emotionalStyles,
...modalStyles,
};
export default StatsStyling;
export default StatsStyling;