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:
WithoutPants
2020-03-06 20:02:02 +11:00
committed by GitHub
parent 088ddc9df4
commit cb594f0e43
20 changed files with 5381 additions and 92 deletions

View File

@@ -107,7 +107,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
function renderSortByOptions() { function renderSortByOptions() {
return props.filter.sortByOptions.map(option => ( return props.filter.sortByOptions.map(option => (
<Dropdown.Item onClick={onChangeSortBy} key={option}> <Dropdown.Item onClick={onChangeSortBy} key={option} className="bg-secondary text-white">
{option} {option}
</Dropdown.Item> </Dropdown.Item>
)); ));
@@ -186,7 +186,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
function renderSelectAll() { function renderSelectAll() {
if (props.onSelectAll) { if (props.onSelectAll) {
return ( return (
<Dropdown.Item key="select-all" onClick={() => onSelectAll()}> <Dropdown.Item key="select-all" className="bg-secondary text-white" onClick={() => onSelectAll()}>
Select All Select All
</Dropdown.Item> </Dropdown.Item>
); );
@@ -196,7 +196,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
function renderSelectNone() { function renderSelectNone() {
if (props.onSelectNone) { if (props.onSelectNone) {
return ( return (
<Dropdown.Item key="select-none" onClick={() => onSelectNone()}> <Dropdown.Item key="select-none" className="bg-secondary text-white" onClick={() => onSelectNone()}>
Select None Select None
</Dropdown.Item> </Dropdown.Item>
); );
@@ -209,7 +209,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
if (props.otherOperations) { if (props.otherOperations) {
props.otherOperations.forEach(o => { props.otherOperations.forEach(o => {
options.push( 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} {o.text}
</Dropdown.Item> </Dropdown.Item>
); );
@@ -222,7 +222,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
<Dropdown.Toggle variant="secondary" id="more-menu"> <Dropdown.Toggle variant="secondary" id="more-menu">
<Icon icon="ellipsis-h" /> <Icon icon="ellipsis-h" />
</Dropdown.Toggle> </Dropdown.Toggle>
<Dropdown.Menu>{options}</Dropdown.Menu> <Dropdown.Menu className="bg-secondary text-white">{options}</Dropdown.Menu>
</Dropdown> </Dropdown>
); );
} }
@@ -259,13 +259,13 @@ export const ListFilter: React.FC<IListFilterProps> = (
placeholder="Search..." placeholder="Search..."
defaultValue={props.filter.searchTerm} defaultValue={props.filter.searchTerm}
onChange={onChangeQuery} 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 <Form.Control
as="select" as="select"
onChange={onChangePageSize} onChange={onChangePageSize}
value={props.filter.itemsPerPage.toString()} 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 => ( {PAGE_SIZE_OPTIONS.map(s => (
<option value={s} key={s}> <option value={s} key={s}>
@@ -278,7 +278,7 @@ export const ListFilter: React.FC<IListFilterProps> = (
<Dropdown.Toggle split 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 className="bg-secondary text-white">{renderSortByOptions()}</Dropdown.Menu>
<OverlayTrigger <OverlayTrigger
overlay={ overlay={
<Tooltip id="sort-direction-tooltip"> <Tooltip id="sort-direction-tooltip">

View File

@@ -73,20 +73,20 @@ export const MainNavbar: React.FC = () => {
variant="dark" variant="dark"
bg="dark" bg="dark"
className="top-nav" 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="/"> <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 Stash
</Button> </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="" /> <img src="favicon.ico" alt="" />
</Button> </Button>
</Link> </Link>
</Navbar.Brand> </Navbar.Brand>
<Navbar.Toggle className="order-0" /> <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"> <Nav className="mr-md-auto">
{menuItems.map(i => ( {menuItems.map(i => (
<Nav.Link eventKey={i.href} as="div" key={i.href}> <Nav.Link eventKey={i.href} as="div" key={i.href}>

View File

@@ -298,6 +298,7 @@ export const PerformerDetailsPanel: React.FC<IPerformerDetails> = ({
</td> </td>
<td> <td>
<Form.Control <Form.Control
className="text-input"
value={url ?? ""} value={url ?? ""}
readOnly={!isEditing} readOnly={!isEditing}
plaintext={!isEditing} plaintext={!isEditing}

View File

@@ -235,11 +235,9 @@ export const SceneCard: React.FC<ISceneCardProps> = (
: TextUtils.fileNameFromPath(props.scene.path)} : TextUtils.fileNameFromPath(props.scene.path)}
</h5> </h5>
<span>{props.scene.date}</span> <span>{props.scene.date}</span>
{props.scene.details && (
<p> <p>
{TextUtils.truncate(props.scene.details, 100, "... (continued)")} {props.scene.details && TextUtils.truncate(props.scene.details, 100, "... (continued)")}
</p> </p>
)}
</div> </div>
{maybeRenderPopoverButtonGroup()} {maybeRenderPopoverButtonGroup()}

View File

@@ -140,7 +140,6 @@ export const Scene: React.FC = () => {
<Tab <Tab
eventKey="scene-edit-panel" eventKey="scene-edit-panel"
title="Edit" title="Edit"
tabClassName="d-none d-sm-block"
> >
<SceneEditPanel <SceneEditPanel
scene={scene} scene={scene}

View File

@@ -310,6 +310,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
} }
value={url} value={url}
placeholder="URL" placeholder="URL"
className="text-input"
/> />
{maybeRenderScrapeButton()} {maybeRenderScrapeButton()}
</td> </td>
@@ -318,7 +319,8 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
title: "Date", title: "Date",
value: date, value: date,
isEditing: true, isEditing: true,
onChange: setDate onChange: setDate,
placeholder: "YYYY-MM-DD"
})} })}
{TableUtils.renderHtmlSelect({ {TableUtils.renderHtmlSelect({
title: "Rating", title: "Rating",
@@ -342,7 +344,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
<td>Studio</td> <td>Studio</td>
<td> <td>
<StudioSelect <StudioSelect
onSelect={items => items.length && setStudioId(items[0]?.id)} onSelect={items => setStudioId(items.length > 0 ? items[0]?.id : undefined)}
ids={studioId ? [studioId] : []} ids={studioId ? [studioId] : []}
/> />
</td> </td>
@@ -377,7 +379,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
<Form.Label>Details</Form.Label> <Form.Label>Details</Form.Label>
<Form.Control <Form.Control
as="textarea" as="textarea"
className="scene-description" className="scene-description text-input"
onChange={(newValue: React.FormEvent<HTMLTextAreaElement>) => onChange={(newValue: React.FormEvent<HTMLTextAreaElement>) =>
setDetails(newValue.currentTarget.value) setDetails(newValue.currentTarget.value)
} }

View File

@@ -11,7 +11,7 @@ import { SettingsTasksPanel } from "./SettingsTasksPanel/SettingsTasksPanel";
export const Settings: React.FC = () => { export const Settings: React.FC = () => {
const location = useLocation(); const location = useLocation();
const history = useHistory(); 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}`); const onSelect = (val: string) => history.push(`?tab=${val}`);
@@ -23,7 +23,7 @@ export const Settings: React.FC = () => {
onSelect={onSelect} onSelect={onSelect}
> >
<Row> <Row>
<Col sm={2}> <Col sm={3} md={2}>
<Nav variant="pills" className="flex-column"> <Nav variant="pills" className="flex-column">
<Nav.Item> <Nav.Item>
<Nav.Link eventKey="configuration">Configuration</Nav.Link> <Nav.Link eventKey="configuration">Configuration</Nav.Link>
@@ -43,7 +43,7 @@ export const Settings: React.FC = () => {
<hr className="d-sm-none" /> <hr className="d-sm-none" />
</Nav> </Nav>
</Col> </Col>
<Col sm={10}> <Col sm={9} md={10}>
<Tab.Content> <Tab.Content>
<Tab.Pane eventKey="configuration"> <Tab.Pane eventKey="configuration">
<SettingsConfigurationPanel /> <SettingsConfigurationPanel />

View File

@@ -173,7 +173,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
<Form.Group id="database-path"> <Form.Group id="database-path">
<h6>Database Path</h6> <h6>Database Path</h6>
<Form.Control <Form.Control
className="col col-sm-6" className="col col-sm-6 text-input"
defaultValue={databasePath} defaultValue={databasePath}
onChange={(e: React.FormEvent<HTMLInputElement>) => onChange={(e: React.FormEvent<HTMLInputElement>) =>
setDatabasePath(e.currentTarget.value) setDatabasePath(e.currentTarget.value)
@@ -187,7 +187,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
<Form.Group id="generated-path"> <Form.Group id="generated-path">
<h6>Generated Path</h6> <h6>Generated Path</h6>
<Form.Control <Form.Control
className="col col-sm-6" className="col col-sm-6 text-input"
defaultValue={generatedPath} defaultValue={generatedPath}
onChange={(e: React.FormEvent<HTMLInputElement>) => onChange={(e: React.FormEvent<HTMLInputElement>) =>
setGeneratedPath(e.currentTarget.value) setGeneratedPath(e.currentTarget.value)
@@ -206,7 +206,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
excludes.map((regexp, i) => ( excludes.map((regexp, i) => (
<InputGroup> <InputGroup>
<Form.Control <Form.Control
className="col col-sm-6" className="col col-sm-6 text-input"
value={regexp} value={regexp}
onChange={(e: React.FormEvent<HTMLInputElement>) => onChange={(e: React.FormEvent<HTMLInputElement>) =>
excludeRegexChanged(i, e.currentTarget.value) excludeRegexChanged(i, e.currentTarget.value)
@@ -226,15 +226,13 @@ export const SettingsConfigurationPanel: React.FC = () => {
<Button className="minimal" onClick={() => excludeAddRegex()}> <Button className="minimal" onClick={() => excludeAddRegex()}>
<Icon icon="plus" /> <Icon icon="plus" />
</Button> </Button>
<Form.Text> <Form.Text className="text-muted">
Regexps of files/paths to exclude from Scan and add to Clean
<a <a
href="https://github.com/stashapp/stash/wiki/Exclude-file-configuration" href="https://github.com/stashapp/stash/wiki/Exclude-file-configuration"
rel="noopener noreferrer" rel="noopener noreferrer"
target="_blank" target="_blank"
> >
<span>
Regexps of files/paths to exclude from Scan and add to Clean
</span>
<Icon icon="question-circle" /> <Icon icon="question-circle" />
</a> </a>
</Form.Text> </Form.Text>
@@ -248,7 +246,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
<Form.Group id="transcode-size"> <Form.Group id="transcode-size">
<h6>Maximum transcode size</h6> <h6>Maximum transcode size</h6>
<Form.Control <Form.Control
className="col col-sm-6" className="col col-sm-6 input-control"
as="select" as="select"
onChange={(event: React.FormEvent<HTMLSelectElement>) => onChange={(event: React.FormEvent<HTMLSelectElement>) =>
setMaxTranscodeSize(translateQuality(event.currentTarget.value)) setMaxTranscodeSize(translateQuality(event.currentTarget.value))
@@ -268,7 +266,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
<Form.Group id="streaming-transcode-size"> <Form.Group id="streaming-transcode-size">
<h6>Maximum streaming transcode size</h6> <h6>Maximum streaming transcode size</h6>
<Form.Control <Form.Control
className="col col-sm-6" className="col col-sm-6 input-control"
as="select" as="select"
onChange={(event: React.FormEvent<HTMLSelectElement>) => onChange={(event: React.FormEvent<HTMLSelectElement>) =>
setMaxStreamingTranscodeSize( setMaxStreamingTranscodeSize(
@@ -296,7 +294,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
<Form.Group id="username"> <Form.Group id="username">
<h6>Username</h6> <h6>Username</h6>
<Form.Control <Form.Control
className="col col-sm-6" className="col col-sm-6 text-input"
defaultValue={username} defaultValue={username}
onChange={(e: React.FormEvent<HTMLInputElement>) => onChange={(e: React.FormEvent<HTMLInputElement>) =>
setUsername(e.currentTarget.value) setUsername(e.currentTarget.value)
@@ -309,7 +307,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
<Form.Group id="password"> <Form.Group id="password">
<h6>Password</h6> <h6>Password</h6>
<Form.Control <Form.Control
className="col col-sm-6" className="col col-sm-6 text-input"
type="password" type="password"
defaultValue={password} defaultValue={password}
onChange={(e: React.FormEvent<HTMLInputElement>) => onChange={(e: React.FormEvent<HTMLInputElement>) =>
@@ -328,7 +326,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
<Form.Group id="log-file"> <Form.Group id="log-file">
<h6>Log file</h6> <h6>Log file</h6>
<Form.Control <Form.Control
className="col col-sm-6" className="col col-sm-6 text-input"
defaultValue={logFile} defaultValue={logFile}
onChange={(e: React.FormEvent<HTMLInputElement>) => onChange={(e: React.FormEvent<HTMLInputElement>) =>
setLogFile(e.currentTarget.value) setLogFile(e.currentTarget.value)
@@ -356,7 +354,7 @@ export const SettingsConfigurationPanel: React.FC = () => {
<Form.Group id="log-level"> <Form.Group id="log-level">
<h6>Log Level</h6> <h6>Log Level</h6>
<Form.Control <Form.Control
className="col col-sm-6" className="col col-sm-6 input-control"
as="select" as="select"
onChange={(event: React.FormEvent<HTMLSelectElement>) => onChange={(event: React.FormEvent<HTMLSelectElement>) =>
setLogLevel(event.currentTarget.value) setLogLevel(event.currentTarget.value)

View File

@@ -56,11 +56,11 @@ export const SettingsInterfacePanel: React.FC = () => {
return ( return (
<> <>
<h4>User Interface</h4> <h4>User Interface</h4>
<Form.Group controlId="language" className="row"> <Form.Group controlId="language">
<Form.Label className="col-2">Language</Form.Label> <h6>Language</h6>
<Form.Control <Form.Control
as="select" as="select"
className="col-4" className="col-4 input-control"
value={language} value={language}
onChange={(e: React.FormEvent<HTMLSelectElement>) => onChange={(e: React.FormEvent<HTMLSelectElement>) =>
setLanguage(e.currentTarget.value) setLanguage(e.currentTarget.value)
@@ -72,7 +72,7 @@ export const SettingsInterfacePanel: React.FC = () => {
</Form.Control> </Form.Control>
</Form.Group> </Form.Group>
<Form.Group> <Form.Group>
<Form.Label>Scene / Marker Wall</Form.Label> <h5>Scene / Marker Wall</h5>
<Form.Check <Form.Check
id="wall-show-title" id="wall-show-title"
checked={wallShowTitle} checked={wallShowTitle}
@@ -104,19 +104,20 @@ export const SettingsInterfacePanel: React.FC = () => {
<Form.Group> <Form.Group>
<h5>Scene Player</h5> <h5>Scene Player</h5>
<Form.Group id="auto-start-video">
<Form.Check <Form.Check
id="auto-start-video"
checked={autostartVideo} checked={autostartVideo}
label="Auto-start video" label="Auto-start video"
onChange={() => { onChange={() => {
setAutostartVideo(!autostartVideo); setAutostartVideo(!autostartVideo);
}} }}
/> />
</Form.Group>
<Form.Group id="max-loop-duration"> <Form.Group id="max-loop-duration">
<Form.Label>Maximum loop duration</Form.Label> <h6>Maximum loop duration</h6>
<DurationInput <DurationInput
className="col col-sm-4" className="row col col-4"
numericValue={maximumLoopDuration} numericValue={maximumLoopDuration}
onValueChange={duration => setMaximumLoopDuration(duration)} onValueChange={duration => setMaximumLoopDuration(duration)}
/> />
@@ -145,7 +146,7 @@ export const SettingsInterfacePanel: React.FC = () => {
setCSS(e.currentTarget.value) setCSS(e.currentTarget.value)
} }
rows={16} rows={16}
className="col col-sm-6" className="col col-sm-6 text-input code"
></Form.Control> ></Form.Control>
<Form.Text className="text-muted"> <Form.Text className="text-muted">
Page must be reloaded for changes to take effect. Page must be reloaded for changes to take effect.

View File

@@ -101,7 +101,7 @@ export const SettingsLogsPanel: React.FC = () => {
<Form.Row id="log-level"> <Form.Row id="log-level">
<Form.Label className="col-6 col-sm-2">Log Level</Form.Label> <Form.Label className="col-6 col-sm-2">Log Level</Form.Label>
<Form.Control <Form.Control
className="col-6 col-sm-2" className="col-6 col-sm-2 input-control"
as="select" as="select"
defaultValue={logLevel} defaultValue={logLevel}
onChange={event => setLogLevel(event.currentTarget.value)} onChange={event => setLogLevel(event.currentTarget.value)}

View File

@@ -167,8 +167,8 @@ export const SettingsTasksPanel: React.FC = () => {
<> <>
<Form.Group> <Form.Group>
<h5>Status: {status}</h5> <h5>Status: {status}</h5>
{status !== "Idle" ? ( {!!status && status !== "Idle" ? (
<ProgressBar now={progress} label={`${progress}%`} /> <ProgressBar animated now={progress} label={`${progress.toFixed(0)}%`} />
) : ( ) : (
"" ""
)} )}
@@ -183,7 +183,7 @@ export const SettingsTasksPanel: React.FC = () => {
{renderImportAlert()} {renderImportAlert()}
{renderCleanAlert()} {renderCleanAlert()}
<h5>Running Jobs</h5> <h4>Running Jobs</h4>
{renderJobStatus()} {renderJobStatus()}

View File

@@ -31,3 +31,7 @@
.log-time { .log-time {
margin-right: 1rem; margin-right: 1rem;
} }
#configuration-tabs-tabpane-about .table {
width: initial;
}

View File

@@ -75,7 +75,7 @@ export const DurationInput: React.FC<IProps> = (props: IProps) => {
<Form.Group className={`duration-input ${props.className}`}> <Form.Group className={`duration-input ${props.className}`}>
<InputGroup> <InputGroup>
<Form.Control <Form.Control
className="duration-control" className="duration-control text-input"
disabled={props.disabled} disabled={props.disabled}
value={value} value={value}
onChange={(e: React.FormEvent<HTMLInputElement>) => onChange={(e: React.FormEvent<HTMLInputElement>) =>

View File

@@ -73,16 +73,20 @@ export const SceneGallerySelect: React.FC<ISceneGallerySelect> = props => {
const onChange = (selectedItems: ValueType<Option>) => { const onChange = (selectedItems: ValueType<Option>) => {
const selectedItem = getSelectedValues(selectedItems)[0]; 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 ( return (
<SelectComponent <SelectComponent
className="input-control"
onChange={onChange} onChange={onChange}
isLoading={loading} isLoading={loading}
items={items} items={items}
initialIds={initialId} selectedOptions={selectedOptions}
/> />
); );
}; };
@@ -207,10 +211,15 @@ export const StudioSelect: React.FC<IFilterProps> = props => {
const { data, loading } = StashService.useAllStudiosForFilter(); const { data, loading } = StashService.useAllStudiosForFilter();
const normalizedData = data?.allStudios ?? []; 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, value: item.id,
label: item.name label: item.name
})); }));
const placeholder = props.noSelectionString ?? "Select studio..."; const placeholder = props.noSelectionString ?? "Select studio...";
const selectedOptions: Option[] = props.ids const selectedOptions: Option[] = props.ids
? items.filter(item => props.ids?.indexOf(item.value) !== -1) ? items.filter(item => props.ids?.indexOf(item.value) !== -1)
@@ -358,6 +367,7 @@ const SelectComponent: React.FC<ISelectProps & ITypeProps> = ({
options, options,
value: selectedOptions, value: selectedOptions,
className, className,
classNamePrefix: "react-select",
onChange, onChange,
isMulti, isMulti,
isClearable, isClearable,

View File

@@ -11,23 +11,32 @@ export class StashService {
public static client: ApolloClient<NormalizedCacheObject>; public static client: ApolloClient<NormalizedCacheObject>;
private static cache: InMemoryCache; private static cache: InMemoryCache;
public static initialize() { public static getPlatformURL(ws? : boolean) {
const platformUrl = new URL(window.location.origin); 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") { if (!process.env.NODE_ENV || process.env.NODE_ENV === "development") {
platformUrl.port = "9999"; // TODO: Hack. Development expects port 9999 platformUrl.port = "9999"; // TODO: Hack. Development expects port 9999
wsPlatformUrl.port = "9999";
if (process.env.REACT_APP_HTTPS === "true") { if (process.env.REACT_APP_HTTPS === "true") {
platformUrl.protocol = "https:"; 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:") { if (platformUrl.protocol === "https:") {
wsPlatformUrl.protocol = "wss:"; wsPlatformUrl.protocol = "wss:";
} }
const url = `${platformUrl.toString().slice(0, -1)}/graphql`; const url = `${platformUrl.toString().slice(0, -1)}/graphql`;
const wsUrl = `${wsPlatformUrl.toString().slice(0, -1)}/graphql`; const wsUrl = `${wsPlatformUrl.toString().slice(0, -1)}/graphql`;

File diff suppressed because it is too large Load Diff

View File

@@ -23,16 +23,40 @@ body {
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
margin: 0; margin: 0;
padding: 4rem 0 0 0; padding: 4rem 0 0 0;
@media (min-width: 600px) {
min-width: 845px;
}
} }
code { a {
color: $primary;
}
code, .code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; 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);
}
}
.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 { .table-list table {
width: inherit; width: inherit;
} }
@@ -56,40 +80,84 @@ code {
@media (min-width: 576px) { @media (min-width: 576px) {
.zoom-0 { .zoom-0 {
width: 15rem; width: 240px;
.scene-card-video {
max-height: 180px;
}
.previewable.portrait {
height: 180px;
}
} }
.zoom-1 { .zoom-1 {
width: 20rem; width: 320px;
.scene-card-video {
max-height: 240px;
}
.previewable.portrait {
height: 240px;
}
} }
.zoom-2 { .zoom-2 {
width: 30rem; width: 480px;
.scene-card-video {
max-height: 360px;
}
.previewable.portrait {
height: 360px;
}
} }
.zoom-3 { .zoom-3 {
width: 40rem; width: 640px;
.scene-card-video {
max-height: 480px;
}
.portrait {
height: 480px;
}
} }
} }
.scene-card-video { .scene-card-video {
height: auto; height: auto;
width: 100%; width: 100%;
.zoom-0 {
height: 11.25rem;
} }
.zoom-1 { /* this is a bit of a hack, because we can't supply direct class names
height: 15rem; 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-2 { .react-select__multi-value {
height: 22.5rem; background-color: $muted-gray;
color: $text-color;
}
} }
.zoom-3 { div.react-select__menu {
height: 30rem; background-color: $secondary;
color: $text-color;
.react-select__option {
color: $text-color;
}
.react-select__option--is-focused {
background-color: #8a9ba826;
cursor: pointer;
} }
} }
@@ -155,7 +223,8 @@ code {
.operation-container { .operation-container {
display: flex; display: flex;
justify-content: center; justify-content: center;
margin: 10px auto; align-items: center;
margin: 0 auto 10px;
} }
.filter-item, .filter-item,
@@ -294,6 +363,10 @@ code {
padding: 0; padding: 0;
} }
.fa-icon {
margin-left: 0;
}
.btn { .btn {
white-space: nowrap; white-space: nowrap;
} }

View File

@@ -7,13 +7,16 @@ import { StashService } from "./core/StashService";
import "./index.scss"; import "./index.scss";
import * as serviceWorker from "./serviceWorker"; import * as serviceWorker from "./serviceWorker";
ReactDOM.render( ReactDOM.render((
<>
<link rel="stylesheet" type="text/css" href={StashService.getPlatformURL() + "css"}/>
<BrowserRouter> <BrowserRouter>
<ApolloProvider client={StashService.initialize()!}> <ApolloProvider client={StashService.initialize()!}>
<App /> <App />
</ApolloProvider> </ApolloProvider>
</BrowserRouter>, </BrowserRouter>
document.getElementById("root") </>
), document.getElementById("root")
); );
// If you want your app to work offline and load faster, you can change // If you want your app to work offline and load faster, you can change

View File

@@ -25,6 +25,7 @@ $pre-color: $text-color;
$navbar-dark-color: rgb(245, 248, 250); $navbar-dark-color: rgb(245, 248, 250);
$popover-bg: $secondary; $popover-bg: $secondary;
$dark-text: #182026; $dark-text: #182026;
$textfield-bg: rgba(16,22,26,.3);
@import "node_modules/bootstrap/scss/bootstrap"; @import "node_modules/bootstrap/scss/bootstrap";
@@ -129,10 +130,6 @@ hr {
padding-right: 0; padding-right: 0;
} }
} }
a {
color: $text-color;
}
} }
.popover { .popover {

View File

@@ -63,6 +63,7 @@ const renderInputGroup = (options: {
<td>{options.title}</td> <td>{options.title}</td>
<td> <td>
<Form.Control <Form.Control
className="text-input"
readOnly={!options.isEditing} readOnly={!options.isEditing}
plaintext={!options.isEditing} plaintext={!options.isEditing}
defaultValue={options.value} defaultValue={options.value}
@@ -87,6 +88,7 @@ const renderHtmlSelect = (options: {
<td> <td>
<Form.Control <Form.Control
as="select" as="select"
className="input-control"
disabled={!options.isEditing} disabled={!options.isEditing}
plaintext={!options.isEditing} plaintext={!options.isEditing}
value={options.value?.toString()} value={options.value?.toString()}