mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
style(portal): simplify shell and team states
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"source_hash": "e0dc04d4f7be0d3c9048256e3dfff63acb71c236f2c8fd44b237612191a7d696",
|
||||
"source_hash": "69bb383eb566fc7cd58d13fdd5aad0d3d5b2b43107d66fbebc9d700607af2d26",
|
||||
"build_inputs": [
|
||||
"package.json",
|
||||
"tsconfig.json",
|
||||
|
||||
+57
-29
@@ -381,8 +381,8 @@ header .logout-btn:hover,
|
||||
.portal-shell-main {
|
||||
min-width: 0;
|
||||
min-height: 820px;
|
||||
padding: 0 0 28px;
|
||||
background: #f5f7fa;
|
||||
padding: 0 0 24px;
|
||||
background: #f3f6fa;
|
||||
}
|
||||
.portal-shell-main > .portal-content-panel {
|
||||
display: none !important;
|
||||
@@ -391,15 +391,27 @@ header .logout-btn:hover,
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 18px;
|
||||
align-items: end;
|
||||
padding: 16px 22px 18px;
|
||||
align-items: center;
|
||||
padding: 18px 22px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: rgba(244, 247, 250, 0.92);
|
||||
background: rgba(255, 255, 255, 0.84);
|
||||
}
|
||||
.portal-account-bar-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
gap: 8px;
|
||||
}
|
||||
.portal-account-bar-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.portal-account-bar-separator,
|
||||
.portal-account-bar-access {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
.portal-account-bar-row {
|
||||
display: flex;
|
||||
@@ -410,9 +422,9 @@ header .logout-btn:hover,
|
||||
}
|
||||
.portal-account-bar-row h2 {
|
||||
margin: 0;
|
||||
font-size: 28px;
|
||||
line-height: 0.98;
|
||||
letter-spacing: -0.05em;
|
||||
font-size: 32px;
|
||||
line-height: 0.96;
|
||||
letter-spacing: -0.06em;
|
||||
}
|
||||
.portal-account-bar-copy p {
|
||||
margin: 0;
|
||||
@@ -459,13 +471,13 @@ header .logout-btn:hover,
|
||||
gap: 26px;
|
||||
}
|
||||
.portal-content-panel {
|
||||
padding: 20px 22px 0;
|
||||
padding: 16px 22px 0;
|
||||
}
|
||||
.portal-top-section,
|
||||
.service-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
gap: 14px;
|
||||
}
|
||||
.portal-top-section-header h2,
|
||||
.service-header h2 {
|
||||
@@ -548,11 +560,11 @@ header .logout-btn:hover,
|
||||
.account-content-panel-overview,
|
||||
.account-content-panel-workspaces,
|
||||
.account-content-panel-team {
|
||||
padding: 18px;
|
||||
padding: 16px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
background: #eef3f7;
|
||||
box-shadow: 0 12px 28px rgba(10, 25, 41, 0.045);
|
||||
border-radius: 14px;
|
||||
background: #edf2f6;
|
||||
box-shadow: 0 10px 22px rgba(10, 25, 41, 0.04);
|
||||
}
|
||||
.account-command-deck,
|
||||
.account-overview-card,
|
||||
@@ -607,12 +619,12 @@ header .logout-btn:hover,
|
||||
.account-command-deck {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 14px;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
padding: 16px;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
.account-overview-card {
|
||||
display: grid;
|
||||
@@ -756,7 +768,7 @@ header .logout-btn:hover,
|
||||
.portal-support-panel {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 22px;
|
||||
padding: 18px 20px;
|
||||
background: var(--panel);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
@@ -944,17 +956,16 @@ header .logout-btn:hover,
|
||||
grid-template-columns: minmax(0, 1.42fr) minmax(360px, 1fr);
|
||||
gap: 14px;
|
||||
align-items: start;
|
||||
padding: 16px;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.56);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.68);
|
||||
}
|
||||
.workspace-operations-main,
|
||||
.workspace-operations-detail {
|
||||
min-width: 0;
|
||||
}
|
||||
.workspace-management-panel,
|
||||
.team-management-panel {
|
||||
.workspace-management-panel {
|
||||
min-height: 100%;
|
||||
}
|
||||
.workspace-management-panel.visible,
|
||||
@@ -1298,16 +1309,33 @@ header .logout-btn:hover,
|
||||
}
|
||||
.team-list-message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
min-height: 120px;
|
||||
padding: 16px;
|
||||
gap: 6px;
|
||||
min-height: 148px;
|
||||
padding: 18px;
|
||||
border: 1px dashed var(--line-strong);
|
||||
border-radius: 10px;
|
||||
color: var(--ink-muted);
|
||||
background: var(--panel-muted);
|
||||
}
|
||||
.team-list-message-title {
|
||||
font-size: 16px;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
color: var(--ink);
|
||||
}
|
||||
.team-list-message-copy {
|
||||
font-size: 13px;
|
||||
line-height: 1.55;
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
.team-list-message.error {
|
||||
border-color: rgba(166, 27, 27, 0.2);
|
||||
background: var(--danger-soft);
|
||||
}
|
||||
.team-list-message.error .team-list-message-title,
|
||||
.team-list-message.error .team-list-message-copy {
|
||||
color: var(--danger);
|
||||
}
|
||||
.btn-remove {
|
||||
|
||||
+16
-22
File diff suppressed because one or more lines are too long
@@ -83,13 +83,16 @@ describe('account view', function() {
|
||||
teamVisible: true,
|
||||
teamQuery: { status: 'loading', error: '', data: [] },
|
||||
}));
|
||||
expect(document.getElementById('team-list-acct_1')?.textContent).toContain('Loading');
|
||||
expect(document.getElementById('team-list-acct_1')?.textContent).toContain('Loading roster');
|
||||
expect(document.getElementById('team-stats-acct_1')?.textContent).toContain('Invites');
|
||||
|
||||
renderTeamSection('acct_1', createEntry({
|
||||
teamVisible: true,
|
||||
teamQuery: { status: 'error', error: 'Failed to load team.', data: [] },
|
||||
}));
|
||||
expect(document.getElementById('team-list-acct_1')?.textContent).toContain('Roster needs attention');
|
||||
expect(document.getElementById('team-list-acct_1')?.textContent).toContain('Failed to load team.');
|
||||
expect(document.getElementById('team-stats-acct_1')?.textContent).toContain('Invite only');
|
||||
|
||||
renderTeamSection(
|
||||
'acct_1',
|
||||
|
||||
@@ -163,11 +163,18 @@ export function renderWorkspaceManagement(account: PortalAccountSummary, entry:
|
||||
closeButton.disabled = entry.manageWorkspace.pending;
|
||||
}
|
||||
|
||||
function setContainerMessage(container: HTMLElement, msg: string, isError: boolean): void {
|
||||
function setContainerMessage(container: HTMLElement, title: string, msg: string, isError: boolean): void {
|
||||
container.textContent = '';
|
||||
var message = document.createElement('div');
|
||||
message.className = 'team-list-message' + (isError ? ' error' : '');
|
||||
message.textContent = msg;
|
||||
var heading = document.createElement('strong');
|
||||
heading.className = 'team-list-message-title';
|
||||
heading.textContent = title;
|
||||
var copy = document.createElement('span');
|
||||
copy.className = 'team-list-message-copy';
|
||||
copy.textContent = msg;
|
||||
message.appendChild(heading);
|
||||
message.appendChild(copy);
|
||||
container.appendChild(message);
|
||||
}
|
||||
|
||||
@@ -187,11 +194,15 @@ function renderTeamStats(accountID: string, entry: PortalAccountUIEntry): void {
|
||||
return;
|
||||
}
|
||||
if (entry.teamQuery.status === 'loading') {
|
||||
stats.innerHTML = '<div class="team-stat-card"><span class="team-stat-label">Roster</span><span class="team-stat-value">Loading…</span></div>';
|
||||
stats.innerHTML =
|
||||
'<div class="team-stat-card"><span class="team-stat-label">Roster</span><span class="team-stat-value">Loading…</span></div>' +
|
||||
'<div class="team-stat-card"><span class="team-stat-label">Invites</span><span class="team-stat-value">Ready</span></div>';
|
||||
return;
|
||||
}
|
||||
if (entry.teamQuery.status === 'error') {
|
||||
stats.innerHTML = '<div class="team-stat-card"><span class="team-stat-label">Roster</span><span class="team-stat-value team-stat-error">Needs attention</span></div>';
|
||||
stats.innerHTML =
|
||||
'<div class="team-stat-card"><span class="team-stat-label">Roster</span><span class="team-stat-value team-stat-error">Needs attention</span></div>' +
|
||||
'<div class="team-stat-card"><span class="team-stat-label">Fallback</span><span class="team-stat-value">Invite only</span></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -317,15 +328,15 @@ export function renderTeamSection(accountID: string, entry: PortalAccountUIEntry
|
||||
return;
|
||||
}
|
||||
if (entry.teamQuery.status === 'loading') {
|
||||
setContainerMessage(roster, 'Loading…', false);
|
||||
setContainerMessage(roster, 'Loading roster', 'Checking who currently has access to this account.', false);
|
||||
return;
|
||||
}
|
||||
if (entry.teamQuery.status === 'error') {
|
||||
setContainerMessage(roster, entry.teamQuery.error, true);
|
||||
setContainerMessage(roster, 'Roster needs attention', entry.teamQuery.error, true);
|
||||
return;
|
||||
}
|
||||
if (!entry.teamQuery.data.length) {
|
||||
setContainerMessage(roster, 'No team members.', false);
|
||||
setContainerMessage(roster, 'No operators yet', 'Invite someone new when this hosted account needs shared access.', false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,9 +125,6 @@ describe('shell view', function() {
|
||||
})
|
||||
);
|
||||
|
||||
expect(html).toContain('portal-shell-head-kicker">Pulse Account</div>');
|
||||
expect(html).toContain('portal-shell-head-title">Operator console</h1>');
|
||||
expect(html).toContain('Hosted operations, operator access, and commercial account services.');
|
||||
expect(html).toContain('portal-shell-nav');
|
||||
expect(html).toContain('Overview');
|
||||
expect(html).toContain('Workspaces');
|
||||
@@ -136,6 +133,7 @@ describe('shell view', function() {
|
||||
expect(html).toContain('id="account-services-section"');
|
||||
expect(html).toContain('Self-hosted licenses and billing');
|
||||
expect(html).toContain('portal-account-bar');
|
||||
expect(html).toContain('Owner access');
|
||||
expect(html).toContain('id="accounts-root"');
|
||||
expect(html).toContain('MSP account');
|
||||
expect(html).toContain('Acme MSP');
|
||||
@@ -196,9 +194,7 @@ describe('shell view', function() {
|
||||
);
|
||||
|
||||
expect(html).toContain('Pulse Account');
|
||||
expect(html).toContain('Self-hosted only');
|
||||
expect(html).toContain('portal-shell-head-title">Account console</h1>');
|
||||
expect(html).toContain('Billing, license recovery, refunds, and privacy actions until hosted access is attached.');
|
||||
expect(html).toContain('Account console');
|
||||
expect(html).toContain('Use these tools for self-hosted commercial actions.');
|
||||
expect(html).toContain('Account services');
|
||||
expect(html).not.toContain('Self-hosted licenses and billing');
|
||||
|
||||
@@ -193,36 +193,6 @@ function renderAttentionPanel(workspaces: PortalWorkspaceSummary[]): string {
|
||||
);
|
||||
}
|
||||
|
||||
function renderOverviewBand(accounts: PortalAccountSummary[]): string {
|
||||
var hosted = hasHostedAccounts(accounts);
|
||||
var workspaceTotal = countWorkspaces(accounts);
|
||||
var summary = hosted
|
||||
? 'Hosted operations, operator access, and commercial account services.'
|
||||
: 'Billing, license recovery, refunds, and privacy actions until hosted access is attached.';
|
||||
|
||||
return (
|
||||
'<section class="portal-shell-head">' +
|
||||
'<div class="portal-shell-head-main">' +
|
||||
'<div class="portal-shell-head-kicker">Pulse Account</div>' +
|
||||
'<div class="portal-shell-head-row">' +
|
||||
'<div class="portal-shell-head-copy">' +
|
||||
'<div class="portal-shell-head-brand-row">' +
|
||||
'<h1 class="portal-shell-head-title">' + (hosted ? 'Operator console' : 'Account console') + '</h1>' +
|
||||
'<span class="portal-shell-head-chip">' + (hosted ? 'Operator ready' : 'Self-hosted only') + '</span>' +
|
||||
'</div>' +
|
||||
'<p>' + summary + '</p>' +
|
||||
'</div>' +
|
||||
'<div class="portal-shell-head-summary">' +
|
||||
'<span class="portal-shell-summary-pill"><strong>Hosted access</strong>' + (hosted ? 'Active' : 'Not attached') + '</span>' +
|
||||
'<span class="portal-shell-summary-pill"><strong>Accounts</strong>' + (accounts.length === 1 ? '1 account' : String(accounts.length) + ' accounts') + '</span>' +
|
||||
'<span class="portal-shell-summary-pill"><strong>Workspace fleet</strong>' + (workspaceTotal ? workspaceCountLabel(workspaceTotal) : '0 workspaces') + '</span>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</section>'
|
||||
);
|
||||
}
|
||||
|
||||
function renderPrimaryAccountBar(account: PortalAccountSummary): string {
|
||||
var workspaceLabel = workspaceCountLabel((account.workspaces || []).length);
|
||||
var actionHTML = '';
|
||||
@@ -249,7 +219,11 @@ function renderPrimaryAccountBar(account: PortalAccountSummary): string {
|
||||
return (
|
||||
'<section class="portal-account-bar">' +
|
||||
'<div class="portal-account-bar-copy">' +
|
||||
'<div class="account-eyebrow">' + escapeHTML(accountKindLabel(account)) + '</div>' +
|
||||
'<div class="portal-account-bar-meta">' +
|
||||
'<span class="account-eyebrow">' + escapeHTML(accountKindLabel(account)) + '</span>' +
|
||||
'<span class="portal-account-bar-separator">/</span>' +
|
||||
'<span class="portal-account-bar-access">' + escapeHTML(titleCase(account.role)) + ' access</span>' +
|
||||
'</div>' +
|
||||
'<div class="portal-account-bar-row">' +
|
||||
'<h2>' + escapeHTML(account.name) + '</h2>' +
|
||||
'<div class="portal-account-bar-chips">' +
|
||||
@@ -657,28 +631,37 @@ function renderAccountTeamSection(account: PortalAccountSummary): string {
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="team-side-column">' +
|
||||
'<div class="team-invite-panel">' +
|
||||
'<div class="team-panel-heading">' +
|
||||
'<h4>Invite someone new</h4>' +
|
||||
'<p>Add another operator with the minimum role they need for this account.</p>' +
|
||||
'<div class="team-operations-panel">' +
|
||||
'<div class="team-panel-heading team-panel-heading-tight">' +
|
||||
'<div class="account-panel-kicker">Access desk</div>' +
|
||||
'<h4>Invite and role policy</h4>' +
|
||||
'<p>Keep the roster deliberate. Invite the smallest role first, then tighten access as responsibilities become clearer.</p>' +
|
||||
'</div>' +
|
||||
'<div class="team-invite">' +
|
||||
'<div><label for="invite-email-' +
|
||||
escapeAttr(account.id) +
|
||||
'">Email</label><input type="email" id="invite-email-' +
|
||||
escapeAttr(account.id) +
|
||||
'" placeholder="user@example.com" autocomplete="off"></div>' +
|
||||
'<div><label for="invite-role-' +
|
||||
escapeAttr(account.id) +
|
||||
'">Role</label><select id="invite-role-' +
|
||||
escapeAttr(account.id) +
|
||||
'"><option value="admin">Admin</option><option value="tech">Tech</option><option value="read_only">Read-only</option></select></div>' +
|
||||
'<button type="button" class="btn-primary btn-compact" data-action="invite-member" data-account-id="' +
|
||||
escapeAttr(account.id) +
|
||||
'">Invite</button>' +
|
||||
'<div class="team-operations-grid">' +
|
||||
'<div class="team-invite-panel">' +
|
||||
'<div class="team-panel-heading">' +
|
||||
'<h4>Invite someone new</h4>' +
|
||||
'<p>Add another operator with the minimum role they need for this account.</p>' +
|
||||
'</div>' +
|
||||
'<div class="team-invite">' +
|
||||
'<div><label for="invite-email-' +
|
||||
escapeAttr(account.id) +
|
||||
'">Email</label><input type="email" id="invite-email-' +
|
||||
escapeAttr(account.id) +
|
||||
'" placeholder="user@example.com" autocomplete="off"></div>' +
|
||||
'<div><label for="invite-role-' +
|
||||
escapeAttr(account.id) +
|
||||
'">Role</label><select id="invite-role-' +
|
||||
escapeAttr(account.id) +
|
||||
'"><option value="admin">Admin</option><option value="tech">Tech</option><option value="read_only">Read-only</option></select></div>' +
|
||||
'<button type="button" class="btn-primary btn-compact" data-action="invite-member" data-account-id="' +
|
||||
escapeAttr(account.id) +
|
||||
'">Invite</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
accessPolicy +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
accessPolicy +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</section>' +
|
||||
@@ -765,7 +748,6 @@ export function renderAuthenticatedPortalHTML(context: ShellViewContext): string
|
||||
'<div class="portal-shell-layout">' +
|
||||
renderShellNavigation(accounts, context.bootstrap.support_email || '', activeSection) +
|
||||
'<div class="portal-shell-main">' +
|
||||
renderOverviewBand(accounts) +
|
||||
(accounts.length === 1 ? renderPrimaryAccountBar(accounts[0]) : '') +
|
||||
'<section class="portal-content-panel portal-content-panel-overview">' +
|
||||
'<div id="accounts-root">' + hostedContent + '</div>' +
|
||||
|
||||
@@ -411,8 +411,8 @@ header .logout-btn:hover,
|
||||
.portal-shell-main {
|
||||
min-width: 0;
|
||||
min-height: 820px;
|
||||
padding: 0 0 28px;
|
||||
background: #f5f7fa;
|
||||
padding: 0 0 24px;
|
||||
background: #f3f6fa;
|
||||
}
|
||||
|
||||
.portal-shell-main > .portal-content-panel {
|
||||
@@ -423,16 +423,30 @@ header .logout-btn:hover,
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto;
|
||||
gap: 18px;
|
||||
align-items: end;
|
||||
padding: 16px 22px 18px;
|
||||
align-items: center;
|
||||
padding: 18px 22px 16px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
background: rgba(244, 247, 250, 0.92);
|
||||
background: rgba(255, 255, 255, 0.84);
|
||||
}
|
||||
|
||||
.portal-account-bar-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.portal-account-bar-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.portal-account-bar-separator,
|
||||
.portal-account-bar-access {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
.portal-account-bar-row {
|
||||
@@ -445,9 +459,9 @@ header .logout-btn:hover,
|
||||
|
||||
.portal-account-bar-row h2 {
|
||||
margin: 0;
|
||||
font-size: 28px;
|
||||
line-height: 0.98;
|
||||
letter-spacing: -0.05em;
|
||||
font-size: 32px;
|
||||
line-height: 0.96;
|
||||
letter-spacing: -0.06em;
|
||||
}
|
||||
|
||||
.portal-account-bar-copy p {
|
||||
@@ -502,14 +516,14 @@ header .logout-btn:hover,
|
||||
}
|
||||
|
||||
.portal-content-panel {
|
||||
padding: 20px 22px 0;
|
||||
padding: 16px 22px 0;
|
||||
}
|
||||
|
||||
.portal-top-section,
|
||||
.service-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.portal-top-section-header h2,
|
||||
@@ -606,11 +620,11 @@ header .logout-btn:hover,
|
||||
.account-content-panel-overview,
|
||||
.account-content-panel-workspaces,
|
||||
.account-content-panel-team {
|
||||
padding: 18px;
|
||||
padding: 16px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
background: #eef3f7;
|
||||
box-shadow: 0 12px 28px rgba(10, 25, 41, 0.045);
|
||||
border-radius: 14px;
|
||||
background: #edf2f6;
|
||||
box-shadow: 0 10px 22px rgba(10, 25, 41, 0.04);
|
||||
}
|
||||
|
||||
.account-command-deck,
|
||||
@@ -670,12 +684,12 @@ header .logout-btn:hover,
|
||||
.account-command-deck {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 14px;
|
||||
gap: 12px;
|
||||
align-items: stretch;
|
||||
padding: 16px;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
}
|
||||
|
||||
.account-overview-card {
|
||||
@@ -838,7 +852,7 @@ header .logout-btn:hover,
|
||||
.portal-support-panel {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 22px;
|
||||
padding: 18px 20px;
|
||||
background: var(--panel);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
@@ -1055,10 +1069,10 @@ header .logout-btn:hover,
|
||||
grid-template-columns: minmax(0, 1.42fr) minmax(360px, 1fr);
|
||||
gap: 14px;
|
||||
align-items: start;
|
||||
padding: 16px;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.56);
|
||||
border-radius: 12px;
|
||||
background: rgba(255, 255, 255, 0.68);
|
||||
}
|
||||
|
||||
.workspace-operations-main,
|
||||
@@ -1066,8 +1080,7 @@ header .logout-btn:hover,
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.workspace-management-panel,
|
||||
.team-management-panel {
|
||||
.workspace-management-panel {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
@@ -1465,17 +1478,37 @@ header .logout-btn:hover,
|
||||
|
||||
.team-list-message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
min-height: 120px;
|
||||
padding: 16px;
|
||||
gap: 6px;
|
||||
min-height: 148px;
|
||||
padding: 18px;
|
||||
border: 1px dashed var(--line-strong);
|
||||
border-radius: 10px;
|
||||
color: var(--ink-muted);
|
||||
background: var(--panel-muted);
|
||||
}
|
||||
|
||||
.team-list-message-title {
|
||||
font-size: 16px;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.team-list-message-copy {
|
||||
font-size: 13px;
|
||||
line-height: 1.55;
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
|
||||
.team-list-message.error {
|
||||
border-color: rgba(166, 27, 27, 0.2);
|
||||
background: var(--danger-soft);
|
||||
}
|
||||
|
||||
.team-list-message.error .team-list-message-title,
|
||||
.team-list-message.error .team-list-message-copy {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user