Files
wekan/client/components/sidebar/sidebar.css
T
Lauri Ojansivu 3aefa94a66 Board Statistics view (Tilastot): full-width board view, replaces Status popup
Move the board Status from a Board Settings sidebar popup into a
full-width board VIEW alongside Swimlanes / Lists / Calendar / Gantt /
Table in the board-view switcher. Named 'Statistics' (Finnish
'Tilastot'), translated to major languages (rest fall back to English).

New statsView template/js/css rendered from boardBody (isViewStats),
selectable via the switcher (js-open-stats-view -> board-view-stats,
added to the profile.boardView schema allowedValues). Reuses the server
boardStatus method so counts are accurate in lazy mode; shows the same
counts + time-spent summary as before. Text is selectable with mouse
(drag) and touch (long-press): the view stops pointer/touch events from
reaching the canvas drag-to-scroll so native selection + copy work.

Removed the old boardStatusPopup (template/handler/helpers/css) and its
Board menu item. Added a Playwright test for the view. Design doc
updated.
2026-07-20 14:47:32 +03:00

505 lines
13 KiB
CSS

.sidebar {
position: absolute;
top: 0;
bottom: 0;
inset-inline-end: 0;
overflow-y: scroll;
}
.sidebar {
background: #f7f7f7;
box-shadow: -10px 0px 5px -10px #b3b3b3;
}
.sidebar-xmark {
position: absolute;
inset-inline-end: 0px;
top: 0px;
font-size: 25px;
padding: 10px;
}
.sidebar-xmark:hover {
background: rgba(0,0,0,0.15);
}
.sidebar-actions {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 10px 10px 0px 10px;
}
.sidebar .sidebar-content {
padding: 0 12px;
}
/* Sidebar text inputs (Filter List by Title, Filter by card title, advanced
filter, etc.) fill the padded content width, so there is equal empty space on
both sides (the .sidebar-content 12px padding) instead of the browser's
default narrow width that left a large gap on the right. box-sizing keeps the
border inside the width so it never overflows the panel. */
.sidebar .sidebar-content input[type="text"],
.sidebar .sidebar-content input[type="search"] {
width: 100%;
box-sizing: border-box;
}
.sidebar .sidebar-content .hide-btn {
display: none;
}
.sidebar .sidebar-content h3 {
color: #808080;
font-size: 1em;
margin-bottom: 10px;
font-weight: bold;
}
.sidebar .sidebar-content h3 i.fa {
margin-inline-end: 3px;
}
.sidebar .sidebar-content hr {
margin: 13px 0;
}
.sidebar .sidebar-content ul.sidebar-list {
display: flex;
flex-direction: column;
}
/* Use checklist-style green checkboxes for all sidebar checkboxes */
.sidebar .materialCheckBox.is-checked,
.boardCardSettingsPopup .materialCheckBox.is-checked,
.boardSubtaskSettingsPopup .materialCheckBox.is-checked {
top: -4px !important;
inset-inline-start: -3px !important;
width: 7px !important;
height: 15px !important;
margin-inline-end: 6px !important;
border-top: 2px solid transparent !important;
border-inline-start: 2px solid transparent !important;
border-bottom: 2px solid #3cb500 !important;
border-inline-end: 2px solid #3cb500 !important;
transform: rotate(40deg) !important;
-webkit-backface-visibility: hidden !important;
backface-visibility: hidden !important;
transform-origin: 100% 100% !important;
}
/* Grey checkmarks when grey icons setting is enabled */
body.grey-icons-enabled .sidebar .materialCheckBox.is-checked,
body.grey-icons-enabled .boardCardSettingsPopup .materialCheckBox.is-checked,
body.grey-icons-enabled .boardSubtaskSettingsPopup .materialCheckBox.is-checked {
border-bottom: 2px solid #7a7a7a !important;
border-inline-end: 2px solid #7a7a7a !important;
}
/* Card Settings 3-column grid layout */
.card-settings-grid {
display: grid;
grid-template-columns: 1fr 1fr 2fr;
gap: 10px;
margin-bottom: 10px;
/* Keep the "Show on Card / Show on Minicard / Description" titles visible
while the rows below scroll (the popup scrolls in .pop-over .content-wrapper). */
position: sticky;
top: 0;
z-index: 2;
background: #fff;
padding: 5px 0;
border-bottom: 2px solid #ddd;
}
.card-settings-row {
display: grid;
grid-template-columns: 1fr 1fr 2fr;
gap: 10px;
align-items: center;
padding: 5px 0;
border-bottom: 1px solid #eee;
}
.card-settings-column {
display: flex;
align-items: center;
justify-content: center;
}
.card-settings-column:last-child {
justify-content: flex-start;
}
.card-settings-column h4 {
margin: 0;
font-size: 12px;
font-weight: bold;
text-align: center;
}
.sidebar .sidebar-content ul.sidebar-list li > a {
display: flex;
height: 30px;
margin: 0;
padding: 4px;
border-radius: 3px;
align-items: center;
}
.sidebar .sidebar-content ul.sidebar-list li > a:hover,
.sidebar .sidebar-content ul.sidebar-list li > a:hover i,
.sidebar .sidebar-content ul.sidebar-list li > a:hover .quiet {
color: #fff;
}
.sidebar .sidebar-content ul.sidebar-list li > a .member,
.sidebar .sidebar-content ul.sidebar-list li > a .card-label {
margin-inline-end: 7px;
margin-top: 5px;
}
.sidebar .sidebar-content ul.sidebar-list li > a .minicard-edit-button {
float: inline-end;
padding: 8px;
border-radius: 3px;
}
.sidebar .sidebar-content ul.sidebar-list li > a .sidebar-list-item-description {
flex: 1;
overflow: ellipsis;
}
.sidebar .sidebar-content ul.sidebar-list li > a .fa.fa-check {
margin: 0 4px;
color: #3cb500;
}
/* Grey check icons when grey icons setting is enabled */
body.grey-icons-enabled .sidebar .sidebar-content ul.sidebar-list li > a .fa.fa-check {
color: #7a7a7a;
}
.sidebar .sidebar-content ul.sidebar-list li .minicard {
padding: 6px 8px 4px;
}
.sidebar .sidebar-content ul.sidebar-list li .minicard .minicard-edit-button {
float: inline-end;
padding: 4px;
border-radius: 3px;
}
.sidebar .sidebar-content ul.sidebar-list li .minicard .minicard-edit-button:hover {
background: #dbdbdb;
}
.sidebar .sidebar-content .sidebar-btn {
display: block;
margin: 5px 0;
padding: 10px;
border-radius: 3px;
background: #e6e6e6;
}
.sidebar .sidebar-content .sidebar-btn * {
color: #fff;
}
.sidebar .sidebar-content .sidebar-btn:hover * {
color: #fff;
}
.sidebar .sidebar-content .sidebar-btn i.fa {
margin-inline-end: 10px;
}
.sidebar .sidebar-shortcuts {
top: 7px;
font-size: 1em;
line-height: 1.6em;
color: #000;
}
.sidebar .sidebar-shortcuts .sidebar-btn {
margin-inline-start: 3px;
margin-inline-end: 3px;
}
.board-sidebar {
display: none;
/* Keep a sensible sidebar width at every screen size. A bare 30vw scaled with
the viewport, so on very wide screens it grew to ~double the intended width
while looking right only at mid widths; clamp keeps the mid-width look and
caps it (and floors it) instead of scaling without bound. Phones (<800px)
are handled by the 100vw rule in the media query below. */
width: clamp(320px, 30vw, 560px);
z-index: 100;
transition: top 0.1s, right 0.1s, width 0.1s;
}
.board-sidebar.is-open {
display: block;
/* #6465 follow-up: the card details window docks to the right edge with
z-index 2001 — the same place this sidebar opens. When the user opens the
sidebar, the sidebar must win, or its content (e.g. the archives
Restore/Delete links) sits unreachable UNDER the card window. */
z-index: 2002;
}
/* Right sidebar resize handle: a thin grab strip on the LEFT edge of the open
sidebar; drag left/right to change the sidebar width. Desktop only (hidden on
phones by the media query below, where the sidebar is full width). */
.sidebar-resize-handle {
display: none;
}
.board-sidebar.is-open .sidebar-resize-handle {
display: block;
position: absolute;
top: 0;
bottom: 0;
inset-inline-start: -3px;
width: 6px;
cursor: col-resize;
z-index: 2003; /* above the open sidebar (2002) and its content */
background: transparent;
transition: background-color 0.2s ease;
}
.sidebar-resize-handle:hover {
background: rgba(0, 123, 255, 0.4);
box-shadow: 0 0 4px rgba(0, 123, 255, 0.3);
}
.sidebar-resize-handle:active {
background: rgba(0, 123, 255, 0.6);
box-shadow: 0 0 6px rgba(0, 123, 255, 0.4);
}
body.sidebar-resizing-active {
user-select: none;
cursor: col-resize;
}
.board-widget h4 {
margin: 5px 0;
}
.board-widget-activity {
margin-inline-end: -4px;
}
.sidebar-tongue {
display: block;
width: 30px;
height: 30px;
inset-inline-start: -30px;
position: absolute;
top: 0px;
z-index: 15;
background: #f7f7f7;
border-bottom-left-radius: 3px;
box-shadow: -4px 0px 7px -4px #b3b3b3;
color: #808080;
transition: left 0.1s;
}
.sidebar-tongue i.fa {
padding: 3px 9px;
font-size: 24px;
transition: transform 0.5s;
}
.sidebar-accessibility {
color: #4d4d4d;
padding: 5px 10px;
display: flex;
align-items: center;
text-decoration: none;
border-radius: 3px;
cursor: pointer;
margin-inline-start: auto;
margin-inline-end: 30px;
}
.sidebar-accessibility:hover {
background-color: #d9d9d9;
}
.sidebar-accessibility span {
margin-inline-start: 5px;
}
.board-sidebar.is-open .sidebar-tongue {
inset-inline-start: -28px;
}
.board-sidebar.is-open .sidebar-tongue:hover {
inset-inline-start: -25px;
}
.board-sidebar.is-open .sidebar-tongue i.fa {
transform: rotate(180deg);
}
.sidebar-tongue.is-hidden,
.board-sidebar.is-open .sidebar-tongue.is-hidden {
z-index: 0;
inset-inline-start: 5px;
}
/* #3199: In the Archive sidebar's Cards tab each card's Restore/Delete links
used to sit BETWEEN two archived cards with near-equal spacing, so users
could not tell which card they belonged to. Group each card with its own
links: no gap between the card and its links, and a clear separator gap
below the whole group before the next card. Spacing-only, so it works in
every board color/theme; logical properties keep it RTL-safe. */
.archived-card-item {
margin-block-end: 1.6em;
}
.archived-card-item .minicard-wrapper {
margin-bottom: 0;
}
.archived-card-item p.quiet {
margin-block-start: 2px;
margin-block-end: 0;
padding-inline-start: 4px;
}
.archived-lists .archived-lists-item {
border-top: 1px solid #ccc;
clear: both;
padding: 5px 0;
}
.archived-lists .archived-lists-item:first-child {
border-top: none;
}
.archived-lists .archived-lists-item button {
float: inline-end;
margin: 0;
margin: 0 0 5px 5px;
padding: 0 10px 0 10px;
}
@media screen and (max-width: 800px) {
/* On phones (iPhone 12 mini, etc.) the right sidebar should be a full-width
panel at the top of the board, in BOTH mobile mode and desktop mode. The
sidebar lives inside .board-wrapper, which is wider than the viewport on a
phone, so an absolutely-positioned sidebar (inset-inline-end: 0) pins to the
far right of the wide board and shows as a narrow strip. Pin it to the
VIEWPORT instead (position: fixed + 100vw) so it spans the full screen
width. At 100% zoom .board-wrapper has no transform, so fixed resolves to
the viewport in desktop mode too. */
.board-sidebar.sidebar {
position: fixed;
top: 0;
bottom: 0;
inset-inline-start: 0;
inset-inline-end: 0;
/* !important so a desktop drag-resize inline width never leaks into mobile,
where the sidebar must stay full width. */
width: 100vw !important;
max-width: 100vw !important;
z-index: 1000;
}
/* No dragging to resize on phones — the sidebar is full width there. */
.board-sidebar .sidebar-resize-handle {
display: none;
}
/* Normalise sidebar text on phones so the headings are not oversized and the
small text is not tiny — keep them close to the board's text size so board
and sidebar read at one consistent size. */
.board-sidebar.sidebar .sidebar-content {
font-size: 14px;
}
.board-sidebar.sidebar .sidebar-content h2,
.board-sidebar.sidebar .sidebar-content h3 {
font-size: 16px;
}
.board-sidebar.sidebar .sidebar-content ul.sidebar-list li > a,
.board-sidebar.sidebar .sidebar-content .card-label,
.board-sidebar.sidebar .sidebar-content .card-label .card-label-name,
.board-sidebar.sidebar .sidebar-content p,
.board-sidebar.sidebar .sidebar-content span {
font-size: 14px;
}
.board-sidebar .sidebar-content .hide-btn {
width: 40px;
height: 40px;
position: absolute;
inset-inline-end: 5px;
top: 5px;
display: block;
z-index: 15;
background: #f7f7f7;
transition: left 0.1s;
color: #808080;
border-radius: 50%;
border: 1px solid #b3b3b3;
box-shadow: 0 1px 6px rgba(0,0,0,0.3);
color: #808080;
}
.board-sidebar .sidebar-content .hide-btn i.fa {
padding: 8px 16px;
font-size: 24px;
font-weight: bold;
}
.sidebar-tongue {
width: 40px;
height: 40px;
inset-inline-start: -47px;
top: 5px;
display: block;
border-radius: 50%;
border: 1px solid #b3b3b3;
box-shadow: 0 1px 6px rgba(0,0,0,0.3);
color: #808080;
}
.board-sidebar.is-open .sidebar-tongue {
display: none;
}
.sidebar-tongue i.fa {
padding: 8px 0px 8px 16px;
font-weight: bold;
}
}
#jsBoardOrgs,
#jsBoardTeams {
width: 90%;
}
.leaveBoardBtn {
background-color: #008000 !important;
}
.cancelLeaveBoardBtn {
margin-inline-start: 5% !important;
background-color: #f00 !important;
}
.addTeamsLabel,
.addOrganizationsLabel {
font-weight: normal;
}
.js-manage-board-removeTeam:hover,
.js-manage-board-removeTeam.is-active,
.js-manage-board-removeOrg:hover,
.js-manage-board-removeOrg.is-active {
box-shadow: 0 0 0 2px #e23210 inset !important;
}
.js-manage-board-addTeam:hover,
.js-manage-board-addTeam.is-active,
.js-manage-board-addOrg:hover,
.js-manage-board-addOrg.is-active {
box-shadow: 0 0 0 2px #73ea10 inset !important;
}
.addTeamFaPlus {
color: #008000 !important;
}
.removeTeamFaMinus {
color: #f00 !important;
}
.divaddfaplusminus {
padding-top: 5px;
margin-inline-start: 40px;
}
/* Board backgrounds management popup */
.board-backgrounds-manage .board-backgrounds-grid {
display: flex;
flex-wrap: wrap;
margin-top: 8px;
}
.board-bg-item {
width: 48%;
margin: 1%;
border: 2px solid transparent;
border-radius: 3px;
}
.board-bg-item.is-active {
border-color: #3cb500;
}
.board-bg-thumb {
height: 80px;
background-size: cover;
background-position: center;
border-radius: 3px;
position: relative;
}
.board-bg-active-check {
position: absolute;
top: 4px;
inset-inline-end: 4px;
color: #3cb500;
background: rgba(255, 255, 255, 0.85);
border-radius: 50%;
padding: 2px;
}
.board-bg-actions {
display: flex;
justify-content: space-around;
padding: 4px 0;
}
.board-bg-actions a {
cursor: pointer;
color: #4d4d4d;
}
.board-bg-actions a:hover {
color: #000;
}
.js-bg-upload-button {
display: inline-block;
margin-bottom: 8px;
}