Improve table styling and make headers more horizontal
- Add visible column borders to teams and projects tables - Make header 2px border for visual separation - Consolidate teams page header: title + inline stats on left, create button on right - Consolidate team dashboard header: title/badge/slug + description + inline stats on left, action buttons on right
This commit is contained in:
@@ -3,10 +3,18 @@
|
||||
}
|
||||
|
||||
.team-header {
|
||||
margin-bottom: 1.5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.team-header-info {
|
||||
.team-header-left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.team-header-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
@@ -15,20 +23,8 @@
|
||||
|
||||
.team-header h1 {
|
||||
margin: 0;
|
||||
font-size: 1.75rem;
|
||||
}
|
||||
|
||||
.team-description {
|
||||
margin: 0 0 0.5rem;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 1rem;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.team-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.team-slug {
|
||||
@@ -36,36 +32,31 @@
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.team-stats {
|
||||
.team-description {
|
||||
margin: 0 0 0.5rem;
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.9375rem;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.team-stats-inline {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: var(--color-bg-secondary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 1rem 1.5rem;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 1.5rem;
|
||||
.team-stats-inline .stat-value {
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.8125rem;
|
||||
color: var(--color-text-muted);
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
.team-actions {
|
||||
.team-header-actions {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 2rem;
|
||||
gap: 0.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.team-section {
|
||||
@@ -106,18 +97,24 @@
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-text-muted);
|
||||
background: var(--color-bg-secondary);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
border-bottom: 2px solid var(--color-border);
|
||||
border-right: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.projects-table th:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.projects-table td {
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
border-right: 1px solid var(--color-border);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.projects-table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
.projects-table td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.project-row {
|
||||
|
||||
@@ -95,54 +95,46 @@ function TeamDashboardPage() {
|
||||
/>
|
||||
|
||||
<div className="team-header">
|
||||
<div className="team-header-info">
|
||||
<h1>{team.name}</h1>
|
||||
{team.user_role && (
|
||||
<Badge variant={roleVariants[team.user_role] || 'default'}>
|
||||
{team.user_role}
|
||||
</Badge>
|
||||
<div className="team-header-left">
|
||||
<div className="team-header-title">
|
||||
<h1>{team.name}</h1>
|
||||
{team.user_role && (
|
||||
<Badge variant={roleVariants[team.user_role] || 'default'}>
|
||||
{team.user_role}
|
||||
</Badge>
|
||||
)}
|
||||
<span className="team-slug">@{team.slug}</span>
|
||||
</div>
|
||||
{team.description && (
|
||||
<p className="team-description">{team.description}</p>
|
||||
)}
|
||||
<div className="team-stats-inline">
|
||||
<span><span className="stat-value">{team.project_count}</span> projects</span>
|
||||
<span><span className="stat-value">{team.member_count}</span> members</span>
|
||||
</div>
|
||||
</div>
|
||||
{team.description && (
|
||||
<p className="team-description">{team.description}</p>
|
||||
{isAdminOrOwner && (
|
||||
<div className="team-header-actions">
|
||||
<Link to={`/teams/${slug}/members`} className="btn btn-secondary">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
|
||||
<circle cx="9" cy="7" r="4"/>
|
||||
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
||||
</svg>
|
||||
Members
|
||||
</Link>
|
||||
<Link to={`/teams/${slug}/settings`} className="btn btn-secondary">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
||||
</svg>
|
||||
Settings
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
<div className="team-meta">
|
||||
<span className="team-slug">@{team.slug}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="team-stats">
|
||||
<div className="stat-card">
|
||||
<div className="stat-value">{team.project_count}</div>
|
||||
<div className="stat-label">Projects</div>
|
||||
</div>
|
||||
<div className="stat-card">
|
||||
<div className="stat-value">{team.member_count}</div>
|
||||
<div className="stat-label">Members</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isAdminOrOwner && (
|
||||
<div className="team-actions">
|
||||
<Link to={`/teams/${slug}/settings`} className="btn btn-secondary">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<circle cx="12" cy="12" r="3"/>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
||||
</svg>
|
||||
Settings
|
||||
</Link>
|
||||
<Link to={`/teams/${slug}/members`} className="btn btn-secondary">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
|
||||
<circle cx="9" cy="7" r="4"/>
|
||||
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
||||
</svg>
|
||||
Members
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showProjectForm && (
|
||||
<div className="modal-overlay" onClick={() => setShowProjectForm(false)}>
|
||||
<div className="modal-content" onClick={e => e.stopPropagation()}>
|
||||
|
||||
@@ -8,50 +8,40 @@
|
||||
.teams-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 2rem;
|
||||
align-items: center;
|
||||
margin-bottom: 1.5rem;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.teams-header__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.teams-header__content h1 {
|
||||
margin: 0;
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.teams-header__subtitle {
|
||||
margin: 0.25rem 0 0;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 0.9375rem;
|
||||
}
|
||||
|
||||
/* Stats */
|
||||
.teams-stats {
|
||||
display: flex;
|
||||
gap: 2rem;
|
||||
padding: 1rem 1.5rem;
|
||||
background: var(--color-bg-secondary);
|
||||
border-radius: var(--radius-lg);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.teams-stat {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.teams-stat__value {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.teams-stat__label {
|
||||
font-size: 0.75rem;
|
||||
.teams-header__stats {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
color: var(--color-text-muted);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.teams-header__stats span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.teams-header__stats .stat-value {
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
/* Search */
|
||||
@@ -203,18 +193,24 @@
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--color-text-muted);
|
||||
background: var(--color-bg-secondary);
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
border-bottom: 2px solid var(--color-border);
|
||||
border-right: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.teams-table th:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.teams-table td {
|
||||
padding: 0.75rem 1rem;
|
||||
font-size: 0.875rem;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
border-right: 1px solid var(--color-border);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.teams-table tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
.teams-table td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.team-row {
|
||||
|
||||
@@ -115,7 +115,13 @@ function TeamsPage() {
|
||||
<div className="teams-header">
|
||||
<div className="teams-header__content">
|
||||
<h1>Teams</h1>
|
||||
<p className="teams-header__subtitle">Organize projects and collaborate with your team</p>
|
||||
{!loading && totalTeams > 0 && (
|
||||
<div className="teams-header__stats">
|
||||
<span><span className="stat-value">{totalTeams}</span> teams</span>
|
||||
<span><span className="stat-value">{ownedTeams}</span> owned</span>
|
||||
<span><span className="stat-value">{totalProjects}</span> projects</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<button className="btn btn-primary" onClick={() => setShowForm(true)}>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
@@ -126,24 +132,6 @@ function TeamsPage() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
{!loading && totalTeams > 0 && (
|
||||
<div className="teams-stats">
|
||||
<div className="teams-stat">
|
||||
<span className="teams-stat__value">{totalTeams}</span>
|
||||
<span className="teams-stat__label">Teams</span>
|
||||
</div>
|
||||
<div className="teams-stat">
|
||||
<span className="teams-stat__value">{ownedTeams}</span>
|
||||
<span className="teams-stat__label">Owned</span>
|
||||
</div>
|
||||
<div className="teams-stat">
|
||||
<span className="teams-stat__value">{totalProjects}</span>
|
||||
<span className="teams-stat__label">Projects</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Search */}
|
||||
{!loading && totalTeams > 3 && (
|
||||
<div className="teams-search">
|
||||
|
||||
Reference in New Issue
Block a user