mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Fix various issues with v2.5 UI (#390)
* Fix navbar collapse breakpoint * Fix list filter colors and height * Make styling similar to v2 * Fix scene card zoom and orientation * Keep p tag even without details * Fix custom css * Default settings tab to tasks * Fix flickering progress bar. Fix percentage. * Fix unsetting studio * Fix scene gallery select * Don't hide edit on small devices * Fix log dropdown style * Use monospace for custom css input
This commit is contained in:
@@ -107,7 +107,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
|
||||
function renderSortByOptions() {
|
||||
return props.filter.sortByOptions.map(option => (
|
||||
<Dropdown.Item onClick={onChangeSortBy} key={option}>
|
||||
<Dropdown.Item onClick={onChangeSortBy} key={option} className="bg-secondary text-white">
|
||||
{option}
|
||||
</Dropdown.Item>
|
||||
));
|
||||
@@ -186,7 +186,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
function renderSelectAll() {
|
||||
if (props.onSelectAll) {
|
||||
return (
|
||||
<Dropdown.Item key="select-all" onClick={() => onSelectAll()}>
|
||||
<Dropdown.Item key="select-all" className="bg-secondary text-white" onClick={() => onSelectAll()}>
|
||||
Select All
|
||||
</Dropdown.Item>
|
||||
);
|
||||
@@ -196,7 +196,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
function renderSelectNone() {
|
||||
if (props.onSelectNone) {
|
||||
return (
|
||||
<Dropdown.Item key="select-none" onClick={() => onSelectNone()}>
|
||||
<Dropdown.Item key="select-none" className="bg-secondary text-white" onClick={() => onSelectNone()}>
|
||||
Select None
|
||||
</Dropdown.Item>
|
||||
);
|
||||
@@ -209,7 +209,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
if (props.otherOperations) {
|
||||
props.otherOperations.forEach(o => {
|
||||
options.push(
|
||||
<Dropdown.Item key={o.text} onClick={o.onClick}>
|
||||
<Dropdown.Item key={o.text} className="bg-secondary text-white" onClick={o.onClick}>
|
||||
{o.text}
|
||||
</Dropdown.Item>
|
||||
);
|
||||
@@ -222,7 +222,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
<Dropdown.Toggle variant="secondary" id="more-menu">
|
||||
<Icon icon="ellipsis-h" />
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu>{options}</Dropdown.Menu>
|
||||
<Dropdown.Menu className="bg-secondary text-white">{options}</Dropdown.Menu>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
@@ -259,13 +259,13 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
placeholder="Search..."
|
||||
defaultValue={props.filter.searchTerm}
|
||||
onChange={onChangeQuery}
|
||||
className="filter-item col-5 col-sm-2"
|
||||
className="filter-item col-5 col-sm-2 bg-secondary text-white border-secondary"
|
||||
/>
|
||||
<Form.Control
|
||||
as="select"
|
||||
onChange={onChangePageSize}
|
||||
value={props.filter.itemsPerPage.toString()}
|
||||
className="filter-item col-1 d-none d-sm-inline"
|
||||
className="btn-secondary filter-item col-1 d-none d-sm-inline"
|
||||
>
|
||||
{PAGE_SIZE_OPTIONS.map(s => (
|
||||
<option value={s} key={s}>
|
||||
@@ -278,7 +278,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
|
||||
<Dropdown.Toggle split variant="secondary" id="more-menu">
|
||||
{props.filter.sortBy}
|
||||
</Dropdown.Toggle>
|
||||
<Dropdown.Menu>{renderSortByOptions()}</Dropdown.Menu>
|
||||
<Dropdown.Menu className="bg-secondary text-white">{renderSortByOptions()}</Dropdown.Menu>
|
||||
<OverlayTrigger
|
||||
overlay={
|
||||
<Tooltip id="sort-direction-tooltip">
|
||||
|
||||
@@ -73,20 +73,20 @@ export const MainNavbar: React.FC = () => {
|
||||
variant="dark"
|
||||
bg="dark"
|
||||
className="top-nav"
|
||||
expand="sm"
|
||||
expand="md"
|
||||
>
|
||||
<Navbar.Brand as="div" className="order-1 order-sm-0">
|
||||
<Navbar.Brand as="div" className="order-1 order-md-0">
|
||||
<Link to="/">
|
||||
<Button className="minimal brand-link d-none d-sm-inline-block">
|
||||
<Button className="minimal brand-link d-none d-md-inline-block">
|
||||
Stash
|
||||
</Button>
|
||||
<Button className="minimal brand-icon d-inline d-sm-none">
|
||||
<Button className="minimal brand-icon d-inline d-md-none">
|
||||
<img src="favicon.ico" alt="" />
|
||||
</Button>
|
||||
</Link>
|
||||
</Navbar.Brand>
|
||||
<Navbar.Toggle className="order-0" />
|
||||
<Navbar.Collapse className="order-3 order-sm-1">
|
||||
<Navbar.Collapse className="order-3 order-md-1">
|
||||
<Nav className="mr-md-auto">
|
||||
{menuItems.map(i => (
|
||||
<Nav.Link eventKey={i.href} as="div" key={i.href}>
|
||||
|
||||
@@ -298,6 +298,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
|
||||
</td>
|
||||
<td>
|
||||
<Form.Control
|
||||
className="text-input"
|
||||
value={url ?? ""}
|
||||
readOnly={!isEditing}
|
||||
plaintext={!isEditing}
|
||||
|
||||
@@ -235,11 +235,9 @@ export const SceneCard: React.FC<ISceneCardProps> = (
|
||||
: TextUtils.fileNameFromPath(props.scene.path)}
|
||||
</h5>
|
||||
<span>{props.scene.date}</span>
|
||||
{props.scene.details && (
|
||||
<p>
|
||||
{TextUtils.truncate(props.scene.details, 100, "... (continued)")}
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
{props.scene.details && TextUtils.truncate(props.scene.details, 100, "... (continued)")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{maybeRenderPopoverButtonGroup()}
|
||||
|
||||
@@ -140,7 +140,6 @@ export const Scene: React.FC = () => {
|
||||
<Tab
|
||||
eventKey="scene-edit-panel"
|
||||
title="Edit"
|
||||
tabClassName="d-none d-sm-block"
|
||||
>
|
||||
<SceneEditPanel
|
||||
scene={scene}
|
||||
|
||||
@@ -310,6 +310,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
||||
}
|
||||
value={url}
|
||||
placeholder="URL"
|
||||
className="text-input"
|
||||
/>
|
||||
{maybeRenderScrapeButton()}
|
||||
</td>
|
||||
@@ -318,7 +319,8 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
||||
title: "Date",
|
||||
value: date,
|
||||
isEditing: true,
|
||||
onChange: setDate
|
||||
onChange: setDate,
|
||||
placeholder: "YYYY-MM-DD"
|
||||
})}
|
||||
{TableUtils.renderHtmlSelect({
|
||||
title: "Rating",
|
||||
@@ -342,7 +344,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
||||
<td>Studio</td>
|
||||
<td>
|
||||
<StudioSelect
|
||||
onSelect={items => items.length && setStudioId(items[0]?.id)}
|
||||
onSelect={items => setStudioId(items.length > 0 ? items[0]?.id : undefined)}
|
||||
ids={studioId ? [studioId] : []}
|
||||
/>
|
||||
</td>
|
||||
@@ -377,7 +379,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
||||
<Form.Label>Details</Form.Label>
|
||||
<Form.Control
|
||||
as="textarea"
|
||||
className="scene-description"
|
||||
className="scene-description text-input"
|
||||
onChange={(newValue: React.FormEvent<HTMLTextAreaElement>) =>
|
||||
setDetails(newValue.currentTarget.value)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { SettingsTasksPanel } from "./SettingsTasksPanel/SettingsTasksPanel";
|
||||
export const Settings: React.FC = () => {
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
const defaultTab = queryString.parse(location.search).tab ?? "configuration";
|
||||
const defaultTab = queryString.parse(location.search).tab ?? "tasks";
|
||||
|
||||
const onSelect = (val: string) => history.push(`?tab=${val}`);
|
||||
|
||||
@@ -23,7 +23,7 @@ export const Settings: React.FC = () => {
|
||||
onSelect={onSelect}
|
||||
>
|
||||
<Row>
|
||||
<Col sm={2}>
|
||||
<Col sm={3} md={2}>
|
||||
<Nav variant="pills" className="flex-column">
|
||||
<Nav.Item>
|
||||
<Nav.Link eventKey="configuration">Configuration</Nav.Link>
|
||||
@@ -43,7 +43,7 @@ export const Settings: React.FC = () => {
|
||||
<hr className="d-sm-none" />
|
||||
</Nav>
|
||||
</Col>
|
||||
<Col sm={10}>
|
||||
<Col sm={9} md={10}>
|
||||
<Tab.Content>
|
||||
<Tab.Pane eventKey="configuration">
|
||||
<SettingsConfigurationPanel />
|
||||
|
||||
@@ -173,7 +173,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
<Form.Group id="database-path">
|
||||
<h6>Database Path</h6>
|
||||
<Form.Control
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 text-input"
|
||||
defaultValue={databasePath}
|
||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||
setDatabasePath(e.currentTarget.value)
|
||||
@@ -187,7 +187,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
<Form.Group id="generated-path">
|
||||
<h6>Generated Path</h6>
|
||||
<Form.Control
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 text-input"
|
||||
defaultValue={generatedPath}
|
||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||
setGeneratedPath(e.currentTarget.value)
|
||||
@@ -206,7 +206,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
excludes.map((regexp, i) => (
|
||||
<InputGroup>
|
||||
<Form.Control
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 text-input"
|
||||
value={regexp}
|
||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||
excludeRegexChanged(i, e.currentTarget.value)
|
||||
@@ -226,15 +226,13 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
<Button className="minimal" onClick={() => excludeAddRegex()}>
|
||||
<Icon icon="plus" />
|
||||
</Button>
|
||||
<Form.Text>
|
||||
<Form.Text className="text-muted">
|
||||
Regexps of files/paths to exclude from Scan and add to Clean
|
||||
<a
|
||||
href="https://github.com/stashapp/stash/wiki/Exclude-file-configuration"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<span>
|
||||
Regexps of files/paths to exclude from Scan and add to Clean
|
||||
</span>
|
||||
<Icon icon="question-circle" />
|
||||
</a>
|
||||
</Form.Text>
|
||||
@@ -248,7 +246,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
<Form.Group id="transcode-size">
|
||||
<h6>Maximum transcode size</h6>
|
||||
<Form.Control
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 input-control"
|
||||
as="select"
|
||||
onChange={(event: React.FormEvent<HTMLSelectElement>) =>
|
||||
setMaxTranscodeSize(translateQuality(event.currentTarget.value))
|
||||
@@ -268,7 +266,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
<Form.Group id="streaming-transcode-size">
|
||||
<h6>Maximum streaming transcode size</h6>
|
||||
<Form.Control
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 input-control"
|
||||
as="select"
|
||||
onChange={(event: React.FormEvent<HTMLSelectElement>) =>
|
||||
setMaxStreamingTranscodeSize(
|
||||
@@ -296,7 +294,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
<Form.Group id="username">
|
||||
<h6>Username</h6>
|
||||
<Form.Control
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 text-input"
|
||||
defaultValue={username}
|
||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||
setUsername(e.currentTarget.value)
|
||||
@@ -309,7 +307,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
<Form.Group id="password">
|
||||
<h6>Password</h6>
|
||||
<Form.Control
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 text-input"
|
||||
type="password"
|
||||
defaultValue={password}
|
||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||
@@ -328,7 +326,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
<Form.Group id="log-file">
|
||||
<h6>Log file</h6>
|
||||
<Form.Control
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 text-input"
|
||||
defaultValue={logFile}
|
||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||
setLogFile(e.currentTarget.value)
|
||||
@@ -356,7 +354,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
|
||||
<Form.Group id="log-level">
|
||||
<h6>Log Level</h6>
|
||||
<Form.Control
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 input-control"
|
||||
as="select"
|
||||
onChange={(event: React.FormEvent<HTMLSelectElement>) =>
|
||||
setLogLevel(event.currentTarget.value)
|
||||
|
||||
@@ -56,11 +56,11 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<h4>User Interface</h4>
|
||||
<Form.Group controlId="language" className="row">
|
||||
<Form.Label className="col-2">Language</Form.Label>
|
||||
<Form.Group controlId="language">
|
||||
<h6>Language</h6>
|
||||
<Form.Control
|
||||
as="select"
|
||||
className="col-4"
|
||||
className="col-4 input-control"
|
||||
value={language}
|
||||
onChange={(e: React.FormEvent<HTMLSelectElement>) =>
|
||||
setLanguage(e.currentTarget.value)
|
||||
@@ -72,7 +72,7 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||
</Form.Control>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Label>Scene / Marker Wall</Form.Label>
|
||||
<h5>Scene / Marker Wall</h5>
|
||||
<Form.Check
|
||||
id="wall-show-title"
|
||||
checked={wallShowTitle}
|
||||
@@ -104,19 +104,20 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||
|
||||
<Form.Group>
|
||||
<h5>Scene Player</h5>
|
||||
<Form.Check
|
||||
id="auto-start-video"
|
||||
checked={autostartVideo}
|
||||
label="Auto-start video"
|
||||
onChange={() => {
|
||||
setAutostartVideo(!autostartVideo);
|
||||
}}
|
||||
/>
|
||||
<Form.Group id="auto-start-video">
|
||||
<Form.Check
|
||||
checked={autostartVideo}
|
||||
label="Auto-start video"
|
||||
onChange={() => {
|
||||
setAutostartVideo(!autostartVideo);
|
||||
}}
|
||||
/>
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group id="max-loop-duration">
|
||||
<Form.Label>Maximum loop duration</Form.Label>
|
||||
<h6>Maximum loop duration</h6>
|
||||
<DurationInput
|
||||
className="col col-sm-4"
|
||||
className="row col col-4"
|
||||
numericValue={maximumLoopDuration}
|
||||
onValueChange={duration => setMaximumLoopDuration(duration)}
|
||||
/>
|
||||
@@ -145,7 +146,7 @@ export const SettingsInterfacePanel: React.FC = () => {
|
||||
setCSS(e.currentTarget.value)
|
||||
}
|
||||
rows={16}
|
||||
className="col col-sm-6"
|
||||
className="col col-sm-6 text-input code"
|
||||
></Form.Control>
|
||||
<Form.Text className="text-muted">
|
||||
Page must be reloaded for changes to take effect.
|
||||
|
||||
@@ -101,7 +101,7 @@ export const SettingsLogsPanel: React.FC = () => {
|
||||
<Form.Row id="log-level">
|
||||
<Form.Label className="col-6 col-sm-2">Log Level</Form.Label>
|
||||
<Form.Control
|
||||
className="col-6 col-sm-2"
|
||||
className="col-6 col-sm-2 input-control"
|
||||
as="select"
|
||||
defaultValue={logLevel}
|
||||
onChange={event => setLogLevel(event.currentTarget.value)}
|
||||
|
||||
@@ -167,8 +167,8 @@ export const SettingsTasksPanel: React.FC = () => {
|
||||
<>
|
||||
<Form.Group>
|
||||
<h5>Status: {status}</h5>
|
||||
{status !== "Idle" ? (
|
||||
<ProgressBar now={progress} label={`${progress}%`} />
|
||||
{!!status && status !== "Idle" ? (
|
||||
<ProgressBar animated now={progress} label={`${progress.toFixed(0)}%`} />
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
@@ -183,7 +183,7 @@ export const SettingsTasksPanel: React.FC = () => {
|
||||
{renderImportAlert()}
|
||||
{renderCleanAlert()}
|
||||
|
||||
<h5>Running Jobs</h5>
|
||||
<h4>Running Jobs</h4>
|
||||
|
||||
{renderJobStatus()}
|
||||
|
||||
|
||||
@@ -31,3 +31,7 @@
|
||||
.log-time {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
#configuration-tabs-tabpane-about .table {
|
||||
width: initial;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ export const DurationInput: React.FC<IProps> = (props: IProps) => {
|
||||
<Form.Group className={`duration-input ${props.className}`}>
|
||||
<InputGroup>
|
||||
<Form.Control
|
||||
className="duration-control"
|
||||
className="duration-control text-input"
|
||||
disabled={props.disabled}
|
||||
value={value}
|
||||
onChange={(e: React.FormEvent<HTMLInputElement>) =>
|
||||
|
||||
@@ -73,16 +73,20 @@ export const SceneGallerySelect: React.FC<ISceneGallerySelect> = props => {
|
||||
|
||||
const onChange = (selectedItems: ValueType<Option>) => {
|
||||
const selectedItem = getSelectedValues(selectedItems)[0];
|
||||
props.onSelect(galleries.find(g => g.id === selectedItem.value));
|
||||
props.onSelect(selectedItem ? galleries.find(g => g.id === selectedItem) : undefined);
|
||||
};
|
||||
|
||||
const initialId = props.initialId ? [props.initialId] : [];
|
||||
const selectedOptions: Option[] = props.initialId
|
||||
? items.filter(item => props.initialId?.indexOf(item.value) !== -1)
|
||||
: [];
|
||||
|
||||
return (
|
||||
<SelectComponent
|
||||
className="input-control"
|
||||
onChange={onChange}
|
||||
isLoading={loading}
|
||||
items={items}
|
||||
initialIds={initialId}
|
||||
selectedOptions={selectedOptions}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -207,10 +211,15 @@ export const StudioSelect: React.FC<IFilterProps> = props => {
|
||||
const { data, loading } = StashService.useAllStudiosForFilter();
|
||||
|
||||
const normalizedData = data?.allStudios ?? [];
|
||||
const items: Option[] = normalizedData.map(item => ({
|
||||
|
||||
const items = (normalizedData.length > 0
|
||||
? [{ name: "None", id: "0" }, ...normalizedData]
|
||||
: []
|
||||
).map(item => ({
|
||||
value: item.id,
|
||||
label: item.name
|
||||
}));
|
||||
|
||||
const placeholder = props.noSelectionString ?? "Select studio...";
|
||||
const selectedOptions: Option[] = props.ids
|
||||
? items.filter(item => props.ids?.indexOf(item.value) !== -1)
|
||||
@@ -358,6 +367,7 @@ const SelectComponent: React.FC<ISelectProps & ITypeProps> = ({
|
||||
options,
|
||||
value: selectedOptions,
|
||||
className,
|
||||
classNamePrefix: "react-select",
|
||||
onChange,
|
||||
isMulti,
|
||||
isClearable,
|
||||
|
||||
@@ -11,23 +11,32 @@ export class StashService {
|
||||
public static client: ApolloClient<NormalizedCacheObject>;
|
||||
private static cache: InMemoryCache;
|
||||
|
||||
public static initialize() {
|
||||
public static getPlatformURL(ws? : boolean) {
|
||||
const platformUrl = new URL(window.location.origin);
|
||||
const wsPlatformUrl = new URL(window.location.origin);
|
||||
wsPlatformUrl.protocol = "ws:";
|
||||
|
||||
if (!process.env.NODE_ENV || process.env.NODE_ENV === "development") {
|
||||
platformUrl.port = "9999"; // TODO: Hack. Development expects port 9999
|
||||
wsPlatformUrl.port = "9999";
|
||||
|
||||
if (process.env.REACT_APP_HTTPS === "true") {
|
||||
platformUrl.protocol = "https:";
|
||||
}
|
||||
}
|
||||
|
||||
if (ws) {
|
||||
platformUrl.protocol = "ws:";
|
||||
}
|
||||
|
||||
return platformUrl;
|
||||
}
|
||||
|
||||
public static initialize() {
|
||||
const platformUrl = StashService.getPlatformURL();
|
||||
const wsPlatformUrl = StashService.getPlatformURL(true);
|
||||
|
||||
if (platformUrl.protocol === "https:") {
|
||||
wsPlatformUrl.protocol = "wss:";
|
||||
}
|
||||
|
||||
const url = `${platformUrl.toString().slice(0, -1)}/graphql`;
|
||||
const wsUrl = `${wsPlatformUrl.toString().slice(0, -1)}/graphql`;
|
||||
|
||||
|
||||
5192
ui/v2.5/src/core/generated-graphql.tsx
Normal file
5192
ui/v2.5/src/core/generated-graphql.tsx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,14 +23,38 @@ body {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
margin: 0;
|
||||
padding: 4rem 0 0 0;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
min-width: 845px;
|
||||
a {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
code, .code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
}
|
||||
|
||||
.input-control, .text-input {
|
||||
color: $text-color;
|
||||
border: 0;
|
||||
box-shadow:0 0 0 0 rgba(19, 124, 189, 0), 0 0 0 0 rgba(19, 124, 189, 0), 0 0 0 0 rgba(19, 124, 189, 0), inset 0 0 0 1px rgba(16, 22, 26, 0.3), inset 0 1px 1px rgba(16, 22, 26, 0.4);
|
||||
|
||||
&:focus {
|
||||
color: $text-color;
|
||||
border: 0;
|
||||
box-shadow: 0 0 0 1px $primary, 0 0 0 1px $primary, 0 0 0 3px rgba(19,124,189,.3), inset 0 0 0 1px rgba(16,22,26,.3), inset 0 1px 1px rgba(16,22,26,.4);
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;
|
||||
.text-input, .text-input:focus {
|
||||
background-color: $textfield-bg;
|
||||
}
|
||||
|
||||
.input-control, .input-control:focus {
|
||||
background-color: $secondary;
|
||||
}
|
||||
|
||||
.table-list a {
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
.table-list table {
|
||||
@@ -56,40 +80,84 @@ code {
|
||||
|
||||
@media (min-width: 576px) {
|
||||
.zoom-0 {
|
||||
width: 15rem;
|
||||
width: 240px;
|
||||
|
||||
.scene-card-video {
|
||||
max-height: 180px;
|
||||
}
|
||||
.previewable.portrait {
|
||||
height: 180px;
|
||||
}
|
||||
}
|
||||
|
||||
.zoom-1 {
|
||||
width: 20rem;
|
||||
width: 320px;
|
||||
|
||||
.scene-card-video {
|
||||
max-height: 240px;
|
||||
}
|
||||
.previewable.portrait {
|
||||
height: 240px;
|
||||
}
|
||||
}
|
||||
|
||||
.zoom-2 {
|
||||
width: 30rem;
|
||||
width: 480px;
|
||||
|
||||
.scene-card-video {
|
||||
max-height: 360px;
|
||||
}
|
||||
.previewable.portrait {
|
||||
height: 360px;
|
||||
}
|
||||
}
|
||||
|
||||
.zoom-3 {
|
||||
width: 40rem;
|
||||
width: 640px;
|
||||
|
||||
.scene-card-video {
|
||||
max-height: 480px;
|
||||
}
|
||||
.portrait {
|
||||
height: 480px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scene-card-video {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.zoom-0 {
|
||||
height: 11.25rem;
|
||||
/* this is a bit of a hack, because we can't supply direct class names
|
||||
to the react-select controls */
|
||||
div.react-select__control {
|
||||
background-color: $secondary;
|
||||
border-color: $secondary;
|
||||
color: $text-color;
|
||||
cursor: pointer;
|
||||
|
||||
.react-select__single-value, .react-select__input {
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
.zoom-1 {
|
||||
height: 15rem;
|
||||
.react-select__multi-value {
|
||||
background-color: $muted-gray;
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
|
||||
div.react-select__menu {
|
||||
background-color: $secondary;
|
||||
color: $text-color;
|
||||
|
||||
.react-select__option {
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
.zoom-2 {
|
||||
height: 22.5rem;
|
||||
}
|
||||
|
||||
.zoom-3 {
|
||||
height: 30rem;
|
||||
.react-select__option--is-focused {
|
||||
background-color: #8a9ba826;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +223,8 @@ code {
|
||||
.operation-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 10px auto;
|
||||
align-items: center;
|
||||
margin: 0 auto 10px;
|
||||
}
|
||||
|
||||
.filter-item,
|
||||
@@ -294,6 +363,10 @@ code {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.fa-icon {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.btn {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,16 @@ import { StashService } from "./core/StashService";
|
||||
import "./index.scss";
|
||||
import * as serviceWorker from "./serviceWorker";
|
||||
|
||||
ReactDOM.render(
|
||||
ReactDOM.render((
|
||||
<>
|
||||
<link rel="stylesheet" type="text/css" href={StashService.getPlatformURL() + "css"}/>
|
||||
<BrowserRouter>
|
||||
<ApolloProvider client={StashService.initialize()!}>
|
||||
<App />
|
||||
</ApolloProvider>
|
||||
</BrowserRouter>,
|
||||
document.getElementById("root")
|
||||
</BrowserRouter>
|
||||
</>
|
||||
), document.getElementById("root")
|
||||
);
|
||||
|
||||
// If you want your app to work offline and load faster, you can change
|
||||
|
||||
@@ -25,6 +25,7 @@ $pre-color: $text-color;
|
||||
$navbar-dark-color: rgb(245, 248, 250);
|
||||
$popover-bg: $secondary;
|
||||
$dark-text: #182026;
|
||||
$textfield-bg: rgba(16,22,26,.3);
|
||||
|
||||
@import "node_modules/bootstrap/scss/bootstrap";
|
||||
|
||||
@@ -129,10 +130,6 @@ hr {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
|
||||
.popover {
|
||||
|
||||
@@ -63,6 +63,7 @@ const renderInputGroup = (options: {
|
||||
<td>{options.title}</td>
|
||||
<td>
|
||||
<Form.Control
|
||||
className="text-input"
|
||||
readOnly={!options.isEditing}
|
||||
plaintext={!options.isEditing}
|
||||
defaultValue={options.value}
|
||||
@@ -87,6 +88,7 @@ const renderHtmlSelect = (options: {
|
||||
<td>
|
||||
<Form.Control
|
||||
as="select"
|
||||
className="input-control"
|
||||
disabled={!options.isEditing}
|
||||
plaintext={!options.isEditing}
|
||||
value={options.value?.toString()}
|
||||
|
||||
Reference in New Issue
Block a user