mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
[RFC] Refactor scene list toolbar (#6322)
* Revert scene list toolbar to use common filtered list toolbar * Add unobtrusive sidebar toggle button * Revert small device sidebar changes * Minor styling fixes
This commit is contained in:
parent
e213fde0cc
commit
730e877e73
9 changed files with 197 additions and 667 deletions
|
|
@ -78,6 +78,7 @@ export interface IFilteredListToolbar {
|
||||||
onEdit?: () => void;
|
onEdit?: () => void;
|
||||||
onDelete?: () => void;
|
onDelete?: () => void;
|
||||||
operations?: IListFilterOperation[];
|
operations?: IListFilterOperation[];
|
||||||
|
operationComponent?: React.ReactNode;
|
||||||
zoomable?: boolean;
|
zoomable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,6 +91,7 @@ export const FilteredListToolbar: React.FC<IFilteredListToolbar> = ({
|
||||||
onEdit,
|
onEdit,
|
||||||
onDelete,
|
onDelete,
|
||||||
operations,
|
operations,
|
||||||
|
operationComponent,
|
||||||
zoomable = false,
|
zoomable = false,
|
||||||
}) => {
|
}) => {
|
||||||
const filterOptions = filter.options;
|
const filterOptions = filter.options;
|
||||||
|
|
@ -100,6 +102,17 @@ export const FilteredListToolbar: React.FC<IFilteredListToolbar> = ({
|
||||||
const { selectedIds, onSelectAll, onSelectNone } = listSelect;
|
const { selectedIds, onSelectAll, onSelectNone } = listSelect;
|
||||||
const hasSelection = selectedIds.size > 0;
|
const hasSelection = selectedIds.size > 0;
|
||||||
|
|
||||||
|
const renderOperations = operationComponent ?? (
|
||||||
|
<ListOperationButtons
|
||||||
|
onSelectAll={onSelectAll}
|
||||||
|
onSelectNone={onSelectNone}
|
||||||
|
otherOperations={operations}
|
||||||
|
itemsSelected={selectedIds.size > 0}
|
||||||
|
onEdit={onEdit}
|
||||||
|
onDelete={onDelete}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonToolbar
|
<ButtonToolbar
|
||||||
className={cx("filtered-list-toolbar", { "has-selection": hasSelection })}
|
className={cx("filtered-list-toolbar", { "has-selection": hasSelection })}
|
||||||
|
|
@ -147,14 +160,7 @@ export const FilteredListToolbar: React.FC<IFilteredListToolbar> = ({
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<ListOperationButtons
|
{renderOperations}
|
||||||
onSelectAll={onSelectAll}
|
|
||||||
onSelectNone={onSelectNone}
|
|
||||||
otherOperations={operations}
|
|
||||||
itemsSelected={selectedIds.size > 0}
|
|
||||||
onEdit={onEdit}
|
|
||||||
onDelete={onDelete}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<ListViewButtonGroup
|
<ListViewButtonGroup
|
||||||
displayMode={filter.displayMode}
|
displayMode={filter.displayMode}
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,13 @@ export const OperationDropdown: React.FC<
|
||||||
PropsWithChildren<{
|
PropsWithChildren<{
|
||||||
className?: string;
|
className?: string;
|
||||||
menuPortalTarget?: HTMLElement;
|
menuPortalTarget?: HTMLElement;
|
||||||
|
menuClassName?: string;
|
||||||
}>
|
}>
|
||||||
> = ({ className, menuPortalTarget, children }) => {
|
> = ({ className, menuPortalTarget, menuClassName, children }) => {
|
||||||
if (!children) return null;
|
if (!children) return null;
|
||||||
|
|
||||||
const menu = (
|
const menu = (
|
||||||
<Dropdown.Menu className="bg-secondary text-white">
|
<Dropdown.Menu className={cx("bg-secondary text-white", menuClassName)}>
|
||||||
{children}
|
{children}
|
||||||
</Dropdown.Menu>
|
</Dropdown.Menu>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
|
||||||
import { Pagination, PaginationIndex } from "../List/Pagination";
|
|
||||||
import { ButtonToolbar } from "react-bootstrap";
|
|
||||||
import { ListViewOptions } from "../List/ListViewOptions";
|
|
||||||
import { PageSizeSelector, SortBySelect } from "../List/ListFilter";
|
|
||||||
import cx from "classnames";
|
|
||||||
|
|
||||||
export const ListResultsHeader: React.FC<{
|
|
||||||
className?: string;
|
|
||||||
loading: boolean;
|
|
||||||
filter: ListFilterModel;
|
|
||||||
totalCount: number;
|
|
||||||
metadataByline?: React.ReactNode;
|
|
||||||
onChangeFilter: (filter: ListFilterModel) => void;
|
|
||||||
}> = ({
|
|
||||||
className,
|
|
||||||
loading,
|
|
||||||
filter,
|
|
||||||
totalCount,
|
|
||||||
metadataByline,
|
|
||||||
onChangeFilter,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<ButtonToolbar className={cx(className, "list-results-header")}>
|
|
||||||
<div>
|
|
||||||
<SortBySelect
|
|
||||||
options={filter.options.sortByOptions}
|
|
||||||
sortBy={filter.sortBy}
|
|
||||||
sortDirection={filter.sortDirection}
|
|
||||||
onChangeSortBy={(s) =>
|
|
||||||
onChangeFilter(filter.setSortBy(s ?? undefined))
|
|
||||||
}
|
|
||||||
onChangeSortDirection={() =>
|
|
||||||
onChangeFilter(filter.toggleSortDirection())
|
|
||||||
}
|
|
||||||
onReshuffleRandomSort={() =>
|
|
||||||
onChangeFilter(filter.reshuffleRandomSort())
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<PageSizeSelector
|
|
||||||
pageSize={filter.itemsPerPage}
|
|
||||||
setPageSize={(s) => onChangeFilter(filter.setPageSize(s))}
|
|
||||||
/>
|
|
||||||
<ListViewOptions
|
|
||||||
displayMode={filter.displayMode}
|
|
||||||
zoomIndex={filter.zoomIndex}
|
|
||||||
displayModeOptions={filter.options.displayModeOptions}
|
|
||||||
onSetDisplayMode={(mode) =>
|
|
||||||
onChangeFilter(filter.setDisplayMode(mode))
|
|
||||||
}
|
|
||||||
onSetZoom={(zoom) => onChangeFilter(filter.setZoom(zoom))}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="pagination-index-container">
|
|
||||||
<Pagination
|
|
||||||
currentPage={filter.currentPage}
|
|
||||||
itemsPerPage={filter.itemsPerPage}
|
|
||||||
totalItems={totalCount}
|
|
||||||
onChangePage={(page) => onChangeFilter(filter.changePage(page))}
|
|
||||||
/>
|
|
||||||
<PaginationIndex
|
|
||||||
loading={loading}
|
|
||||||
itemsPerPage={filter.itemsPerPage}
|
|
||||||
currentPage={filter.currentPage}
|
|
||||||
totalItems={totalCount}
|
|
||||||
metadataByline={metadataByline}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="empty-space"></div>
|
|
||||||
</ButtonToolbar>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,141 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
|
||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
|
||||||
import { faTimes } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { FilterTags } from "../List/FilterTags";
|
|
||||||
import cx from "classnames";
|
|
||||||
import { Button, ButtonGroup, ButtonToolbar } from "react-bootstrap";
|
|
||||||
import { FilterButton } from "../List/Filters/FilterButton";
|
|
||||||
import { Icon } from "../Shared/Icon";
|
|
||||||
import { SearchTermInput } from "../List/ListFilter";
|
|
||||||
import { Criterion } from "src/models/list-filter/criteria/criterion";
|
|
||||||
import { SidebarToggleButton } from "../Shared/Sidebar";
|
|
||||||
import { PatchComponent } from "src/patch";
|
|
||||||
import { SavedFilterDropdown } from "./SavedFilterList";
|
|
||||||
import { View } from "./views";
|
|
||||||
|
|
||||||
export const ToolbarFilterSection: React.FC<{
|
|
||||||
filter: ListFilterModel;
|
|
||||||
onToggleSidebar: () => void;
|
|
||||||
onSetFilter: (filter: ListFilterModel) => void;
|
|
||||||
onEditCriterion: (c?: Criterion) => void;
|
|
||||||
onRemoveCriterion: (criterion: Criterion, valueIndex?: number) => void;
|
|
||||||
onRemoveAllCriterion: () => void;
|
|
||||||
onEditSearchTerm: () => void;
|
|
||||||
onRemoveSearchTerm: () => void;
|
|
||||||
view?: View;
|
|
||||||
}> = PatchComponent(
|
|
||||||
"ToolbarFilterSection",
|
|
||||||
({
|
|
||||||
filter,
|
|
||||||
onToggleSidebar,
|
|
||||||
onSetFilter,
|
|
||||||
onEditCriterion,
|
|
||||||
onRemoveCriterion,
|
|
||||||
onRemoveAllCriterion,
|
|
||||||
onEditSearchTerm,
|
|
||||||
onRemoveSearchTerm,
|
|
||||||
view,
|
|
||||||
}) => {
|
|
||||||
const { criteria, searchTerm } = filter;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="search-container">
|
|
||||||
<SearchTermInput filter={filter} onFilterUpdate={onSetFilter} />
|
|
||||||
</div>
|
|
||||||
<div className="filter-section">
|
|
||||||
<ButtonGroup>
|
|
||||||
<SidebarToggleButton onClick={onToggleSidebar} />
|
|
||||||
<SavedFilterDropdown
|
|
||||||
filter={filter}
|
|
||||||
onSetFilter={onSetFilter}
|
|
||||||
view={view}
|
|
||||||
menuPortalTarget={document.body}
|
|
||||||
/>
|
|
||||||
<FilterButton
|
|
||||||
onClick={() => onEditCriterion()}
|
|
||||||
count={criteria.length}
|
|
||||||
/>
|
|
||||||
</ButtonGroup>
|
|
||||||
<FilterTags
|
|
||||||
searchTerm={searchTerm}
|
|
||||||
criteria={criteria}
|
|
||||||
onEditCriterion={onEditCriterion}
|
|
||||||
onRemoveCriterion={onRemoveCriterion}
|
|
||||||
onRemoveAll={onRemoveAllCriterion}
|
|
||||||
onEditSearchTerm={onEditSearchTerm}
|
|
||||||
onRemoveSearchTerm={onRemoveSearchTerm}
|
|
||||||
truncateOnOverflow
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
export const ToolbarSelectionSection: React.FC<{
|
|
||||||
selected: number;
|
|
||||||
onToggleSidebar: () => void;
|
|
||||||
operations?: React.ReactNode;
|
|
||||||
onSelectAll: () => void;
|
|
||||||
onSelectNone: () => void;
|
|
||||||
}> = PatchComponent(
|
|
||||||
"ToolbarSelectionSection",
|
|
||||||
({ selected, onToggleSidebar, operations, onSelectAll, onSelectNone }) => {
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="toolbar-selection-section">
|
|
||||||
<div className="selected-items-info">
|
|
||||||
<SidebarToggleButton onClick={onToggleSidebar} />
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
className="minimal"
|
|
||||||
onClick={() => onSelectNone()}
|
|
||||||
title={intl.formatMessage({ id: "actions.select_none" })}
|
|
||||||
>
|
|
||||||
<Icon icon={faTimes} />
|
|
||||||
</Button>
|
|
||||||
<span>{selected} selected</span>
|
|
||||||
<Button variant="link" onClick={() => onSelectAll()}>
|
|
||||||
<FormattedMessage id="actions.select_all" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
{operations}
|
|
||||||
<div className="empty-space" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO - rename to FilteredListToolbar once all list components have been updated
|
|
||||||
// TODO - and expose to plugins
|
|
||||||
export const FilteredListToolbar2: React.FC<{
|
|
||||||
className?: string;
|
|
||||||
hasSelection: boolean;
|
|
||||||
filterSection: React.ReactNode;
|
|
||||||
selectionSection: React.ReactNode;
|
|
||||||
operationSection: React.ReactNode;
|
|
||||||
}> = ({
|
|
||||||
className,
|
|
||||||
hasSelection,
|
|
||||||
filterSection,
|
|
||||||
selectionSection,
|
|
||||||
operationSection,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<ButtonToolbar
|
|
||||||
className={cx(className, "filtered-list-toolbar", {
|
|
||||||
"has-selection": hasSelection,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{!hasSelection ? filterSection : selectionSection}
|
|
||||||
{!hasSelection ? (
|
|
||||||
<div className="filtered-list-toolbar-operations">
|
|
||||||
{operationSection}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
</ButtonToolbar>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -948,14 +948,6 @@ input[type="range"].zoom-slider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-pane .filtered-list-toolbar {
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
|
|
||||||
& > .btn-group {
|
|
||||||
align-items: baseline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.custom-field-filter {
|
.custom-field-filter {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -987,14 +979,6 @@ input[type="range"].zoom-slider {
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
// make controls slightly larger on mobile
|
|
||||||
@include media-breakpoint-down(xs) {
|
|
||||||
.btn,
|
|
||||||
.form-control {
|
|
||||||
font-size: 1.25rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-search-container {
|
.sidebar-search-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
|
@ -1033,18 +1017,22 @@ input[type="range"].zoom-slider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination-footer {
|
.pagination-footer-container {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
bottom: $navbar-height;
|
bottom: $navbar-height;
|
||||||
margin: auto;
|
|
||||||
padding: 0.5rem 1rem 0.75rem;
|
|
||||||
position: sticky;
|
position: sticky;
|
||||||
width: fit-content;
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
||||||
@include media-breakpoint-up(sm) {
|
@include media-breakpoint-up(sm) {
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-footer {
|
||||||
|
margin: auto;
|
||||||
|
padding: 0.5rem 1rem 0.75rem;
|
||||||
|
|
||||||
|
width: fit-content;
|
||||||
|
|
||||||
.pagination.btn-group {
|
.pagination.btn-group {
|
||||||
box-shadow: 0 8px 10px 2px rgb(0 0 0 / 30%);
|
box-shadow: 0 8px 10px 2px rgb(0 0 0 / 30%);
|
||||||
|
|
@ -1060,6 +1048,18 @@ input[type="range"].zoom-slider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// on very large screens, offset the margins to center the pagination controls
|
||||||
|
@media (min-width: 1800px) {
|
||||||
|
.sidebar-pane:not(.hide-sidebar) {
|
||||||
|
.filter-tags,
|
||||||
|
.pagination-index-container,
|
||||||
|
.pagination-footer-container {
|
||||||
|
margin-left: -$sidebar-width;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// hide sidebar Edit Filter button on larger screens
|
// hide sidebar Edit Filter button on larger screens
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
.sidebar .edit-filter-button {
|
.sidebar .edit-filter-button {
|
||||||
|
|
@ -1067,232 +1067,11 @@ input[type="range"].zoom-slider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// the following refers to the new FilteredListToolbar2 component
|
// hide the search input field if the sidebar is open on smaller screens
|
||||||
// ensure the rules here don't conflict with the original filtered-list-toolbar above
|
@media (min-width: 576px) and (max-width: 1400px) {
|
||||||
// TODO - replace with only .filtered-list-toolbar once all lists use the new toolbar
|
.sidebar-pane:not(.hide-sidebar) .filtered-list-toolbar .search-term-input {
|
||||||
.scene-list-toolbar {
|
|
||||||
&.filtered-list-toolbar {
|
|
||||||
align-items: center;
|
|
||||||
background-color: $body-bg;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 0;
|
|
||||||
row-gap: 1rem;
|
|
||||||
|
|
||||||
> div {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
gap: 0.5rem;
|
|
||||||
justify-content: flex-start;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
flex-shrink: 0;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.filtered-list-toolbar {
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
gap: 1rem;
|
|
||||||
position: sticky;
|
|
||||||
top: $navbar-height;
|
|
||||||
z-index: 10;
|
|
||||||
|
|
||||||
@include media-breakpoint-down(xs) {
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hide drop down menu items for play and create new
|
|
||||||
// when the buttons are visible
|
|
||||||
@include media-breakpoint-up(sm) {
|
|
||||||
.scene-list-operations {
|
|
||||||
.play-item,
|
|
||||||
.create-new-item {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hide play and create new buttons on xs screens
|
|
||||||
// show these in the drop down menu instead
|
|
||||||
@include media-breakpoint-down(xs) {
|
|
||||||
.play-button,
|
|
||||||
.create-new-button {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-selection-section,
|
|
||||||
div.filter-section {
|
|
||||||
border: 1px solid $secondary;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.toolbar-selection-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.sidebar-toggle-button {
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div:first-child,
|
|
||||||
> div:last-child {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div:last-child {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scene-list-operations {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// on smaller viewports move the operation buttons to the right
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
div.scene-list-operations {
|
|
||||||
flex: 1;
|
|
||||||
justify-content: flex-end;
|
|
||||||
order: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div:last-child {
|
|
||||||
flex: 0;
|
|
||||||
order: 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// on larger viewports, move the operation buttons to the center
|
|
||||||
@include media-breakpoint-up(lg) {
|
|
||||||
div.toolbar-selection-section div.scene-list-operations {
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
> .btn-group {
|
|
||||||
gap: 0.5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.toolbar-selection-section .empty-space {
|
|
||||||
flex: 1;
|
|
||||||
order: 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-container {
|
|
||||||
border-right: 1px solid $secondary;
|
|
||||||
display: flex;
|
|
||||||
margin-right: -0.5rem;
|
|
||||||
min-width: calc($sidebar-width - 15px);
|
|
||||||
padding-right: 10px;
|
|
||||||
|
|
||||||
.search-term-input {
|
|
||||||
margin-right: 0;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.clearable-text-field {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-tags {
|
|
||||||
flex-grow: 1;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
justify-content: flex-start;
|
|
||||||
margin-bottom: 0;
|
|
||||||
|
|
||||||
// account for filter button, and toggle sidebar buttons with gaps
|
|
||||||
width: calc(100% - 70px - 1rem);
|
|
||||||
|
|
||||||
@include media-breakpoint-down(xs) {
|
|
||||||
overflow-x: auto;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag-item {
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hide the search box in the toolbar when sidebar is shown on larger screens
|
|
||||||
// larger screens don't overlap the sidebar
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
.sidebar-pane:not(.hide-sidebar) .filtered-list-toolbar .search-container {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// hide the search box when sidebar is hidden on smaller screens
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
.sidebar-pane.hide-sidebar .filtered-list-toolbar .search-container {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hide the filter and saved filters icon buttons when sidebar is shown on smaller screens
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
.sidebar-pane:not(.hide-sidebar) .filtered-list-toolbar {
|
|
||||||
.filter-button,
|
|
||||||
.saved-filter-dropdown {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust the width of the filter-tags as well
|
|
||||||
.sidebar-pane:not(.hide-sidebar) .filtered-list-toolbar .filter-tags {
|
|
||||||
width: calc(100% - 35px - 0.5rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// move the sidebar toggle to the left on larger viewports
|
|
||||||
@include media-breakpoint-up(md) {
|
|
||||||
.filtered-list-toolbar .filter-section {
|
|
||||||
.sidebar-toggle-button {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-tags {
|
|
||||||
order: 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hide the search term tag item when the search box is visible
|
|
||||||
@include media-breakpoint-up(lg) {
|
|
||||||
// TODO - remove scene-list-toolbar when all lists use the new toolbar
|
|
||||||
.scene-list-toolbar.filtered-list-toolbar
|
|
||||||
.filter-tags
|
|
||||||
.search-term-filter-tag {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
// TODO - remove scene-list-toolbar when all lists use the new toolbar
|
|
||||||
.sidebar-pane:not(.hide-sidebar)
|
|
||||||
.scene-list-toolbar.filtered-list-toolbar
|
|
||||||
.filter-tags
|
|
||||||
.search-term-filter-tag {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO - remove scene-list-toolbar when all lists use the new toolbar
|
|
||||||
.detail-body .scene-list-toolbar.filtered-list-toolbar {
|
|
||||||
top: calc($sticky-detail-header-height + $navbar-height);
|
|
||||||
|
|
||||||
@include media-breakpoint-down(xs) {
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#more-criteria-popover {
|
#more-criteria-popover {
|
||||||
|
|
@ -1301,103 +1080,6 @@ input[type="range"].zoom-slider {
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-results-header {
|
|
||||||
align-items: flex-start;
|
|
||||||
background-color: $body-bg;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
> div {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
gap: 0.5rem;
|
|
||||||
justify-content: flex-start;
|
|
||||||
|
|
||||||
&.pagination-index-container {
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
flex-shrink: 0;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-results-header .pagination-index-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.5rem;
|
|
||||||
|
|
||||||
.pagination {
|
|
||||||
// hidden by default. Can be shown via css override if needed
|
|
||||||
display: none;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-results-header {
|
|
||||||
gap: 0.25rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
|
|
||||||
.paginationIndex {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// move pagination info to right on medium screens
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
& > .empty-space {
|
|
||||||
flex: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > div.pagination-index-container {
|
|
||||||
align-items: flex-end;
|
|
||||||
order: 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// center the header on smaller screens
|
|
||||||
@include media-breakpoint-down(sm) {
|
|
||||||
& > div,
|
|
||||||
& > div.pagination-index-container {
|
|
||||||
flex-basis: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > div.pagination-index-container {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sidebar visible styling
|
|
||||||
.sidebar-pane:not(.hide-sidebar) .list-results-header {
|
|
||||||
// move pagination info to right on medium screens when sidebar
|
|
||||||
@include media-breakpoint-down(lg) {
|
|
||||||
& > .empty-space {
|
|
||||||
flex: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > div.pagination-index-container {
|
|
||||||
justify-content: flex-end;
|
|
||||||
order: 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// center the header on smaller screens when sidebar is visible
|
|
||||||
@include media-breakpoint-down(md) {
|
|
||||||
& > div,
|
|
||||||
& > div.pagination-index-container {
|
|
||||||
flex-basis: 100%;
|
|
||||||
justify-content: center;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Duration slider styles
|
// Duration slider styles
|
||||||
.duration-slider,
|
.duration-slider,
|
||||||
.age-slider-container {
|
.age-slider-container {
|
||||||
|
|
@ -1442,7 +1124,23 @@ input[type="range"].zoom-slider {
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-list-container > .filtered-list-toolbar.has-selection {
|
// modify margins for toolbar within sidebar pane to accommodate toggle button
|
||||||
|
.sidebar-pane .filtered-list-toolbar {
|
||||||
|
margin-left: 40px;
|
||||||
|
margin-right: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// on very large screens, offset the margins to center the toolbar
|
||||||
|
@media (min-width: 1800px) {
|
||||||
|
.sidebar-pane:not(.hide-sidebar) {
|
||||||
|
.filtered-list-toolbar {
|
||||||
|
margin-left: -$sidebar-width;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-list-container .filtered-list-toolbar.has-selection {
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
|
|
||||||
|
|
@ -67,17 +67,13 @@ import {
|
||||||
useFilteredSidebarKeybinds,
|
useFilteredSidebarKeybinds,
|
||||||
} from "../List/Filters/FilterSidebar";
|
} from "../List/Filters/FilterSidebar";
|
||||||
import { PatchContainerComponent } from "src/patch";
|
import { PatchContainerComponent } from "src/patch";
|
||||||
import { Pagination } from "../List/Pagination";
|
import { Pagination, PaginationIndex } from "../List/Pagination";
|
||||||
import { Button, ButtonGroup } from "react-bootstrap";
|
import { Button, ButtonGroup } from "react-bootstrap";
|
||||||
import { Icon } from "../Shared/Icon";
|
import { Icon } from "../Shared/Icon";
|
||||||
import useFocus from "src/utils/focus";
|
import useFocus from "src/utils/focus";
|
||||||
import {
|
|
||||||
FilteredListToolbar2,
|
|
||||||
ToolbarFilterSection,
|
|
||||||
ToolbarSelectionSection,
|
|
||||||
} from "../List/ListToolbar";
|
|
||||||
import { ListResultsHeader } from "../List/ListResultsHeader";
|
|
||||||
import { useZoomKeybinds } from "../List/ZoomSlider";
|
import { useZoomKeybinds } from "../List/ZoomSlider";
|
||||||
|
import { FilteredListToolbar } from "../List/FilteredListToolbar";
|
||||||
|
import { FilterTags } from "../List/FilterTags";
|
||||||
|
|
||||||
function renderMetadataByline(result: GQL.FindScenesQueryResult) {
|
function renderMetadataByline(result: GQL.FindScenesQueryResult) {
|
||||||
const duration = result?.data?.findScenes?.duration;
|
const duration = result?.data?.findScenes?.duration;
|
||||||
|
|
@ -439,6 +435,7 @@ const SceneListOperations: React.FC<{
|
||||||
|
|
||||||
<OperationDropdown
|
<OperationDropdown
|
||||||
className="scene-list-operations"
|
className="scene-list-operations"
|
||||||
|
menuClassName="scene-list-operations-dropdown"
|
||||||
menuPortalTarget={document.body}
|
menuPortalTarget={document.body}
|
||||||
>
|
>
|
||||||
{operations.map((o) => {
|
{operations.map((o) => {
|
||||||
|
|
@ -474,7 +471,6 @@ export const FilteredSceneList = (props: IFilteredScenes) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const searchFocus = useFocus();
|
const searchFocus = useFocus();
|
||||||
const [, setSearchFocus] = searchFocus;
|
|
||||||
|
|
||||||
const { filterHook, defaultSort, view, alterQuery, fromGroupId } = props;
|
const { filterHook, defaultSort, view, alterQuery, fromGroupId } = props;
|
||||||
|
|
||||||
|
|
@ -752,50 +748,44 @@ export const FilteredSceneList = (props: IFilteredScenes) => {
|
||||||
focus={searchFocus}
|
focus={searchFocus}
|
||||||
/>
|
/>
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
<SidebarPaneContent>
|
<SidebarPaneContent
|
||||||
<FilteredListToolbar2
|
onSidebarToggle={() => setShowSidebar(!showSidebar)}
|
||||||
className="scene-list-toolbar"
|
>
|
||||||
hasSelection={hasSelection}
|
<FilteredListToolbar
|
||||||
filterSection={
|
|
||||||
<ToolbarFilterSection
|
|
||||||
filter={filter}
|
filter={filter}
|
||||||
onSetFilter={setFilter}
|
listSelect={listSelect}
|
||||||
onToggleSidebar={() => setShowSidebar(!showSidebar)}
|
setFilter={setFilter}
|
||||||
onEditCriterion={(c) =>
|
showEditFilter={showEditFilter}
|
||||||
showEditFilter(c?.criterionOption.type)
|
onDelete={onDelete}
|
||||||
}
|
onEdit={onEdit}
|
||||||
onRemoveCriterion={removeCriterion}
|
operationComponent={operations}
|
||||||
onRemoveAllCriterion={() => clearAllCriteria(true)}
|
|
||||||
onEditSearchTerm={() => {
|
|
||||||
setShowSidebar(true);
|
|
||||||
setSearchFocus(true);
|
|
||||||
}}
|
|
||||||
onRemoveSearchTerm={() =>
|
|
||||||
setFilter(filter.clearSearchTerm())
|
|
||||||
}
|
|
||||||
view={view}
|
view={view}
|
||||||
/>
|
zoomable
|
||||||
}
|
|
||||||
selectionSection={
|
|
||||||
<ToolbarSelectionSection
|
|
||||||
selected={selectedIds.size}
|
|
||||||
onToggleSidebar={() => setShowSidebar(!showSidebar)}
|
|
||||||
onSelectAll={() => onSelectAll()}
|
|
||||||
onSelectNone={() => onSelectNone()}
|
|
||||||
operations={operations}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
operationSection={operations}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ListResultsHeader
|
<FilterTags
|
||||||
loading={cachedResult.loading}
|
criteria={filter.criteria}
|
||||||
filter={filter}
|
onEditCriterion={(c) => showEditFilter(c.criterionOption.type)}
|
||||||
totalCount={totalCount}
|
onRemoveCriterion={removeCriterion}
|
||||||
metadataByline={metadataByline}
|
onRemoveAll={clearAllCriteria}
|
||||||
onChangeFilter={(newFilter) => setFilter(newFilter)}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div className="pagination-index-container">
|
||||||
|
<Pagination
|
||||||
|
currentPage={filter.currentPage}
|
||||||
|
itemsPerPage={filter.itemsPerPage}
|
||||||
|
totalItems={totalCount}
|
||||||
|
onChangePage={(page) => setFilter(filter.changePage(page))}
|
||||||
|
/>
|
||||||
|
<PaginationIndex
|
||||||
|
loading={cachedResult.loading}
|
||||||
|
itemsPerPage={filter.itemsPerPage}
|
||||||
|
currentPage={filter.currentPage}
|
||||||
|
totalItems={totalCount}
|
||||||
|
metadataByline={metadataByline}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<LoadedContent loading={result.loading} error={result.error}>
|
<LoadedContent loading={result.loading} error={result.error}>
|
||||||
<SceneList
|
<SceneList
|
||||||
filter={effectiveFilter}
|
filter={effectiveFilter}
|
||||||
|
|
@ -807,6 +797,7 @@ export const FilteredSceneList = (props: IFilteredScenes) => {
|
||||||
</LoadedContent>
|
</LoadedContent>
|
||||||
|
|
||||||
{totalCount > filter.itemsPerPage && (
|
{totalCount > filter.itemsPerPage && (
|
||||||
|
<div className="pagination-footer-container">
|
||||||
<div className="pagination-footer">
|
<div className="pagination-footer">
|
||||||
<Pagination
|
<Pagination
|
||||||
itemsPerPage={filter.itemsPerPage}
|
itemsPerPage={filter.itemsPerPage}
|
||||||
|
|
@ -817,6 +808,7 @@ export const FilteredSceneList = (props: IFilteredScenes) => {
|
||||||
pagePopupPlacement="top"
|
pagePopupPlacement="top"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</SidebarPaneContent>
|
</SidebarPaneContent>
|
||||||
</SidebarPane>
|
</SidebarPane>
|
||||||
|
|
|
||||||
|
|
@ -964,3 +964,25 @@ input[type="range"].blue-slider {
|
||||||
// TODO - this will need to be rolled out to other tables
|
// TODO - this will need to be rolled out to other tables
|
||||||
max-height: calc(100dvh - 210px);
|
max-height: calc(100dvh - 210px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scene-list .filtered-list-toolbar {
|
||||||
|
// hide play and create new buttons on xs screens
|
||||||
|
// show these in the drop down menu instead
|
||||||
|
@include media-breakpoint-down(xs) {
|
||||||
|
.play-button,
|
||||||
|
.create-new-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// hide drop down menu items for play and create new
|
||||||
|
// when the buttons are visible
|
||||||
|
@include media-breakpoint-up(sm) {
|
||||||
|
.scene-list-operations-dropdown {
|
||||||
|
.dropdown-item.play-item,
|
||||||
|
.dropdown-item.create-new-item {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,34 @@ export const SidebarPane: React.FC<
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SidebarPaneContent: React.FC = ({ children }) => {
|
export const SidebarToggleButton: React.FC<{
|
||||||
return <div className="sidebar-pane-content">{children}</div>;
|
onClick: () => void;
|
||||||
|
}> = ({ onClick }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
return (
|
||||||
|
<div className="sidebar-toggle-button-container">
|
||||||
|
<Button
|
||||||
|
className="sidebar-toggle-button ignore-sidebar-outside-click minimal"
|
||||||
|
variant="secondary"
|
||||||
|
onClick={onClick}
|
||||||
|
title={intl.formatMessage({ id: "actions.sidebar.toggle" })}
|
||||||
|
>
|
||||||
|
<Icon icon={faSliders} />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SidebarPaneContent: React.FC<{ onSidebarToggle: () => void }> = ({
|
||||||
|
onSidebarToggle,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className="sidebar-pane-content">
|
||||||
|
<SidebarToggleButton onClick={onSidebarToggle} />
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IContext {
|
interface IContext {
|
||||||
|
|
@ -125,22 +151,6 @@ export const SidebarSection: React.FC<
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SidebarToggleButton: React.FC<{
|
|
||||||
onClick: () => void;
|
|
||||||
}> = ({ onClick }) => {
|
|
||||||
const intl = useIntl();
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
className="sidebar-toggle-button ignore-sidebar-outside-click"
|
|
||||||
variant="secondary"
|
|
||||||
onClick={onClick}
|
|
||||||
title={intl.formatMessage({ id: "actions.sidebar.toggle" })}
|
|
||||||
>
|
|
||||||
<Icon icon={faSliders} />
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// show sidebar by default if not on mobile
|
// show sidebar by default if not on mobile
|
||||||
export function defaultShowSidebar() {
|
export function defaultShowSidebar() {
|
||||||
return !ScreenUtils.matchesMediaQuery(fixedSidebarMediaQuery);
|
return !ScreenUtils.matchesMediaQuery(fixedSidebarMediaQuery);
|
||||||
|
|
|
||||||
|
|
@ -815,21 +815,6 @@ button.btn.favorite-button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@include media-breakpoint-down(xs) {
|
@include media-breakpoint-down(xs) {
|
||||||
.sidebar {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hide-sidebar .sidebar {
|
|
||||||
margin-left: -100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hide-sidebar > :nth-child(2) {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@include media-breakpoint-down(xs) {
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
margin-bottom: $navbar-height;
|
margin-bottom: $navbar-height;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
|
@ -837,6 +822,36 @@ button.btn.favorite-button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sidebar-toggle-button-container {
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
.sidebar-toggle-button {
|
||||||
|
border-bottom: 1px solid $secondary;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
border-bottom-right-radius: 10px;
|
||||||
|
border-right: 1px solid $secondary;
|
||||||
|
border-top: 1px solid $secondary;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
margin-left: -15px;
|
||||||
|
opacity: 0.5;
|
||||||
|
position: sticky;
|
||||||
|
top: calc($navbar-height + 0.5rem);
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
top: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-pane:not(.hide-sidebar) .sidebar-toggle-button-container {
|
||||||
|
.sidebar-toggle-button {
|
||||||
|
margin-left: -0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-toolbar {
|
.sidebar-toolbar {
|
||||||
// TODO - use different colours for sidebar and toolbar
|
// TODO - use different colours for sidebar and toolbar
|
||||||
background-color: $body-bg;
|
background-color: $body-bg;
|
||||||
|
|
@ -884,6 +899,14 @@ button.btn.favorite-button {
|
||||||
$sticky-header-height: calc(50px + 3.3rem);
|
$sticky-header-height: calc(50px + 3.3rem);
|
||||||
|
|
||||||
// special case for sidebar in details view
|
// special case for sidebar in details view
|
||||||
|
.detail-body .sidebar-toggle-button-container .sidebar-toggle-button {
|
||||||
|
top: calc($sticky-header-height + 0.5rem);
|
||||||
|
|
||||||
|
@include media-breakpoint-down(sm) {
|
||||||
|
top: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.detail-body {
|
.detail-body {
|
||||||
.sidebar {
|
.sidebar {
|
||||||
// required for sticky to work
|
// required for sticky to work
|
||||||
|
|
@ -921,19 +944,11 @@ $sticky-header-height: calc(50px + 3.3rem);
|
||||||
}
|
}
|
||||||
@include media-breakpoint-down(xs) {
|
@include media-breakpoint-down(xs) {
|
||||||
.sidebar {
|
.sidebar {
|
||||||
flex: 100% 0 0;
|
// flex: 100% 0 0;
|
||||||
height: calc(100vh - 4rem);
|
height: calc(100vh - $navbar-height);
|
||||||
max-height: calc(100vh - 4rem);
|
max-height: calc(100vh - $navbar-height);
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-pane:not(.hide-sidebar) .sidebar {
|
|
||||||
margin-right: -100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-pane.hide-sidebar .sidebar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@include media-breakpoint-up(md) {
|
@include media-breakpoint-up(md) {
|
||||||
.sidebar-pane:not(.hide-sidebar) {
|
.sidebar-pane:not(.hide-sidebar) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue