Add alignItems: "end" to the fieldRow grid style so that all grid cells align their content to the bottom edge of the row. This ensures the DNS Mode <Select> and the Date Pattern <Combobox> sit on the same horizontal baseline even though Date Pattern carries a hint line that makes it taller. All other fieldRow usages have consistent hint presence across their fields, so no visual regressions are introduced.
258 lines
7.8 KiB
TypeScript
258 lines
7.8 KiB
TypeScript
/**
|
|
* Shared makeStyles definitions for the config page and its components.
|
|
*
|
|
* All config tab components import `useConfigStyles` from this module
|
|
* so that visual changes need updating in only one place.
|
|
*/
|
|
|
|
import { makeStyles, tokens } from "@fluentui/react-components";
|
|
|
|
export const useConfigStyles = makeStyles({
|
|
page: {
|
|
padding: tokens.spacingVerticalXXL,
|
|
maxWidth: "1100px",
|
|
},
|
|
// -------------------------------------------------------------------------
|
|
// List/Detail layout (ConfigListDetail component)
|
|
// -------------------------------------------------------------------------
|
|
/** Root flex-row container for the two-pane list/detail layout. */
|
|
listDetailRoot: {
|
|
display: "flex",
|
|
flexDirection: "row",
|
|
gap: tokens.spacingHorizontalM,
|
|
minHeight: "400px",
|
|
"@media (max-width: 900px)": {
|
|
flexDirection: "column",
|
|
},
|
|
},
|
|
/** Fixed-width left pane with scrollable item list. */
|
|
listPane: {
|
|
width: "280px",
|
|
flexShrink: "0",
|
|
overflowY: "auto",
|
|
borderRight: `1px solid ${tokens.colorNeutralStroke2}`,
|
|
paddingRight: tokens.spacingHorizontalS,
|
|
"@media (max-width: 900px)": {
|
|
width: "100%",
|
|
borderRight: "none",
|
|
borderBottom: `1px solid ${tokens.colorNeutralStroke2}`,
|
|
paddingRight: "0",
|
|
paddingBottom: tokens.spacingVerticalS,
|
|
overflowY: "visible",
|
|
},
|
|
},
|
|
/** A single clickable item in the left pane. */
|
|
listItem: {
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "space-between",
|
|
padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalM}`,
|
|
borderRadius: tokens.borderRadiusMedium,
|
|
cursor: "pointer",
|
|
userSelect: "none",
|
|
overflow: "hidden",
|
|
":hover": {
|
|
backgroundColor: tokens.colorNeutralBackground2,
|
|
},
|
|
":focus-visible": {
|
|
outline: `2px solid ${tokens.colorBrandBackground}`,
|
|
outlineOffset: "2px",
|
|
},
|
|
},
|
|
/** Additional styles applied to the currently selected list item. */
|
|
listItemSelected: {
|
|
backgroundColor: tokens.colorNeutralBackground1Selected,
|
|
borderLeft: `3px solid ${tokens.colorBrandBackground}`,
|
|
paddingLeft: `calc(${tokens.spacingHorizontalM} - 3px)`,
|
|
":hover": {
|
|
backgroundColor: tokens.colorNeutralBackground1Selected,
|
|
},
|
|
},
|
|
/** Right pane that shows detail content for the selected item. */
|
|
detailPane: {
|
|
flex: "1",
|
|
overflowY: "auto",
|
|
paddingLeft: tokens.spacingHorizontalM,
|
|
"@media (max-width: 900px)": {
|
|
paddingLeft: "0",
|
|
},
|
|
},
|
|
header: {
|
|
marginBottom: tokens.spacingVerticalL,
|
|
},
|
|
tabContent: {
|
|
marginTop: tokens.spacingVerticalL,
|
|
animationName: "fadeInUp",
|
|
animationDuration: tokens.durationNormal,
|
|
animationTimingFunction: tokens.curveDecelerateMid,
|
|
animationFillMode: "both",
|
|
},
|
|
section: {
|
|
marginBottom: tokens.spacingVerticalXL,
|
|
},
|
|
/** Card container for form sections — adds visual separation and depth. */
|
|
sectionCard: {
|
|
backgroundColor: tokens.colorNeutralBackground2,
|
|
borderRadius: tokens.borderRadiusMedium,
|
|
padding: `${tokens.spacingVerticalM} ${tokens.spacingHorizontalL}`,
|
|
boxShadow: tokens.shadow4,
|
|
marginBottom: tokens.spacingVerticalS,
|
|
},
|
|
/** Label row at the top of a sectionCard. */
|
|
sectionCardHeader: {
|
|
color: tokens.colorNeutralForeground2,
|
|
borderBottom: `1px solid ${tokens.colorNeutralStroke2}`,
|
|
paddingBottom: tokens.spacingVerticalS,
|
|
marginBottom: tokens.spacingVerticalM,
|
|
textTransform: "uppercase",
|
|
letterSpacing: "0.05em",
|
|
fontSize: tokens.fontSizeBase200,
|
|
fontWeight: tokens.fontWeightSemibold,
|
|
},
|
|
/** Monospace input with left brand-colour accent bar. */
|
|
codeInput: {
|
|
fontFamily: "monospace",
|
|
borderLeft: `3px solid ${tokens.colorBrandStroke1}`,
|
|
},
|
|
/** Applied to AccordionItem wrappers to get a hover background on headers. */
|
|
accordionItem: {
|
|
"& button:hover": {
|
|
backgroundColor: tokens.colorNeutralBackground1Hover,
|
|
},
|
|
},
|
|
/** Applied to AccordionItem wrappers that are currently expanded. */
|
|
accordionItemOpen: {
|
|
borderLeft: `3px solid ${tokens.colorBrandBackground}`,
|
|
},
|
|
fieldRow: {
|
|
display: "grid",
|
|
gridTemplateColumns: "1fr 1fr",
|
|
gap: tokens.spacingHorizontalM,
|
|
marginBottom: tokens.spacingVerticalS,
|
|
alignItems: "end",
|
|
"@media (max-width: 900px)": {
|
|
gridTemplateColumns: "1fr",
|
|
},
|
|
},
|
|
fieldRowThree: {
|
|
display: "grid",
|
|
gridTemplateColumns: "1fr 1fr 1fr",
|
|
gap: tokens.spacingHorizontalM,
|
|
marginBottom: tokens.spacingVerticalS,
|
|
"@media (max-width: 900px)": {
|
|
gridTemplateColumns: "1fr 1fr",
|
|
},
|
|
"@media (max-width: 700px)": {
|
|
gridTemplateColumns: "1fr",
|
|
},
|
|
},
|
|
buttonRow: {
|
|
display: "flex",
|
|
gap: tokens.spacingHorizontalS,
|
|
marginTop: tokens.spacingVerticalM,
|
|
flexWrap: "wrap",
|
|
},
|
|
codeFont: {
|
|
fontFamily: "monospace",
|
|
fontSize: "0.85rem",
|
|
},
|
|
regexItem: {
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: tokens.spacingHorizontalS,
|
|
marginBottom: tokens.spacingVerticalXS,
|
|
},
|
|
regexInput: {
|
|
flexGrow: "1",
|
|
fontFamily: "monospace",
|
|
borderLeft: `3px solid ${tokens.colorBrandStroke1}`,
|
|
},
|
|
logLine: {
|
|
padding: `${tokens.spacingVerticalXS} ${tokens.spacingHorizontalS}`,
|
|
borderRadius: tokens.borderRadiusSmall,
|
|
fontFamily: "monospace",
|
|
fontSize: "0.8rem",
|
|
marginBottom: tokens.spacingVerticalXXS,
|
|
wordBreak: "break-all",
|
|
},
|
|
matched: {
|
|
backgroundColor: tokens.colorPaletteGreenBackground2,
|
|
},
|
|
notMatched: {
|
|
backgroundColor: tokens.colorNeutralBackground3,
|
|
},
|
|
previewArea: {
|
|
maxHeight: "400px",
|
|
overflowY: "auto",
|
|
padding: tokens.spacingHorizontalS,
|
|
border: `1px solid ${tokens.colorNeutralStroke1}`,
|
|
borderRadius: tokens.borderRadiusMedium,
|
|
marginTop: tokens.spacingVerticalS,
|
|
},
|
|
infoText: {
|
|
color: tokens.colorNeutralForeground3,
|
|
fontStyle: "italic",
|
|
},
|
|
/** Empty-state container: centred icon + message. */
|
|
emptyState: {
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
gap: tokens.spacingVerticalM,
|
|
padding: `${tokens.spacingVerticalXXL} ${tokens.spacingHorizontalL}`,
|
|
color: tokens.colorNeutralForeground3,
|
|
textAlign: "center",
|
|
},
|
|
/** Auto-save status chip — for AutoSaveIndicator. */
|
|
autoSaveWrapper: {
|
|
display: "flex",
|
|
alignItems: "center",
|
|
gap: tokens.spacingHorizontalXS,
|
|
fontSize: tokens.fontSizeBase200,
|
|
color: tokens.colorNeutralForeground2,
|
|
},
|
|
autoSaveSaved: {
|
|
opacity: "1",
|
|
transform: "scale(1)",
|
|
transition: `opacity ${tokens.durationNormal} ${tokens.curveDecelerateMid}, transform ${tokens.durationNormal} ${tokens.curveDecelerateMid}`,
|
|
},
|
|
autoSaveFadingOut: {
|
|
opacity: "0",
|
|
transition: `opacity ${tokens.durationNormal} ${tokens.curveDecelerateMid}`,
|
|
},
|
|
});
|
|
|
|
/**
|
|
* Global CSS keyframes injected once.
|
|
*
|
|
* ``makeStyles`` does not support top-level ``@keyframes``, so we inject them
|
|
* via a ``<style>`` element on first import. The function is idempotent.
|
|
*/
|
|
export function injectGlobalStyles(): void {
|
|
if (document.getElementById("bangui-global-styles")) return;
|
|
const style = document.createElement("style");
|
|
style.id = "bangui-global-styles";
|
|
style.textContent = `
|
|
@keyframes fadeInUp {
|
|
from { opacity: 0; transform: translateY(4px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
@keyframes fadeInScale {
|
|
from { opacity: 0; transform: scale(0.95); }
|
|
to { opacity: 1; transform: scale(1); }
|
|
}
|
|
/* ConfigListDetail responsive: show dropdown on narrow screens */
|
|
@media (max-width: 900px) {
|
|
.bangui-list-dropdown { display: block !important; }
|
|
.bangui-list-items { display: none !important; }
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
}
|
|
|
|
// Inject keyframes on first module load (browser environment only).
|
|
if (typeof window !== "undefined") {
|
|
injectGlobalStyles();
|
|
}
|