feat: add domain rules management feature

- Introduced a new DomainRulesPage component for managing custom and global equivalent domains.
- Updated AppMainRoutes to include a route for domain rules.
- Added API functions to fetch and save domain rules.
- Enhanced localization with new strings for domain rules in multiple languages.
- Updated styles for the new domain rules interface and ensured responsiveness.
- Added types for domain rules in the TypeScript definitions.
This commit is contained in:
shuaiplus
2026-05-06 00:33:09 +08:00
parent 246c73a3d3
commit 0a001bebcc
32 changed files with 2045 additions and 32 deletions
+282 -4
View File
@@ -2,6 +2,13 @@
@apply grid gap-3;
}
.domain-rules-route {
height: 100%;
min-height: 0;
overflow: hidden;
grid-template-rows: minmax(0, 1fr);
}
.import-export-page {
@apply grid gap-3;
}
@@ -19,9 +26,8 @@
.backup-operations-sidebar,
.backup-destination-sidebar,
.backup-detail-panel {
@apply min-w-0 rounded-xl bg-white p-3;
border: 1px solid #d8dee8;
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05);
@apply min-w-0 rounded-2xl border bg-panel p-3 shadow-soft;
border-color: var(--line);
}
.backup-actions-stack {
@@ -305,7 +311,7 @@
}
.backup-browser-list {
@apply overflow-hidden rounded-xl bg-white;
@apply overflow-hidden rounded-xl border bg-white;
border: 1px solid var(--line);
}
@@ -875,3 +881,275 @@
background: #e2e8f0;
color: #475569;
}
.section-heading-row {
@apply mb-3.5 flex items-center justify-between gap-3;
}
.section-heading-row h3 {
@apply mb-0;
}
.domain-rules-page {
@apply grid min-h-0 gap-3.5;
height: 100%;
overflow: hidden;
grid-template-rows: auto minmax(0, 1fr);
}
.domain-rules-toolbar {
@apply flex flex-wrap items-start justify-between gap-3;
}
.domain-rules-toolbar-copy {
max-width: 760px;
}
.domain-rules-toolbar-title {
@apply text-base font-bold;
color: var(--text);
}
.domain-rules-toolbar-copy p {
@apply mt-1.5 text-sm leading-6;
color: var(--muted-strong);
}
.domain-rules-grid {
min-height: 0;
grid-template-columns: minmax(380px, 1fr) minmax(420px, 1.08fr);
}
.domain-rules-custom,
.domain-rules-global {
@apply flex min-h-0 flex-col rounded-2xl border bg-panel shadow-soft;
border-color: var(--line);
}
.domain-rules-heading-actions {
@apply flex flex-wrap items-center justify-end gap-2;
}
.domain-rules-filter {
width: min(240px, 100%);
}
.domain-rules-table {
@apply grid min-h-0 flex-1 content-start gap-2 overflow-auto pr-0.5;
overflow-anchor: none;
}
.domain-rule-row {
@apply grid items-center gap-2.5 rounded-md px-2.5 py-2.5;
grid-template-columns: 18px minmax(0, 1fr) auto auto;
border: 1px solid var(--line);
background: var(--panel);
}
.domain-rule-row > input[type='checkbox'] {
align-self: center;
}
.domain-rule-readonly-row {
grid-template-columns: 18px minmax(0, 1fr) auto;
}
.domain-rule-editing-row {
@apply items-start;
grid-template-columns: minmax(360px, 1fr) auto;
column-gap: 12px;
}
.domain-rule-domains {
display: block;
line-height: 20px;
min-width: 0;
max-height: 20px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition:
max-height 180ms var(--ease-out-soft),
opacity 140ms var(--ease-smooth);
}
.domain-rule-row-expanded {
@apply items-start;
}
.domain-rule-row-expanded > input[type='checkbox'],
.domain-rule-row-expanded .domain-rule-expand-btn,
.domain-rule-row-expanded .domain-rule-row-actions {
margin-top: 1px;
}
.domain-rule-row-expanded .domain-rule-domains {
overflow: visible;
text-overflow: clip;
white-space: normal;
overflow-wrap: anywhere;
}
.domain-rule-domains-expanded {
max-height: 220px;
}
.domain-rule-expand-btn {
@apply flex h-8 w-8 cursor-pointer items-center justify-center rounded-full border-0 p-0;
background: transparent;
color: var(--muted-strong);
transition:
background-color var(--dur-fast) var(--ease-smooth),
color var(--dur-fast) var(--ease-smooth),
transform var(--dur-fast) var(--ease-out-soft);
}
.domain-rule-expand-btn:hover {
background: var(--panel-soft);
color: var(--primary);
transform: translateY(-1px);
}
.domain-rule-main {
width: 100%;
min-width: 0;
}
.domain-rule-inputs {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px 18px;
align-items: center;
}
.domain-rule-input-piece {
position: relative;
min-width: 0;
@apply flex items-center;
}
.domain-rule-inline-input {
width: 100%;
min-width: 0;
padding-right: 52px;
}
.domain-rule-inline-input.domain-rule-input-invalid {
border-color: rgba(217, 45, 87, 0.78);
background: color-mix(in srgb, var(--danger) 5%, var(--panel));
box-shadow: 0 0 0 3px rgba(217, 45, 87, 0.10), inset 0 1px 0 rgba(255, 255, 255, 0.72);
}
.domain-rule-inline-input.domain-rule-input-invalid:focus {
border-color: rgba(217, 45, 87, 0.86);
box-shadow: 0 0 0 4px rgba(217, 45, 87, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.78);
}
.domain-rule-operator {
position: absolute;
top: 50%;
right: -12px;
transform: translateY(-50%);
color: var(--muted);
font-weight: 700;
pointer-events: none;
}
.domain-rule-input-piece:nth-child(even) .domain-rule-operator {
display: none;
}
.domain-rule-mini-btn,
.domain-rule-icon-btn {
@apply h-9 w-9 justify-center p-0;
}
.domain-rule-input-remove {
@apply absolute top-1/2 flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full border-0 p-0;
right: 1rem;
background: var(--panel-soft);
color: var(--primary);
transition:
background-color var(--dur-fast) var(--ease-smooth),
color var(--dur-fast) var(--ease-smooth),
transform var(--dur-fast) var(--ease-out-soft);
}
.domain-rule-input-remove:hover {
background: color-mix(in srgb, var(--danger) 12%, var(--panel));
color: var(--danger);
transform: translateY(-50%) scale(1.04);
}
.domain-rule-row-actions {
@apply flex items-center self-center gap-2;
}
.domain-rule-row-actions .btn {
white-space: nowrap;
}
.domain-rule-editing-row .domain-rule-row-actions {
align-self: start;
padding-top: 6px;
}
.domain-rule-new-row {
@apply mb-2;
background: var(--panel-soft);
}
@media (max-width: 1180px) {
.route-stage-fixed {
overflow: auto;
}
.domain-rules-route {
height: auto;
overflow: visible;
grid-template-rows: auto;
}
.domain-rules-page {
height: auto;
overflow: visible;
}
.domain-rules-grid {
grid-auto-rows: minmax(320px, min(54vh, 560px));
}
.domain-rules-table {
max-height: none;
}
}
@media (max-width: 560px) {
.domain-rules-page {
height: auto;
}
.domain-rules-grid {
grid-auto-rows: auto;
}
.domain-rules-table {
max-height: 56vh;
}
.domain-rule-editing-row {
grid-template-columns: 1fr;
}
.domain-rule-inputs {
grid-template-columns: 1fr;
}
.domain-rule-operator {
display: none;
}
.domain-rule-editing-row .domain-rule-row-actions {
padding-top: 0;
}
}