zotero/scss/components/_citationDialog.scss
Dan Stillman caeffa9f41 Citation dialog: Hide the citation preview until the citation has items
Show the preview area and its toggle button only once there is
something to preview, instead of showing a "Preview" placeholder in an
empty dialog.
2026-07-28 12:29:59 -04:00

960 lines
23 KiB
SCSS

#citation-dialog, #progress-bar {
min-width: 800px;
&[dialog-layout="library"] {
min-width: 1000px;
}
// during resizing, components of library mode have flexible height
&[resizing="true"] {
#library-other-items {
flex-shrink: 1 !important;
}
#library-trees {
min-height: 0 !important;
#sidebar {
#annotations-message {
display: none !important;
}
}
}
}
height: 100%;
body {
height: inherit;
margin: 0;
color: var(--fill-primary);
background: var(--material-background);
overflow-y: hidden;
-moz-window-dragging: drag;
}
[hidden] {
display: none !important;
}
.layout {
display: contents;
}
.btn-icon {
@include focus-ring;
border: none;
width: 28px;
height: 28px;
max-height: 28px;
padding: 0;
color: var(--fill-secondary);
background-size: auto !important;
background-repeat: no-repeat;
border-radius: 5px;
margin: 0;
&:hover:not([disabled]) {
cursor: pointer;
background-color: var(--fill-quinary) !important;
}
&:active:not([disabled]) {
background-color: var(--fill-quarternary) !important;
}
&:disabled {
opacity: 0.5;
}
}
#accept-button {
@include svgicon("checkmark", "universal", "20");
}
#cancel-button {
@include svgicon("x", "universal", "20");
}
#search-row {
margin: 9px 8px 9px 0;
#z-icon-container {
width: 36px; // same as left margin on .library-other-items
#z-icon {
background-image: url(chrome://zotero/skin/z.svg);
width: 16px;
height: 16px;
margin-top: 7px;
margin-left: 12px;
}
}
#progress {
flex: 1;
}
#top-level-btn-group {
display: flex;
width: 73px;
justify-content: end;
align-items: center;
gap: 8px;
-moz-window-dragging: no-drag;
// same height as a single row of bubbles so that this group is not stretched
// when there are multiple rows of bubbles and buttons do not shift
height: 30px;
#loading-spinner {
width: 28px;
height: 28px;
}
.vertical-separator {
border-inline-end: 1px solid var(--fill-quarternary);
height: 20px;
}
}
}
.divider {
border-bottom: 1px solid var(--color-panedivider);
margin: 0;
&.subtle {
border-bottom-color: var(--fill-quinary);
margin: 0 8px;
}
}
.add-all {
@include focus-ring(true);
border-radius: 5px;
font-weight: 400;
text-decoration: underline;
margin-left: auto;
-moz-window-dragging: no-drag;
&:hover {
cursor: pointer;
}
}
.zotero-spinner-16 {
background-size: 60%;
background-repeat: no-repeat;
display: none;
&[status="animate"] {
display: inline-block;
}
}
// alternative to var(--accent-blue10) without opacity
// which causes issues with stacked item cards in library mode
--selected-item-background: #EBF0FC;
@media (prefers-color-scheme: dark) {
--selected-item-background: #28375A;
}
#library-layout {
#sidebar {
display: none;
}
#library-other-items {
// constant height is so the message can appear/disappear without shifting the layout
height: 82px;
flex-shrink: 0; // make sure suggested items do not get shrunk when window is resized
--item-width: 210px;
--item-padding-horizontal: 4px;
--item-margin: 4px;
--item-horizontal-size: calc(var(--item-width) + 2*var(--item-padding-horizontal) + 2px);
position: relative;
overflow-x: auto;
overflow-y: hidden;
// no vertical scrollbar for selected/opened/cited items
scrollbar-width: none;
// add fade effect on the edges of
mask-image: linear-gradient(to right, transparent, black 10px, black calc(100% - 10px), transparent);
// padding and margin needed to allow space for fade effect
// without it being visible at initial scroll position
padding-inline: 8px;
margin-inline: 4px;
// wrapper for horizontal scrollable suggested items
.search-items {
display: flex;
padding: 8px 0;
.section {
&:not(:last-of-type) {
margin-inline-end: 16px;
}
// hide vertical divider
.divider {
display: none;
}
.header {
height: 20px;
color: var(--fill-secondary);
// keep header stuck to the top left corner as the user scrolls
position: sticky;
top: 0;
left: 0;
width: var(--item-horizontal-size);
-moz-user-select: none;
// ensure long headers in non-english locales do not break the layout
text-wrap: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: flex;
.header-btn-group {
display: flex;
align-items: center;
}
}
.itemsContainer {
flex-direction: row;
display: flex;
margin-top: 2px;
gap: var(--item-margin);
transition: gap 0.2s ease-in-out;
border-radius: 5px;
.item {
@include focus-ring(true);
height: 42px;
flex-shrink: 0;
width: var(--item-width);
overflow: hidden;
white-space: pre;
border: 1px solid var(--fill-quarternary);
border-radius: 5px;
display: flex;
flex-direction: column;
justify-content: center;
cursor: default;
padding: 0 var(--item-padding-horizontal);
line-height: 18px;
-moz-user-select: none;
transform: translateX(0);
transition: transform 0.2s ease-in-out;//, margin-inline 0.3s ease-in-out;
// color has to be without opacity to the selected items deck
background-color: var(--color-background);
-moz-window-dragging: no-drag;
.title {
font-size: 1rem;
overflow: hidden;
text-overflow: ellipsis;
}
.description {
color: var(--fill-secondary);
line-height: 16px;
overflow: hidden;
text-overflow: ellipsis;
}
&.selected {
background-color: var(--selected-item-background) !important;
}
// no visible border around the placeholder
&.cited-placeholder {
border: 1px solid transparent;
padding: 0;
}
}
}
// handle sections that can be expanded or collapsed
&.expandable {
transition: width 0.2s ease-in-out;
width: calc((var(--item-horizontal-size) * var(--deck-length)) + (var(--item-margin) * (var(--deck-length) - 1)));
.header {
.header-label {
// make sure header text does not overlap with buttons
max-width: 160px;
text-overflow: ellipsis;
overflow: hidden;
}
.header-btn-group {
gap: 4px;
flex: 1;
margin-inline-start: 2px;
.collapse-section-btn {
@include focus-ring(true);
@include svgicon("chevron-12-double", "universal", "16");
color: var(--fill-primary);
width: 16px;
height: 16px;
margin-top: 1px; // nicer alignment with the section header
-moz-window-dragging: no-drag;
}
}
}
.item {
z-index: calc(var(--deck-length) - var(--deck-index));
}
// collapsed sections move all items under the top first item
&:not(.expanded) {
// collapsed deck's width = width of an item + 5px for each item peaking behind the top one (max of 2)
width: calc(var(--item-horizontal-size) + 5px * min(2, var(--deck-length)));
.itemsContainer {
@include focus-ring(true);
gap: 0;
}
.item:nth-child(1) {
box-shadow: 2px 0px 4px 0px rgba(0, 0, 0, 0.10)
}
// 2nd and 3rd children are moved behind the first item, shrunk slightly and moved a bit to the right
// (by 16px and 32px) so their edge peaks out behind the top item
.item:nth-child(2) {
transform: translateX(calc(-1 * var(--deck-index) * (var(--item-horizontal-size)) + 16px)) scale(0.9);
box-shadow: 2px 0px 4px 0px rgba(0, 0, 0, 0.10)
}
.item:nth-child(3) {
transform: translateX(calc(-1 * var(--deck-index) * (var(--item-horizontal-size)) + 32px)) scale(0.8);
box-shadow: 2px 0px 4px 0px rgba(0, 0, 0, 0.10)
}
// remaining item cards are just hidden behind the top item
.item:nth-child(n + 4) {
transform: translateX(calc(-1 * var(--deck-index) * (var(--item-horizontal-size))));
}
// no button to collapse the dection when it is already collapsed
.collapse-section-btn {
display: none;
}
}
}
// separate items get a hover effect, unless they are in
// a collapsed expandable group, in which case the whole group is hovered
&:not(.expandable), &.expandable.expanded {
.item:not([disabled]):hover {
background-color: var(--color-quinary-on-background);
}
}
&.expandable:not(.expanded) {
.itemsContainer:hover {
.item {
background-color: var(--color-quinary-on-background);
}
}
}
}
}
#library-no-suggested-items-message {
align-self: center;
width: 100%;
text-align: center;
font-size: 1rem;
color: var(--fill-secondary);
-moz-user-select: none;
}
}
#library-trees {
min-height: 200px;
flex: 1;
-moz-user-select: none;
-moz-window-dragging: no-drag;
#collections-tree-container {
min-width: 200px;
min-height: 100%;
width: 200px;
flex-shrink: 0;
& > #zotero-collections-tree {
background: var(--material-sidepane) !important;
}
.virtualized-table-body {
padding-top: 8px;
}
}
#collections-tree-divider {
flex: 0 0 9px;
margin-inline-end: -8px;
position: relative;
cursor: ew-resize;
z-index: 1;
-moz-window-dragging: no-drag;
&::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
inset-inline-start: 0;
width: 1px;
background-color: var(--color-panedivider);
}
}
#item-tree-container {
min-height: 100%;
flex: 1; /* expand all the way to the right */
// supress focus ring flashing during double-click
&.no-focus-ring {
.row.focused {
outline: none !important;
border: none !important;
> *:first-child {
margin-inline-start: 0;
}
> *:last-child {
margin-inline-end: 0;
}
}
}
}
}
}
#list-layout {
#list-layout-wrapper {
-moz-user-select: none;
overflow-y: auto;
scrollbar-color: var(--color-scrollbar) var(--color-scrollbar-background);
height: 100%;
.section {
&:first-child {
padding-top: 4px;
}
&:last-child {
padding-bottom: 8px;
}
// show dividers except for on the last section
.divider {
margin: 4px 16px;
border-bottom: 1px solid var(--fill-quinary);
}
&:last-child {
.divider {
display: none;
}
}
.header {
font-weight: 700;
font-size: 1rem;
color: var(--fill-secondary);
padding: 4px 8px 4px 16px;
display: flex;
.header-btn-group {
display: flex;
align-items: center;
height: 17px;
}
}
.item {
@include focus-ring(true);
margin: 0 8px;
padding: 4px 8px;
border-radius: 5px;
color: var(--fill-primary);
cursor: default;
-moz-window-dragging: no-drag;
&:not([disabled]):hover {
background-color: var(--fill-quinary);
}
&.selected {
background-color: var(--selected-item-background);
border-radius: 0;
}
// selected background wins over the hover effect
&.selected:not([disabled]):hover {
background-color: var(--selected-item-background);
}
&.selected-first {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
&.selected-last {
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
.icon {
margin-top: -4px;
margin-inline-end: 4px;
flex-shrink: 0;
&.retracted {
width: 12px;
height: 12px;
color: var(--accent-red);
@include svgicon("cross", "universal", "16");
}
}
.description {
// Needed to have empty item row description to still occupy height
white-space: pre;
margin-inline-start: 20px;
overflow: hidden;
text-overflow: ellipsis;
}
.title {
font-size: 1rem;
overflow: hidden;
text-wrap: nowrap;
text-overflow: ellipsis;
}
}
&.expandable {
// styling for expandable header with a twisty
.header {
display: flex;
justify-content: space-between;
.header-label {
@include focus-ring;
border-radius: 5px;
-moz-window-dragging: no-drag;
&:hover {
cursor: pointer;
text-decoration: underline;
}
&::before {
@include svgicon("chevron-8", "universal", "8");
width: 8px;
height: 8px;
display: inline-block;
content: "";
white-space: pre;
margin-inline-end: 3px;
transform: rotate(0deg);
transform-origin: center;
transition: transform 0.2s ease-in-out;
vertical-align: middle;
margin-bottom: 3px;
}
}
}
&.expanded {
.header-label::before {
transform: rotate(180deg);
}
}
// item container has no height when it is collapsed
.itemsContainer {
transition: height 0.3s ease;
overflow: hidden;
// add small padding at the top and bottom to make sure the focus-ring (if it appear) is not
// cutoff by the overflow:hidden. Negative margin is to preserve spacing set by other components.
padding: 1px 0;
margin: -1px 0;
}
&:not(.expanded) {
.itemsContainer {
height: 0 !important; // important to override inline height with items displayed
}
}
}
}
}
&.empty {
// the bottom area's divider immediately follows, so hide this
// layout's divider to avoid a doubled line
> .divider {
display: none;
}
#list-layout-wrapper {
padding: 0;
}
}
}
#citation-preview {
padding-top: 6px;
// While the preview is being toggled on, lay it out off-flow so the window can grow to
// fit it before it's revealed: absolute keeps a real, measurable height without pushing
// the list around, and visibility:hidden keeps it invisible until there's room for it.
// inset-inline: 0 matches the in-flow width (body is the flow parent), so the measured
// height is accurate.
&.measuring {
position: absolute;
inset-inline: 0;
visibility: hidden;
}
#citation-preview-wrapper {
padding: 2px 12px 8px 12px;
min-height: 20px;
max-height: 160px;
overflow-y: auto;
-moz-window-dragging: no-drag;
font-family: "Times New Roman";
#citation-preview-content {
color: var(--fill-primary);
font-size: 1.1rem;
}
#citation-preview-error {
padding-top: 2px;
color: var(--fill-secondary);
font-family: $font-family-base;
}
}
}
#bottom-area-wrapper {
padding: 4px 8px;
.segmented-switch {
// Make the whole control look like a tab bar
background-color: var(--fill-quinary);
-moz-window-dragging: no-drag;
display: flex;
border: var(--material-border);
border-radius: 5px;
margin: 0;
padding: 0;
.option {
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative; // anchor separators
box-sizing: border-box;
min-width: 56px;
padding-inline: 5px;
height: 26px; // match 28px height of all other buttons minus 2 px for container border
border-radius: 5px;
// keep constant inline border width to prevent width jumps on selection
border-inline-start: 1px solid transparent;
border-inline-end: 1px solid transparent;
background-color: transparent;
&:not(.active):hover {
// bring place hover effect above the button
z-index: 2;
&::after {
content: "";
position: absolute;
top: 1px;
left: 0px;
right: 0px;
bottom: 1px;
background-color: var(--fill-quinary);
border-radius: 4px;
z-index: -1;
}
}
&:focus-visible {
// bring focused option above active its outline is visible
z-index: 2;
}
}
/* draw vertical separator on the left edge of every option except the first */
.option:not(:first-of-type)::before {
content: "";
position: absolute;
inset-inline-start: 0;
top: 5px;
bottom: 5px;
width: 1px;
background-color: var(--fill-quarternary);
}
/* selected option looks like a light card */
.option.active {
background-color: var(--material-background);
// Do not remove borders; only change colors so width stays constant
border-inline-start: var(--material-border);
border-inline-end: var(--material-border);
}
/* avoid overlapping with the container border on edges (keep width, make color transparent) */
.option.active:first-of-type {
border-inline-start-color: transparent;
}
.option.active:last-of-type {
border-inline-end-color: transparent;
}
/* hide separators adjacent to the selected or hovered option */
.option.active::before, .option:hover::before {
display: none;
}
.option.active + .option::before,
.option:hover + .option::before{
display: none;
}
/* add focus ring around the entire option when focused */
.option:focus-visible {
outline: 2px solid var(--accent-blue30);
border-radius: 5px;
}
}
#bottom-btn-group {
height: 28px;
gap: 8px;
-moz-window-dragging: no-drag;
#display-preview-button {
@include svgicon("dialog-citation-preview", "universal", "20");
&[aria-pressed="true"] {
background-color: var(--fill-quinary);
}
}
#settings-button {
@include svgicon("dialog-options", "universal", "16");
}
}
#dialog-type-setting {
#dialog-type-annotations .icon {
width: 16px;
height: 16px;
@include light-dark(
background,
url('chrome://zotero/skin/16/light/annotations.svg') no-repeat center/contain,
url('chrome://zotero/skin/16/dark/annotations.svg') no-repeat center/contain
);
}
}
}
#popups {
panel {
padding: 0;
.popup {
padding: 14px 16px;
}
}
.overlay {
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.1);
z-index: 1000;
}
#settings-popup {
top: 35px;
right: 5px;
.title {
font-size: 1rem;
font-weight: 700;
padding-bottom: 8px;
}
}
#itemDetails {
.popup {
width: min-content;
min-width: 364px; // with padding and border, the panel is 400px
.details-header {
.icon {
margin-inline-end: 5px;
margin-top: 2px;
flex-shrink: 0;
}
}
.details {
margin: 16px 0;
display: grid;
grid-template-columns: auto 1fr;
gap: 8px 1px;
align-items: center;
.details-label:not(select) {
text-align: end;
}
.details-data {
@media not (-moz-platform: windows) {
@include focus-ring;
}
margin-inline-end: 0;
padding-inline-start: 5px;
border-radius: 5px;
border: none;
box-shadow: 0px 0.5px 2.5px 0px rgba(0, 0, 0, 0.3);
}
#suppress-author-container {
// undo input's left margin to align checkbox with inputs
margin-left: -3px;
}
#label {
// align <select>'s end with the end of prefix/suffix labels better
margin-inline-end: -1px;
@media (-moz-platform: macos) {
height: 22px;
// <select> with increased height is hard to position but this helps
// to align it with <input> better
margin-bottom: -3px;
}
@media (-moz-platform: windows) {
border: 1px solid var(--color-border);
border-radius: 3px;
height: 25px;
}
@media (-moz-platform: linux) {
height: 24px; // same height as input
}
}
.details-locator-info {
padding-inline-start: 5px;
grid-column: 2;
// pull closer to the locator input above
margin-top: -4px;
color: var(--fill-secondary);
font-size: .93rem;
}
}
.buttons {
display: flex;
flex-wrap: nowrap;
white-space: nowrap;
gap: 4px;
}
.annotation-detail {
margin: 16px 0;
}
button.done {
// align html buttons with 'done' xul:button
@media not (-moz-platform: macos) {
margin-top: 0;
margin-bottom: 0;
margin-inline-end: 0;
}
margin-inline-start: auto;
}
button.remove {
color: var(--accent-red);
}
}
}
}
.description {
color: var(--fill-secondary);
font-size: 0.93rem;
// add comma between description <span>s
span:not(:last-child):not([no-comma])::after {
content: ", ";
}
}
.aria-hidden {
position: absolute;
top: -1000px;
left: -1000px;
visibility: hidden;
}
input[type="checkbox"], select, button {
// other platforms already get a standard focusring
@media (-moz-platform: linux) {
@include focus-ring;
}
}
.drag-image-wrapper {
position: absolute;
top: -1000px;
height: 200px;
width: 100%;
}
}
#progress-bar {
body {
justify-content: center;
}
#search-row {
margin-top: 9px;
#z-icon-container {
display: flex;
justify-content: center;
#z-icon {
margin: 0 !important;
}
}
}
}
#citation-dialog[dialog-type="annotations"] {
#library-layout {
#sidebar {
display: block;
width: 300px;
border-inline-start: var(--material-panedivider);
background: var(--material-sidepane);
#annotations-sidebar {
height: 100%;
#annotations-sidebar-filter-wrapper {
display: flex;
margin: 8px;
height: auto; // override height set by .search class
#annotations-sidebar-filter {
width: 100%;
border-radius: 5px;
border: 1px solid var(--fill-quarternary);
padding: 2px 3px;
margin: 0;
}
}
#annotations-list-wrapper {
overflow-y: auto;
// undo top padding of the first section
collapsible-section:first-of-type {
padding-top: 0;
}
}
#annotations-message {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
margin-inline: 8px;
#annotations-message-text {
text-align: center;
}
}
}
}
#library-other-items {
height: 98px;
.search-items {
.item {
height: 58px !important;
.title {
&.annotation-quote {
width: min-content;
max-width: 100%;
position: relative;
.title-text {
padding-inline-end: 6px;
&::before {
content: attr(q-mark-open);
}
}
&::after {
content: attr(q-mark-close);
position: absolute;
right: 0px;
}
}
}
}
}
}
#library-trees {
#item-tree-container {
// push +/- icon to the end of the row, since annotations
// rows are rendered disregarding the layout of columns
.row.annotation-row {
.clickable {
margin-inline-start: auto;
}
}
}
}
}
}