mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Styling
This commit is contained in:
@@ -31,8 +31,6 @@ module.exports = merge(commonConfig, {
|
|||||||
compress: true,
|
compress: true,
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0',
|
||||||
hot: true, // enable HMR on the server host: '0.0.0.0',
|
hot: true, // enable HMR on the server host: '0.0.0.0',
|
||||||
transportMode: 'ws',
|
|
||||||
injectClient: false,
|
|
||||||
port: process.env.PORT,
|
port: process.env.PORT,
|
||||||
historyApiFallback: true,
|
historyApiFallback: true,
|
||||||
stats: {
|
stats: {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Spinner } from "react-bootstrap";
|
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
|
import { LoadingIndicator } from 'src/components/Shared';
|
||||||
import { GalleryViewer } from "./GalleryViewer";
|
import { GalleryViewer } from "./GalleryViewer";
|
||||||
|
|
||||||
export const Gallery: React.FC = () => {
|
export const Gallery: React.FC = () => {
|
||||||
@@ -11,7 +11,7 @@ export const Gallery: React.FC = () => {
|
|||||||
const gallery = data?.findGallery;
|
const gallery = data?.findGallery;
|
||||||
|
|
||||||
if (loading || !gallery)
|
if (loading || !gallery)
|
||||||
return <Spinner animation="border" variant="light" />;
|
return <LoadingIndicator />;
|
||||||
if (error) return <div>{error.message}</div>;
|
if (error) return <div>{error.message}</div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export const MainNavbar: React.FC = () => {
|
|||||||
<Navbar fixed="top" variant="dark" bg="dark">
|
<Navbar fixed="top" variant="dark" bg="dark">
|
||||||
<Navbar.Brand as="div">
|
<Navbar.Brand as="div">
|
||||||
<Link to="/">
|
<Link to="/">
|
||||||
<Button variant="secondary">Stash</Button>
|
<Button className="minimal">Stash</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</Navbar.Brand>
|
</Navbar.Brand>
|
||||||
<Nav className="mr-auto">
|
<Nav className="mr-auto">
|
||||||
@@ -78,7 +78,7 @@ export const MainNavbar: React.FC = () => {
|
|||||||
to={i.href}
|
to={i.href}
|
||||||
key={i.href}
|
key={i.href}
|
||||||
>
|
>
|
||||||
<Button variant="secondary">
|
<Button className="minimal">
|
||||||
<Icon icon={i.icon} />
|
<Icon icon={i.icon} />
|
||||||
{i.text}
|
{i.text}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -88,7 +88,7 @@ export const MainNavbar: React.FC = () => {
|
|||||||
<Nav>
|
<Nav>
|
||||||
{newButton}
|
{newButton}
|
||||||
<LinkContainer exact to="/settings">
|
<LinkContainer exact to="/settings">
|
||||||
<Button variant="secondary">
|
<Button className="minimal">
|
||||||
<Icon icon="cog" />
|
<Icon icon="cog" />
|
||||||
</Button>
|
</Button>
|
||||||
</LinkContainer>
|
</LinkContainer>
|
||||||
|
|||||||
@@ -17,11 +17,13 @@ interface ITypeProps {
|
|||||||
type?: "performers" | "studios" | "tags";
|
type?: "performers" | "studios" | "tags";
|
||||||
}
|
}
|
||||||
interface IFilterProps {
|
interface IFilterProps {
|
||||||
initialIds: string[];
|
ids?: string[];
|
||||||
|
initialIds?: string[];
|
||||||
onSelect: (item: ValidTypes[]) => void;
|
onSelect: (item: ValidTypes[]) => void;
|
||||||
noSelectionString?: string;
|
noSelectionString?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
isMulti?: boolean;
|
isMulti?: boolean;
|
||||||
|
isClearable?: boolean;
|
||||||
}
|
}
|
||||||
interface ISelectProps {
|
interface ISelectProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
@@ -31,8 +33,9 @@ interface ISelectProps {
|
|||||||
onCreateOption?: (value: string) => void;
|
onCreateOption?: (value: string) => void;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
onChange: (item: ValueType<Option>) => void;
|
onChange: (item: ValueType<Option>) => void;
|
||||||
initialIds: string[];
|
initialIds?: string[];
|
||||||
isMulti?: boolean;
|
isMulti?: boolean;
|
||||||
|
isClearable?: boolean,
|
||||||
onInputChange?: (input: string) => void;
|
onInputChange?: (input: string) => void;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
}
|
}
|
||||||
@@ -48,9 +51,10 @@ interface ISceneGallerySelect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getSelectedValues = (selectedItems: ValueType<Option>) =>
|
const getSelectedValues = (selectedItems: ValueType<Option>) =>
|
||||||
|
selectedItems ?
|
||||||
(Array.isArray(selectedItems) ? selectedItems : [selectedItems]).map(
|
(Array.isArray(selectedItems) ? selectedItems : [selectedItems]).map(
|
||||||
item => item.value
|
item => item.value
|
||||||
);
|
) : [];
|
||||||
|
|
||||||
export const SceneGallerySelect: React.FC<ISceneGallerySelect> = props => {
|
export const SceneGallerySelect: React.FC<ISceneGallerySelect> = props => {
|
||||||
const { data, loading } = StashService.useValidGalleriesForScene(
|
const { data, loading } = StashService.useValidGalleriesForScene(
|
||||||
@@ -165,6 +169,8 @@ export const PerformerSelect: React.FC<IFilterProps> = props => {
|
|||||||
label: item.name ?? ""
|
label: item.name ?? ""
|
||||||
}));
|
}));
|
||||||
const placeholder = props.noSelectionString ?? "Select performer...";
|
const placeholder = props.noSelectionString ?? "Select performer...";
|
||||||
|
const selectedOptions:Option[] = props.ids ?
|
||||||
|
items.filter(item => props.ids?.indexOf(item.value) !== -1) : [];
|
||||||
|
|
||||||
const onChange = (selectedItems: ValueType<Option>) => {
|
const onChange = (selectedItems: ValueType<Option>) => {
|
||||||
const selectedIds = getSelectedValues(selectedItems);
|
const selectedIds = getSelectedValues(selectedItems);
|
||||||
@@ -176,6 +182,7 @@ export const PerformerSelect: React.FC<IFilterProps> = props => {
|
|||||||
return (
|
return (
|
||||||
<SelectComponent
|
<SelectComponent
|
||||||
{...props}
|
{...props}
|
||||||
|
selectedOptions={selectedOptions}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
type="performers"
|
type="performers"
|
||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
@@ -194,6 +201,8 @@ export const StudioSelect: React.FC<IFilterProps> = props => {
|
|||||||
label: item.name
|
label: item.name
|
||||||
}));
|
}));
|
||||||
const placeholder = props.noSelectionString ?? "Select studio...";
|
const placeholder = props.noSelectionString ?? "Select studio...";
|
||||||
|
const selectedOptions:Option[] = props.ids ?
|
||||||
|
items.filter(item => props.ids?.indexOf(item.value) !== -1) : [];
|
||||||
|
|
||||||
const onChange = (selectedItems: ValueType<Option>) => {
|
const onChange = (selectedItems: ValueType<Option>) => {
|
||||||
const selectedIds = getSelectedValues(selectedItems);
|
const selectedIds = getSelectedValues(selectedItems);
|
||||||
@@ -210,13 +219,14 @@ export const StudioSelect: React.FC<IFilterProps> = props => {
|
|||||||
isLoading={loading}
|
isLoading={loading}
|
||||||
items={items}
|
items={items}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
|
selectedOptions={selectedOptions}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TagSelect: React.FC<IFilterProps> = props => {
|
export const TagSelect: React.FC<IFilterProps> = props => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
const [selectedIds, setSelectedIds] = useState<string[]>(props.ids ?? []);
|
||||||
const { data, loading: dataLoading } = StashService.useAllTagsForFilter();
|
const { data, loading: dataLoading } = StashService.useAllTagsForFilter();
|
||||||
const [createTag] = StashService.useTagCreate({ name: "" });
|
const [createTag] = StashService.useTagCreate({ name: "" });
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
@@ -290,6 +300,7 @@ const SelectComponent: React.FC<ISelectProps & ITypeProps> = ({
|
|||||||
selectedOptions,
|
selectedOptions,
|
||||||
isLoading,
|
isLoading,
|
||||||
onCreateOption,
|
onCreateOption,
|
||||||
|
isClearable = true,
|
||||||
creatable = false,
|
creatable = false,
|
||||||
isMulti = false,
|
isMulti = false,
|
||||||
onInputChange,
|
onInputChange,
|
||||||
@@ -298,26 +309,58 @@ const SelectComponent: React.FC<ISelectProps & ITypeProps> = ({
|
|||||||
const defaultValue =
|
const defaultValue =
|
||||||
items.filter(item => initialIds?.indexOf(item.value) !== -1) ?? null;
|
items.filter(item => initialIds?.indexOf(item.value) !== -1) ?? null;
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
control: (provided:any) => ({
|
||||||
|
...provided,
|
||||||
|
background: '#394b59',
|
||||||
|
borderColor: 'rgba(16,22,26,.4)'
|
||||||
|
}),
|
||||||
|
singleValue: (provided:any) => ({
|
||||||
|
...provided,
|
||||||
|
color: 'f5f8fa',
|
||||||
|
}),
|
||||||
|
placeholder: (provided:any) => ({
|
||||||
|
...provided,
|
||||||
|
color: 'f5f8fa',
|
||||||
|
}),
|
||||||
|
menu: (provided:any) => ({
|
||||||
|
...provided,
|
||||||
|
color: 'f5f8fa',
|
||||||
|
background: '#394b59',
|
||||||
|
borderColor: 'rgba(16,22,26,.4)',
|
||||||
|
zIndex: 3
|
||||||
|
}),
|
||||||
|
option: (provided:any, state:any ) => (
|
||||||
|
state.isFocused ? { ...provided, backgroundColor: '#137cbd' } : provided
|
||||||
|
),
|
||||||
|
multiValueRemove: (provided:any, state:any) => (
|
||||||
|
{ ...provided, color: 'black' }
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
className,
|
|
||||||
options: items,
|
options: items,
|
||||||
value: selectedOptions,
|
value: selectedOptions,
|
||||||
|
styles,
|
||||||
|
className,
|
||||||
onChange,
|
onChange,
|
||||||
isMulti,
|
isMulti,
|
||||||
|
isClearable,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
noOptionsMessage: () => (type !== "tags" ? "None" : null),
|
noOptionsMessage: () => (type !== "tags" ? "None" : null),
|
||||||
placeholder,
|
placeholder,
|
||||||
onInputChange
|
onInputChange,
|
||||||
|
isLoading,
|
||||||
|
components: { IndicatorSeparator: () => null }
|
||||||
};
|
};
|
||||||
|
|
||||||
return creatable ? (
|
return creatable ? (
|
||||||
<CreatableSelect
|
<CreatableSelect
|
||||||
{...props}
|
{...props}
|
||||||
isLoading={isLoading}
|
|
||||||
isDisabled={isLoading}
|
isDisabled={isLoading}
|
||||||
onCreateOption={onCreateOption}
|
onCreateOption={onCreateOption}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Select {...props} isLoading={isLoading} />
|
<Select {...props} />
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,8 +39,6 @@
|
|||||||
.scene-wall-item-container {
|
.scene-wall-item-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
// align-items: center;
|
|
||||||
// overflow: hidden; // Commented out since it shows gaps in the wall
|
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -62,6 +60,7 @@
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
background: linear-gradient(rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.65));
|
background: linear-gradient(rgba(255, 255, 255, 0.25), rgba(255, 255, 255, 0.65));
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -80,18 +79,17 @@
|
|||||||
left: -5px;
|
left: -5px;
|
||||||
right: -5px;
|
right: -5px;
|
||||||
bottom: -5px;
|
bottom: -5px;
|
||||||
/*background-color: rgba(255, 255, 255, 0.75);*/
|
|
||||||
/*backdrop-filter: blur(5px);*/
|
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wall.grid-item video, .wall.grid-item img {
|
.wall-item video, .wall-item img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wall.grid-item {
|
.wall-item {
|
||||||
|
width: 20%;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React, { FunctionComponent, useRef, useState, useEffect } from "react";
|
import React, { useRef, useState, useEffect } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { StashService } from "src/core/StashService";
|
import { StashService } from "src/core/StashService";
|
||||||
@@ -16,10 +16,10 @@ interface IWallItemProps {
|
|||||||
) => void;
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WallItem: FunctionComponent<IWallItemProps> = (
|
export const WallItem: React.FC<IWallItemProps> = (
|
||||||
props: IWallItemProps
|
props: IWallItemProps
|
||||||
) => {
|
) => {
|
||||||
const [videoPath, setVideoPath] = useState<string | undefined>(undefined);
|
const [videoPath, setVideoPath] = useState<string>();
|
||||||
const [previewPath, setPreviewPath] = useState<string>("");
|
const [previewPath, setPreviewPath] = useState<string>("");
|
||||||
const [screenshotPath, setScreenshotPath] = useState<string>("");
|
const [screenshotPath, setScreenshotPath] = useState<string>("");
|
||||||
const [title, setTitle] = useState<string>("");
|
const [title, setTitle] = useState<string>("");
|
||||||
@@ -28,10 +28,7 @@ export const WallItem: FunctionComponent<IWallItemProps> = (
|
|||||||
const videoHoverHook = VideoHoverHook.useVideoHover({
|
const videoHoverHook = VideoHoverHook.useVideoHover({
|
||||||
resetOnMouseLeave: true
|
resetOnMouseLeave: true
|
||||||
});
|
});
|
||||||
const showTextContainer =
|
const showTextContainer = config.data?.configuration.interface.wallShowTitle ?? true;
|
||||||
!!config.data && !!config.data.configuration
|
|
||||||
? config.data.configuration.interface.wallShowTitle
|
|
||||||
: true;
|
|
||||||
|
|
||||||
function onMouseEnter() {
|
function onMouseEnter() {
|
||||||
VideoHoverHook.onMouseEnter(videoHoverHook);
|
VideoHoverHook.onMouseEnter(videoHoverHook);
|
||||||
@@ -122,7 +119,7 @@ export const WallItem: FunctionComponent<IWallItemProps> = (
|
|||||||
style.transformOrigin = props.origin;
|
style.transformOrigin = props.origin;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="wall grid-item">
|
<div className="wall-item">
|
||||||
<div
|
<div
|
||||||
className={className.join(" ")}
|
className={className.join(" ")}
|
||||||
style={style}
|
style={style}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { FunctionComponent, useState } from "react";
|
import React, { useState } from "react";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { WallItem } from "./WallItem";
|
import { WallItem } from "./WallItem";
|
||||||
import "./Wall.scss";
|
import "./Wall.scss";
|
||||||
@@ -11,7 +11,7 @@ interface IWallPanelProps {
|
|||||||
) => void;
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WallPanel: FunctionComponent<IWallPanelProps> = (
|
export const WallPanel: React.FC<IWallPanelProps> = (
|
||||||
props: IWallPanelProps
|
props: IWallPanelProps
|
||||||
) => {
|
) => {
|
||||||
const [showOverlay, setShowOverlay] = useState<boolean>(false);
|
const [showOverlay, setShowOverlay] = useState<boolean>(false);
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ export const AddFilter: React.FC<IAddFilterProps> = (
|
|||||||
placement="top"
|
placement="top"
|
||||||
overlay={<Tooltip id="filter-tooltip">Filter</Tooltip>}
|
overlay={<Tooltip id="filter-tooltip">Filter</Tooltip>}
|
||||||
>
|
>
|
||||||
<Button onClick={() => onToggle()} active={isOpen}>
|
<Button variant="secondary" onClick={() => onToggle()} active={isOpen}>
|
||||||
<Icon icon="filter" />
|
<Icon icon="filter" />
|
||||||
</Button>
|
</Button>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
|
|||||||
@@ -139,6 +139,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
|
variant="secondary"
|
||||||
key={option}
|
key={option}
|
||||||
active={props.filter.displayMode === option}
|
active={props.filter.displayMode === option}
|
||||||
onClick={() => onChangeDisplayMode(option)}
|
onClick={() => onChangeDisplayMode(option)}
|
||||||
@@ -157,7 +158,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
onClick={() => onClickCriterionTag(criterion)}
|
onClick={() => onClickCriterionTag(criterion)}
|
||||||
>
|
>
|
||||||
{criterion.getLabel()}
|
{criterion.getLabel()}
|
||||||
<Button onClick={() => onRemoveCriterionTag(criterion)}>
|
<Button variant="secondary" onClick={() => onRemoveCriterionTag(criterion)}>
|
||||||
<Icon icon="times" />
|
<Icon icon="times" />
|
||||||
</Button>
|
</Button>
|
||||||
</Badge>
|
</Badge>
|
||||||
@@ -226,8 +227,8 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
function maybeRenderZoom() {
|
function maybeRenderZoom() {
|
||||||
if (props.onChangeZoom) {
|
if (props.onChangeZoom) {
|
||||||
return (
|
return (
|
||||||
<span className="zoom-slider">
|
|
||||||
<Form.Control
|
<Form.Control
|
||||||
|
className="zoom-slider"
|
||||||
type="range"
|
type="range"
|
||||||
min={0}
|
min={0}
|
||||||
max={3}
|
max={3}
|
||||||
@@ -235,7 +236,6 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
onChangeZoom(Number.parseInt(event.target.value, 10))
|
onChangeZoom(Number.parseInt(event.target.value, 10))
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</span>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
function render() {
|
function render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="d-flex justify-content-center m-auto">
|
<div className="filter-container">
|
||||||
<Form.Control
|
<Form.Control
|
||||||
placeholder="Search..."
|
placeholder="Search..."
|
||||||
value={props.filter.searchTerm}
|
value={props.filter.searchTerm}
|
||||||
@@ -262,13 +262,11 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
))}
|
))}
|
||||||
</Form.Control>
|
</Form.Control>
|
||||||
<ButtonGroup className="filter-item">
|
<ButtonGroup className="filter-item">
|
||||||
<Dropdown>
|
<Dropdown as={ButtonGroup}>
|
||||||
<Dropdown.Toggle variant="secondary" id="more-menu">
|
<Dropdown.Toggle split variant="secondary" id="more-menu">
|
||||||
{props.filter.sortBy}
|
{props.filter.sortBy}
|
||||||
</Dropdown.Toggle>
|
</Dropdown.Toggle>
|
||||||
<Dropdown.Menu>{renderSortByOptions()}</Dropdown.Menu>
|
<Dropdown.Menu>{renderSortByOptions()}</Dropdown.Menu>
|
||||||
</Dropdown>
|
|
||||||
|
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
overlay={
|
overlay={
|
||||||
<Tooltip id="sort-direction-tooltip">
|
<Tooltip id="sort-direction-tooltip">
|
||||||
@@ -278,7 +276,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Button onClick={onChangeSortDirection}>
|
<Button variant="secondary" onClick={onChangeSortDirection}>
|
||||||
<Icon
|
<Icon
|
||||||
icon={
|
icon={
|
||||||
props.filter.sortDirection === "asc"
|
props.filter.sortDirection === "asc"
|
||||||
@@ -288,6 +286,8 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
|||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
|
</Dropdown>
|
||||||
|
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<AddFilter
|
<AddFilter
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ export const Pagination: React.FC<IPaginationProps> = ({
|
|||||||
|
|
||||||
const pageButtons = pages.map((page: number) => (
|
const pageButtons = pages.map((page: number) => (
|
||||||
<Button
|
<Button
|
||||||
|
variant="secondary"
|
||||||
key={page}
|
key={page}
|
||||||
active={currentPage === page}
|
active={currentPage === page}
|
||||||
onClick={() => onChangePage(page)}
|
onClick={() => onChangePage(page)}
|
||||||
@@ -48,11 +49,12 @@ export const Pagination: React.FC<IPaginationProps> = ({
|
|||||||
));
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonGroup className="filter-container">
|
<ButtonGroup className="filter-container pagination">
|
||||||
<Button disabled={currentPage === 1} onClick={() => onChangePage(1)}>
|
<Button variant="secondary" disabled={currentPage === 1} onClick={() => onChangePage(1)}>
|
||||||
First
|
First
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
variant="secondary"
|
||||||
disabled={currentPage === 1}
|
disabled={currentPage === 1}
|
||||||
onClick={() => onChangePage(currentPage - 1)}
|
onClick={() => onChangePage(currentPage - 1)}
|
||||||
>
|
>
|
||||||
@@ -60,12 +62,14 @@ export const Pagination: React.FC<IPaginationProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
{pageButtons}
|
{pageButtons}
|
||||||
<Button
|
<Button
|
||||||
|
variant="secondary"
|
||||||
disabled={currentPage === totalPages}
|
disabled={currentPage === totalPages}
|
||||||
onClick={() => onChangePage(currentPage + 1)}
|
onClick={() => onChangePage(currentPage + 1)}
|
||||||
>
|
>
|
||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
variant="secondary"
|
||||||
disabled={currentPage === totalPages}
|
disabled={currentPage === totalPages}
|
||||||
onClick={() => onChangePage(totalPages)}
|
onClick={() => onChangePage(totalPages)}
|
||||||
>
|
>
|
||||||
|
|||||||
15
ui/v2.5/src/components/list/styles.scss
Normal file
15
ui/v2.5/src/components/list/styles.scss
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
.pagination {
|
||||||
|
.btn {
|
||||||
|
flex-grow: 0;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
border-left: 1px solid $body-bg;
|
||||||
|
border-right: 1px solid $body-bg;
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.zoom-slider {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
@@ -91,7 +91,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<HoverPopover placement="bottom" content={popoverContent}>
|
<HoverPopover placement="bottom" content={popoverContent}>
|
||||||
<Button>
|
<Button className="minimal">
|
||||||
<Icon icon="tag" />
|
<Icon icon="tag" />
|
||||||
{props.scene.tags.length}
|
{props.scene.tags.length}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -115,7 +115,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<HoverPopover placement="bottom" content={popoverContent}>
|
<HoverPopover placement="bottom" content={popoverContent}>
|
||||||
<Button>
|
<Button className="minimal">
|
||||||
<Icon icon="user" />
|
<Icon icon="user" />
|
||||||
{props.scene.performers.length}
|
{props.scene.performers.length}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -133,8 +133,8 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<HoverPopover placement="bottom" content={popoverContent}>
|
<HoverPopover placement="bottom" content={popoverContent}>
|
||||||
<Button>
|
<Button className="minimal">
|
||||||
<Icon icon="tag" />
|
<Icon icon="map-marker-alt" />
|
||||||
{props.scene.scene_markers.length}
|
{props.scene.scene_markers.length}
|
||||||
</Button>
|
</Button>
|
||||||
</HoverPopover>
|
</HoverPopover>
|
||||||
@@ -150,7 +150,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<hr />
|
<hr />
|
||||||
<ButtonGroup className="mr-2">
|
<ButtonGroup className="scene-popovers">
|
||||||
{maybeRenderTagPopoverButton()}
|
{maybeRenderTagPopoverButton()}
|
||||||
{maybeRenderPerformerPopoverButton()}
|
{maybeRenderPerformerPopoverButton()}
|
||||||
{maybeRenderSceneMarkerPopoverButton()}
|
{maybeRenderSceneMarkerPopoverButton()}
|
||||||
@@ -182,7 +182,7 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
className={`col-4 zoom-${props.zoomIndex}`}
|
className={`zoom-${props.zoomIndex}`}
|
||||||
onMouseEnter={onMouseEnter}
|
onMouseEnter={onMouseEnter}
|
||||||
onMouseLeave={onMouseLeave}
|
onMouseLeave={onMouseLeave}
|
||||||
>
|
>
|
||||||
@@ -216,11 +216,11 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
|||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<div className="card-section">
|
<div className="card-section">
|
||||||
<h4 className="text-truncate">
|
<h5 className="text-truncate">
|
||||||
{props.scene.title
|
{props.scene.title
|
||||||
? props.scene.title
|
? props.scene.title
|
||||||
: TextUtils.fileNameFromPath(props.scene.path)}
|
: TextUtils.fileNameFromPath(props.scene.path)}
|
||||||
</h4>
|
</h5>
|
||||||
<span>{props.scene.date}</span>
|
<span>{props.scene.date}</span>
|
||||||
<p>
|
<p>
|
||||||
{TextUtils.truncate(
|
{TextUtils.truncate(
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export const SceneMarkerList: React.FC = () => {
|
|||||||
filter: ListFilterModel
|
filter: ListFilterModel
|
||||||
) {
|
) {
|
||||||
// query for a random scene
|
// query for a random scene
|
||||||
if (result.data && result.data.findSceneMarkers) {
|
if (result.data?.findSceneMarkers) {
|
||||||
const { count } = result.data.findSceneMarkers;
|
const { count } = result.data.findSceneMarkers;
|
||||||
|
|
||||||
const index = Math.floor(Math.random() * count);
|
const index = Math.floor(Math.random() * count);
|
||||||
@@ -37,10 +37,7 @@ export const SceneMarkerList: React.FC = () => {
|
|||||||
filterCopy.currentPage = index + 1;
|
filterCopy.currentPage = index + 1;
|
||||||
const singleResult = await StashService.queryFindSceneMarkers(filterCopy);
|
const singleResult = await StashService.queryFindSceneMarkers(filterCopy);
|
||||||
if (
|
if (
|
||||||
singleResult &&
|
singleResult?.data?.findSceneMarkers?.scene_markers?.length === 1
|
||||||
singleResult.data &&
|
|
||||||
singleResult.data.findSceneMarkers &&
|
|
||||||
singleResult.data.findSceneMarkers.scene_markers.length === 1
|
|
||||||
) {
|
) {
|
||||||
// navigate to the scene player page
|
// navigate to the scene player page
|
||||||
const url = NavUtils.makeSceneMarkerUrl(
|
const url = NavUtils.makeSceneMarkerUrl(
|
||||||
|
|||||||
@@ -16,16 +16,14 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
|
|||||||
) => {
|
) => {
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
const [rating, setRating] = useState<string>("");
|
const [rating, setRating] = useState<string>("");
|
||||||
const [studioId, setStudioId] = useState<string | undefined>(undefined);
|
const [studioId, setStudioId] = useState<string>();
|
||||||
const [performerIds, setPerformerIds] = useState<string[] | undefined>(
|
const [performerIds, setPerformerIds] = useState<string[]>();
|
||||||
undefined
|
const [tagIds, setTagIds] = useState<string[]>();
|
||||||
);
|
|
||||||
const [tagIds, setTagIds] = useState<string[] | undefined>(undefined);
|
|
||||||
|
|
||||||
const [updateScenes] = StashService.useBulkSceneUpdate(getSceneInput());
|
const [updateScenes] = StashService.useBulkSceneUpdate(getSceneInput());
|
||||||
|
|
||||||
// Network state
|
// Network state
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
function getSceneInput(): GQL.BulkSceneUpdateInput {
|
function getSceneInput(): GQL.BulkSceneUpdateInput {
|
||||||
// need to determine what we are actually setting on each scene
|
// need to determine what we are actually setting on each scene
|
||||||
@@ -184,14 +182,14 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
|
|||||||
|
|
||||||
function updateScenesEditState(state: GQL.SlimSceneDataFragment[]) {
|
function updateScenesEditState(state: GQL.SlimSceneDataFragment[]) {
|
||||||
let updateRating = "";
|
let updateRating = "";
|
||||||
let updateStudioId: string | undefined;
|
let updateStudioId: string|undefined;
|
||||||
let updatePerformerIds: string[] = [];
|
let updatePerformerIds: string[] = [];
|
||||||
let updateTagIds: string[] = [];
|
let updateTagIds: string[] = [];
|
||||||
let first = true;
|
let first = true;
|
||||||
|
|
||||||
state.forEach((scene: GQL.SlimSceneDataFragment) => {
|
state.forEach((scene: GQL.SlimSceneDataFragment) => {
|
||||||
const thisRating = scene.rating ? scene.rating.toString() : "";
|
const thisRating = scene.rating?.toString() ?? "";
|
||||||
const thisStudio = scene.studio ? scene.studio.id : undefined;
|
const thisStudio = scene?.studio?.id;
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
updateRating = thisRating;
|
updateRating = thisRating;
|
||||||
@@ -231,44 +229,47 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateScenesEditState(props.selected);
|
updateScenesEditState(props.selected);
|
||||||
|
setIsLoading(false);
|
||||||
}, [props.selected]);
|
}, [props.selected]);
|
||||||
|
|
||||||
function renderMultiSelect(
|
function renderMultiSelect(
|
||||||
type: "performers" | "tags",
|
type: "performers" | "tags",
|
||||||
initialIds: string[] | undefined
|
ids: string[] | undefined
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<FilterSelect
|
<FilterSelect
|
||||||
type={type}
|
type={type}
|
||||||
isMulti
|
isMulti
|
||||||
|
isClearable={false}
|
||||||
onSelect={items => {
|
onSelect={items => {
|
||||||
const ids = items.map(i => i.id);
|
const itemIDs = items.map(i => i.id);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "performers":
|
case "performers":
|
||||||
setPerformerIds(ids);
|
setPerformerIds(itemIDS);
|
||||||
break;
|
break;
|
||||||
case "tags":
|
case "tags":
|
||||||
setTagIds(ids);
|
setTagIds(itemIDs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
initialIds={initialIds ?? []}
|
ids={ids ?? []}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isLoading)
|
||||||
|
return <Spinner animation="border" variant="light" />;
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
{isLoading ? <Spinner animation="border" variant="light" /> : undefined}
|
|
||||||
<div className="operation-container">
|
<div className="operation-container">
|
||||||
<Form.Group controlId="rating" className="operation-item">
|
<Form.Group controlId="rating" className="operation-item rating-operation">
|
||||||
<Form.Label>Rating</Form.Label>
|
<Form.Label>Rating</Form.Label>
|
||||||
<Form.Control
|
<Form.Control
|
||||||
as="select"
|
as="select"
|
||||||
onChange={(event: any) => setRating(event.target.value)}
|
onChange={(event: any) => setRating(event.target.value)}
|
||||||
>
|
>
|
||||||
{["", 1, 2, 3, 4, 5].map(opt => (
|
{["", '1', '2', '3', '4', '5'].map(opt => (
|
||||||
<option selected={opt === rating} value={opt}>
|
<option selected={opt === rating} value={opt}>
|
||||||
{opt}
|
{opt}
|
||||||
</option>
|
</option>
|
||||||
@@ -280,27 +281,24 @@ export const SceneSelectedOptions: React.FC<IListOperationProps> = (
|
|||||||
<Form.Label>Studio</Form.Label>
|
<Form.Label>Studio</Form.Label>
|
||||||
<StudioSelect
|
<StudioSelect
|
||||||
onSelect={items => setStudioId(items[0]?.id)}
|
onSelect={items => setStudioId(items[0]?.id)}
|
||||||
initialIds={studioId ? [studioId] : []}
|
ids={studioId ? [studioId] : []}
|
||||||
/>
|
/>
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
<Form.Group className="opeation-item" controlId="performers">
|
<Form.Group className="operation-item" controlId="performers">
|
||||||
<Form.Label>Performers</Form.Label>
|
<Form.Label>Performers</Form.Label>
|
||||||
{renderMultiSelect("performers", performerIds)}
|
{renderMultiSelect("performers", performerIds)}
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
<Form.Group className="operation-item" controlId="performers">
|
<Form.Group className="operation-item" controlId="performers">
|
||||||
<Form.Label>Performers</Form.Label>
|
<Form.Label>Tags</Form.Label>
|
||||||
{renderMultiSelect("tags", tagIds)}
|
{renderMultiSelect("tags", tagIds)}
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
<ButtonGroup className="operation-item">
|
<Button variant="primary" onClick={onSave} className="apply-operation">
|
||||||
<Button variant="primary" onClick={onSave}>
|
|
||||||
Apply
|
Apply
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonGroup>
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
ui/v2.5/src/components/scenes/styles.scss
Normal file
28
ui/v2.5/src/components/scenes/styles.scss
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
.scene-popovers {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding-top: 3px;
|
||||||
|
padding-bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation-container {
|
||||||
|
.operation-item {
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rating-operation {
|
||||||
|
min-width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.apply-operation {
|
||||||
|
margin-top: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
@import "styles/shared/details";
|
@import "styles/shared/details";
|
||||||
|
|
||||||
|
@import "styles/range";
|
||||||
@import "styles/scrollbars";
|
@import "styles/scrollbars";
|
||||||
@import "styles/variables";
|
@import "styles/variables";
|
||||||
|
|
||||||
@@ -17,7 +18,6 @@ body {
|
|||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: $dark-gray2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
code {
|
||||||
@@ -37,10 +37,6 @@ code {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .bp3-button.favorite .bp3-icon {
|
|
||||||
color: #ff7373 !important
|
|
||||||
}
|
|
||||||
|
|
||||||
& .performer-list-thumbnail {
|
& .performer-list-thumbnail {
|
||||||
min-width: 50px;
|
min-width: 50px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
@@ -55,58 +51,59 @@ code {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.grid-item {
|
.card {
|
||||||
// flex: auto;
|
margin: 0 0 10px 10px;
|
||||||
width: 320px;
|
|
||||||
min-width: 185px;
|
|
||||||
margin: 0px 0 $pt-grid-size $pt-grid-size;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&.wall {
|
|
||||||
width: calc(20%);
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.zoom-0 {
|
&.zoom-0 {
|
||||||
width: 240px;
|
width: 15rem;
|
||||||
|
|
||||||
& .previewable {
|
& .previewable {
|
||||||
max-height: 180px;
|
max-height: 11.25rem;
|
||||||
}
|
}
|
||||||
& .previewable.portrait {
|
& .previewable.portrait {
|
||||||
height: 180px;
|
max-height: 11.25rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.zoom-1 {
|
&.zoom-1 {
|
||||||
width: 320px;
|
width: 20rem;
|
||||||
|
|
||||||
& .previewable {
|
& .previewable {
|
||||||
max-height: 240px;
|
max-height: 15rem;
|
||||||
}
|
}
|
||||||
& .previewable.portrait {
|
& .previewable.portrait {
|
||||||
height: 240px;
|
height: 15rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.zoom-2 {
|
&.zoom-2 {
|
||||||
width: 480px;
|
width: 30rem;
|
||||||
|
|
||||||
& .previewable {
|
& .previewable {
|
||||||
max-height: 360px;
|
max-height: 22.5rem;
|
||||||
}
|
}
|
||||||
& .previewable.portrait {
|
& .previewable.portrait {
|
||||||
height: 360px;
|
height: 22.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.zoom-3 {
|
&.zoom-3 {
|
||||||
width: 640px;
|
width: 40rem;
|
||||||
|
|
||||||
& .previewable {
|
& .previewable {
|
||||||
max-height: 480px;
|
max-height: 30rem;
|
||||||
}
|
}
|
||||||
& .previewable.portrait {
|
& .previewable.portrait {
|
||||||
height: 480px;
|
height: 30rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-select {
|
||||||
|
position: absolute;
|
||||||
|
padding-left: 15px;
|
||||||
|
margin-top: -12px;
|
||||||
|
z-index: 1;
|
||||||
|
opacity: 0.5;
|
||||||
|
width: 1.2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,14 +122,6 @@ code {
|
|||||||
height: 240px;
|
height: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-item label.card-select {
|
|
||||||
position: absolute;
|
|
||||||
padding-left: 15px;
|
|
||||||
margin-top: -12px;
|
|
||||||
z-index: 9;
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-container {
|
.video-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -336,6 +325,7 @@ span.block {
|
|||||||
|
|
||||||
.performer-tag-container {
|
.performer-tag-container {
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.performer-tag.image {
|
.performer-tag.image {
|
||||||
@@ -548,7 +538,7 @@ span.block {
|
|||||||
background-color: #30404d;
|
background-color: #30404d;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
box-shadow: 0 0 0 1px rgba(16,22,26,.4), 0 0 0 rgba(16,22,26,0), 0 0 0 rgba(16,22,26,0);
|
box-shadow: 0 0 0 1px rgba(16,22,26,.4), 0 0 0 rgba(16,22,26,0), 0 0 0 rgba(16,22,26,0);
|
||||||
padding: 20px;
|
padding: 20px 20px 0px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toast-container {
|
.toast-container {
|
||||||
|
|||||||
94
ui/v2.5/src/styles/_range.scss
Normal file
94
ui/v2.5/src/styles/_range.scss
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
input[type=range] {
|
||||||
|
height: 22px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 10px 0;
|
||||||
|
background-color: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
input[type=range]:focus {
|
||||||
|
border: inherit;
|
||||||
|
box-shadow: none;
|
||||||
|
outline: none;
|
||||||
|
background-color: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
input[type=range]::-webkit-slider-runnable-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
animate: 0.2s;
|
||||||
|
box-shadow: 0px 0px 0px #000000;
|
||||||
|
background: #137cbd;
|
||||||
|
border-radius: 25px;
|
||||||
|
border: 0px solid #000101;
|
||||||
|
}
|
||||||
|
input[type=range]::-webkit-slider-thumb {
|
||||||
|
box-shadow: 0px 0px 0px #000000;
|
||||||
|
border: 0px solid #000000;
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: #394B59;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
input[type=range]:focus::-webkit-slider-runnable-track {
|
||||||
|
background: #137cbd;
|
||||||
|
}
|
||||||
|
input[type=range]::-moz-range-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
animate: 0.2s;
|
||||||
|
box-shadow: 0px 0px 0px #000000;
|
||||||
|
background: #137cbd;
|
||||||
|
border-radius: 25px;
|
||||||
|
border: 0px solid #000101;
|
||||||
|
}
|
||||||
|
input[type=range]::-moz-range-thumb {
|
||||||
|
box-shadow: 0px 0px 0px #000000;
|
||||||
|
border: 0px solid #000000;
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: #394B59;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
input[type=range]::-ms-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
animate: 0.2s;
|
||||||
|
background: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
input[type=range]::-ms-fill-lower {
|
||||||
|
background: #137cbd;
|
||||||
|
border: 0px solid #000101;
|
||||||
|
border-radius: 50px;
|
||||||
|
box-shadow: 0px 0px 0px #000000;
|
||||||
|
}
|
||||||
|
input[type=range]::-ms-fill-upper {
|
||||||
|
background: #137cbd;
|
||||||
|
border: 0px solid #000101;
|
||||||
|
border-radius: 50px;
|
||||||
|
box-shadow: 0px 0px 0px #000000;
|
||||||
|
}
|
||||||
|
input[type=range]::-ms-thumb {
|
||||||
|
margin-top: 1px;
|
||||||
|
box-shadow: 0px 0px 0px #000000;
|
||||||
|
border: 0px solid #000000;
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background: #394B59;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
input[type=range]:focus::-ms-fill-lower {
|
||||||
|
background: #137cbd;
|
||||||
|
}
|
||||||
|
input[type=range]:focus::-ms-fill-upper {
|
||||||
|
background: #137cbd;
|
||||||
|
}
|
||||||
@@ -1,9 +1,80 @@
|
|||||||
|
|
||||||
/* Blueprint dark theme */
|
/* Blueprint dark theme */
|
||||||
|
|
||||||
|
$secondary: #394b59;
|
||||||
|
|
||||||
|
$theme-colors: (
|
||||||
|
primary: #137cbd,
|
||||||
|
secondary: $secondary,
|
||||||
|
success: #0f9960,
|
||||||
|
warning: #d9822b,
|
||||||
|
danger: #db3737,
|
||||||
|
dark: #394b59
|
||||||
|
);
|
||||||
|
|
||||||
|
$body-bg: #202b33;
|
||||||
$text-muted: #bfccd6;
|
$text-muted: #bfccd6;
|
||||||
$link-color: #48aff0;
|
$link-color: #48aff0;
|
||||||
$link-hover-color: #48aff0;
|
$link-hover-color: #48aff0;
|
||||||
$text-color: f5f8fa;
|
$text-color: #f5f8fa;
|
||||||
$pre-color: $text-color;
|
$pre-color: $text-color;
|
||||||
|
$navbar-dark-color: rgb(245, 248, 250);
|
||||||
|
$input-bg: $secondary;
|
||||||
|
$input-color: #f5f8fa;
|
||||||
|
$popover-bg: $secondary;
|
||||||
|
|
||||||
@import "node_modules/bootstrap/scss/bootstrap";
|
@import "node_modules/bootstrap/scss/bootstrap";
|
||||||
|
|
||||||
|
.btn.active:not(.disabled),
|
||||||
|
.btn.active.minimal:not(.disabled) {
|
||||||
|
background-color: rgba(138,155,168,.3);
|
||||||
|
color: #f5f8fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.minimal,
|
||||||
|
button.minimal {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: $text-color;
|
||||||
|
transition: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(138,155,168,.15);
|
||||||
|
color: $text-color;
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background: rgba(138,155,168,.3);
|
||||||
|
color: $text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.form-control {
|
||||||
|
background-color: rgba(16, 22, 26, 0.3);
|
||||||
|
}
|
||||||
|
.form-control {
|
||||||
|
border-color: rgba(16,22,26,.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-toggle:after {
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav .svg-inline--fa {
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table {
|
||||||
|
th {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
th {
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user