refactor(webui): lean import buttons on shared styles
- move the import page over to shared button variants and option buttons - strip route-local button chrome back to layout-only helpers - keep the import route styling focused on layout, cards, and state indicators
This commit is contained in:
parent
b78350a3e2
commit
d066aba03d
7 changed files with 70 additions and 273 deletions
|
|
@ -408,6 +408,14 @@
|
||||||
box-shadow: 0 0 0 1px rgba(var(--accent-light-rgb), 0.08);
|
box-shadow: 0 0 0 1px rgba(var(--accent-light-rgb), 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.optionButtonSelected:hover {
|
||||||
|
border-color: rgba(var(--accent-light-rgb), 0.62);
|
||||||
|
background: rgba(var(--accent-rgb), 0.26);
|
||||||
|
box-shadow:
|
||||||
|
0 0 0 1px rgba(var(--accent-light-rgb), 0.12),
|
||||||
|
0 10px 24px rgba(0, 0, 0, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -498,6 +506,29 @@
|
||||||
color: rgba(0, 0, 0, 0.55);
|
color: rgba(0, 0, 0, 0.55);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.buttonSecondary {
|
||||||
|
border-color: rgba(255, 255, 255, 0.12);
|
||||||
|
background: rgba(255, 255, 255, 0.08);
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonSecondary:hover:not(:disabled) {
|
||||||
|
border-color: rgba(255, 255, 255, 0.18);
|
||||||
|
background: rgba(255, 255, 255, 0.14);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonSecondary:focus-visible {
|
||||||
|
border-color: rgba(var(--accent-light-rgb), 0.45);
|
||||||
|
box-shadow: 0 0 0 3px rgba(var(--accent-light-rgb), 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonSecondary:disabled {
|
||||||
|
opacity: 0.55;
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
color: rgba(255, 255, 255, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
.buttonGhost {
|
.buttonGhost {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|
|
||||||
|
|
@ -266,7 +266,7 @@ type BaseButtonProps = ComponentPropsWithoutRef<typeof BaseButton>;
|
||||||
export type ButtonProps = Omit<BaseButtonProps, 'className'> & {
|
export type ButtonProps = Omit<BaseButtonProps, 'className'> & {
|
||||||
className?: string;
|
className?: string;
|
||||||
size?: 'sm' | 'md' | 'lg' | 'icon';
|
size?: 'sm' | 'md' | 'lg' | 'icon';
|
||||||
variant?: 'default' | 'primary' | 'ghost';
|
variant?: 'default' | 'primary' | 'secondary' | 'ghost';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
|
||||||
|
|
@ -284,6 +284,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
|
||||||
[styles.buttonSizeLg]: size === 'lg',
|
[styles.buttonSizeLg]: size === 'lg',
|
||||||
[styles.buttonIcon]: size === 'icon',
|
[styles.buttonIcon]: size === 'icon',
|
||||||
[styles.buttonPrimary]: variant === 'primary',
|
[styles.buttonPrimary]: variant === 'primary',
|
||||||
|
[styles.buttonSecondary]: variant === 'secondary',
|
||||||
[styles.buttonGhost]: variant === 'ghost',
|
[styles.buttonGhost]: variant === 'ghost',
|
||||||
},
|
},
|
||||||
className,
|
className,
|
||||||
|
|
|
||||||
|
|
@ -301,6 +301,7 @@ function AlbumImportPanelContent({ viewModel }: { viewModel: AlbumImportViewMode
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
className={albumResults === null ? styles.hidden : ''}
|
className={albumResults === null ? styles.hidden : ''}
|
||||||
id="import-page-album-clear-btn"
|
id="import-page-album-clear-btn"
|
||||||
title="Clear search"
|
title="Clear search"
|
||||||
|
|
@ -436,14 +437,16 @@ function AlbumMatchPanel({ viewModel }: { viewModel: AlbumImportViewModel }) {
|
||||||
<div className={styles.importPageMatchActions}>
|
<div className={styles.importPageMatchActions}>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.importPageSecondaryBtn}
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
onClick={onAutoRematch}
|
onClick={onAutoRematch}
|
||||||
>
|
>
|
||||||
Re-match Automatically
|
Re-match Automatically
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.importPageBackBtn}
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
onClick={onBackToSearch}
|
onClick={onBackToSearch}
|
||||||
>
|
>
|
||||||
Back to Search
|
Back to Search
|
||||||
|
|
@ -509,7 +512,8 @@ function AlbumMatchPanel({ viewModel }: { viewModel: AlbumImportViewModel }) {
|
||||||
{file ? (
|
{file ? (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.importPageMatchUnmatch}
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onUnmatchTrack(index);
|
onUnmatchTrack(index);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { Button, RangeInput, Select, Switch } from '@/components/form/form';
|
import { Button, OptionButton, OptionButtonGroup, RangeInput, Select, Switch } from '@/components/form/form';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ImportAutoFilter,
|
ImportAutoFilter,
|
||||||
|
|
@ -171,10 +171,12 @@ export function AutoImportPanel({
|
||||||
>
|
>
|
||||||
{getAutoImportStatusText(statusQuery.data)}
|
{getAutoImportStatusText(statusQuery.data)}
|
||||||
</span>
|
</span>
|
||||||
|
<div className={styles.importPageFlexSpacer} />
|
||||||
{statusQuery.data?.running ? (
|
{statusQuery.data?.running ? (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.autoImportScanNowBtn}
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
id="auto-import-scan-now"
|
id="auto-import-scan-now"
|
||||||
title="Scan import folder now"
|
title="Scan import folder now"
|
||||||
disabled={scanMutation.isPending}
|
disabled={scanMutation.isPending}
|
||||||
|
|
@ -215,7 +217,8 @@ export function AutoImportPanel({
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={`${styles.autoImportActionBtn} ${styles.autoImportActionSecondary}`}
|
variant="primary"
|
||||||
|
size="sm"
|
||||||
disabled={saveSettingsMutation.isPending}
|
disabled={saveSettingsMutation.isPending}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
saveSettingsMutation.mutate({
|
saveSettingsMutation.mutate({
|
||||||
|
|
@ -264,25 +267,22 @@ export function AutoImportPanel({
|
||||||
{counts.failed} failed
|
{counts.failed} failed
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.autoImportFilters} id="auto-import-filters">
|
<OptionButtonGroup className={styles.autoImportFilters}>
|
||||||
{(['all', 'pending', 'imported', 'failed'] as const).map((filter) => (
|
{(['all', 'pending', 'imported', 'failed'] as const).map((filter) => (
|
||||||
<Button
|
<OptionButton
|
||||||
key={filter}
|
key={filter}
|
||||||
type="button"
|
selected={autoFilter === filter}
|
||||||
className={`${styles.autoImportFilterPill} ${
|
|
||||||
autoFilter === filter ? styles.active : ''
|
|
||||||
}`}
|
|
||||||
data-filter={filter}
|
|
||||||
onClick={() => onFilterChange(filter)}
|
onClick={() => onFilterChange(filter)}
|
||||||
>
|
>
|
||||||
{filter === 'pending' ? 'Needs Review' : titleCase(filter)}
|
{filter === 'pending' ? 'Needs Review' : titleCase(filter)}
|
||||||
</Button>
|
</OptionButton>
|
||||||
))}
|
))}
|
||||||
<div className={styles.importPageFlexSpacer} />
|
<div className={styles.importPageFlexSpacer} />
|
||||||
{counts.review > 0 ? (
|
{counts.review > 0 ? (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.autoImportBatchBtn}
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
id="auto-import-approve-all"
|
id="auto-import-approve-all"
|
||||||
disabled={approveAllMutation.isPending}
|
disabled={approveAllMutation.isPending}
|
||||||
onClick={() => approveAllMutation.mutate()}
|
onClick={() => approveAllMutation.mutate()}
|
||||||
|
|
@ -293,7 +293,8 @@ export function AutoImportPanel({
|
||||||
{counts.imported + counts.failed > 0 ? (
|
{counts.imported + counts.failed > 0 ? (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={`${styles.autoImportBatchBtn} ${styles.autoImportClearBtn}`}
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
id="auto-import-clear-completed"
|
id="auto-import-clear-completed"
|
||||||
disabled={clearMutation.isPending}
|
disabled={clearMutation.isPending}
|
||||||
onClick={() => clearMutation.mutate()}
|
onClick={() => clearMutation.mutate()}
|
||||||
|
|
@ -301,7 +302,7 @@ export function AutoImportPanel({
|
||||||
Clear History
|
Clear History
|
||||||
</Button>
|
</Button>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</OptionButtonGroup>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
|
@ -449,7 +450,8 @@ function AutoImportResultCard({
|
||||||
<div className={styles.autoImportActions}>
|
<div className={styles.autoImportActions}>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={`${styles.autoImportActionBtn} ${styles.autoImportActionPrimary}`}
|
variant="primary"
|
||||||
|
size="sm"
|
||||||
disabled={approvePending}
|
disabled={approvePending}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
@ -460,7 +462,8 @@ function AutoImportResultCard({
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={`${styles.autoImportActionBtn} ${styles.autoImportActionSecondary}`}
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
disabled={rejectPending}
|
disabled={rejectPending}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
|
||||||
|
|
@ -44,30 +44,6 @@
|
||||||
animation: page-title-shimmer 6s ease-in-out infinite;
|
animation: page-title-shimmer 6s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.importPageRefreshBtn {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
background: rgba(255, 255, 255, 0.08);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
||||||
border-radius: 8px;
|
|
||||||
color: #ccc;
|
|
||||||
font-size: 13px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageRefreshBtn:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.14);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageRefreshBtnRefreshing {
|
|
||||||
opacity: 0.72;
|
|
||||||
cursor: progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageStagingBar {
|
.importPageStagingBar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -175,12 +151,6 @@
|
||||||
border-color: rgba(var(--accent-light-rgb), 0.5);
|
border-color: rgba(var(--accent-light-rgb), 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.importPageSearchBar > button {
|
|
||||||
align-self: stretch;
|
|
||||||
min-width: 40px;
|
|
||||||
padding: 0 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Album grid */
|
/* Album grid */
|
||||||
.importPageAlbumGrid {
|
.importPageAlbumGrid {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|
@ -416,25 +386,6 @@
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
.importPageMatchUnmatch {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: rgba(255, 255, 255, 0.3);
|
|
||||||
font-size: 14px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 4px;
|
|
||||||
border-radius: 4px;
|
|
||||||
transition: all 0.2s;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageMatchUnmatch:hover {
|
|
||||||
color: #ff4444;
|
|
||||||
background: rgba(255, 68, 68, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unmatched file pool */
|
/* Unmatched file pool */
|
||||||
.importPageUnmatchedPool {
|
.importPageUnmatchedPool {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
|
@ -508,30 +459,6 @@
|
||||||
color: rgba(255, 255, 255, 0.5);
|
color: rgba(255, 255, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.importPageSecondaryBtn {
|
|
||||||
background: rgba(255, 255, 255, 0.08);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
||||||
color: #ccc;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageSecondaryBtn:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.14);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageBackBtn {
|
|
||||||
background: none;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
color: rgba(255, 255, 255, 0.5);
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageBackBtn:hover {
|
|
||||||
color: #fff;
|
|
||||||
border-color: rgba(255, 255, 255, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Singles */
|
/* Singles */
|
||||||
.importPageSinglesHeader {
|
.importPageSinglesHeader {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -631,25 +558,6 @@
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.importPageIdentifyBtn {
|
|
||||||
padding: 6px 12px;
|
|
||||||
background: rgba(255, 255, 255, 0.08);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
||||||
border-radius: 6px;
|
|
||||||
color: #ccc;
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageIdentifyBtn:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.14);
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Inline search panel for singles */
|
/* Inline search panel for singles */
|
||||||
.importPageSingleSearchPanel {
|
.importPageSingleSearchPanel {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
|
|
@ -677,17 +585,6 @@
|
||||||
border-color: rgba(var(--accent-light-rgb), 0.4);
|
border-color: rgba(var(--accent-light-rgb), 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.importPageSingleSearchGo {
|
|
||||||
padding: 8px 14px;
|
|
||||||
background: rgb(var(--accent-light-rgb));
|
|
||||||
border: none;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: #000;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 600;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageSingleSearchResults {
|
.importPageSingleSearchResults {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -796,19 +693,6 @@
|
||||||
letter-spacing: 0.5px;
|
letter-spacing: 0.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.importPageQueueClear {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: rgba(255, 255, 255, 0.3);
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 2px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageQueueClear:hover {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageQueueList {
|
.importPageQueueList {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
@ -956,11 +840,6 @@
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.importPageMatchUnmatch {
|
|
||||||
grid-area: unmatch;
|
|
||||||
justify-self: end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.importPageSinglesHeader {
|
.importPageSinglesHeader {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
@ -1097,7 +976,6 @@
|
||||||
|
|
||||||
.autoImportCard:hover {
|
.autoImportCard:hover {
|
||||||
background: rgba(255, 255, 255, 0.04);
|
background: rgba(255, 255, 255, 0.04);
|
||||||
border-color: rgba(255, 255, 255, 0.1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.autoImportCompleted {
|
.autoImportCompleted {
|
||||||
|
|
@ -1214,27 +1092,6 @@
|
||||||
color: rgba(255, 255, 255, 0.5);
|
color: rgba(255, 255, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan Now button */
|
|
||||||
.autoImportScanNowBtn {
|
|
||||||
background: rgba(255, 255, 255, 0.06);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
color: rgba(255, 255, 255, 0.6);
|
|
||||||
font-size: 11px;
|
|
||||||
padding: 4px 12px;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 5px;
|
|
||||||
transition: all 0.15s;
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportScanNowBtn:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
color: rgba(255, 255, 255, 0.9);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Live progress */
|
/* Live progress */
|
||||||
.autoImportProgress {
|
.autoImportProgress {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
|
@ -1288,105 +1145,10 @@
|
||||||
|
|
||||||
/* Filter pills */
|
/* Filter pills */
|
||||||
.autoImportFilters {
|
.autoImportFilters {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 6px 0;
|
padding: 6px 0;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autoImportFilterPill {
|
|
||||||
padding: 6px 16px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
color: rgba(255, 255, 255, 0.45);
|
|
||||||
font-size: 0.78rem;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportFilterPill:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.05);
|
|
||||||
color: rgba(255, 255, 255, 0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportFilterPill.active {
|
|
||||||
background: rgba(var(--accent-rgb), 0.15);
|
|
||||||
color: rgb(var(--accent-light-rgb));
|
|
||||||
box-shadow: 0 2px 8px rgba(var(--accent-rgb), 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportActionBtn {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 7px;
|
|
||||||
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
|
||||||
white-space: nowrap;
|
|
||||||
letter-spacing: 0.1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportActionPrimary {
|
|
||||||
background: linear-gradient(135deg, rgb(var(--accent-rgb)), rgba(var(--accent-rgb), 0.85));
|
|
||||||
color: #fff;
|
|
||||||
border-color: rgba(var(--accent-rgb), 0.3);
|
|
||||||
box-shadow: 0 2px 8px rgba(var(--accent-rgb), 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportActionPrimary:hover {
|
|
||||||
transform: translateY(-1px);
|
|
||||||
box-shadow: 0 4px 14px rgba(var(--accent-rgb), 0.3);
|
|
||||||
filter: brightness(1.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportActionPrimary:disabled {
|
|
||||||
opacity: 0.45;
|
|
||||||
cursor: not-allowed;
|
|
||||||
transform: none;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportActionSecondary {
|
|
||||||
background: rgba(255, 255, 255, 0.05);
|
|
||||||
color: rgba(255, 255, 255, 0.7);
|
|
||||||
border-color: rgba(255, 255, 255, 0.08);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportActionSecondary:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
color: #fff;
|
|
||||||
border-color: rgba(255, 255, 255, 0.15);
|
|
||||||
transform: translateY(-1px);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Batch action buttons */
|
|
||||||
.autoImportBatchBtn {
|
|
||||||
font-size: 11px;
|
|
||||||
padding: 4px 12px;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 1px solid rgba(var(--accent-rgb), 0.3);
|
|
||||||
background: rgba(var(--accent-rgb), 0.08);
|
|
||||||
color: rgba(var(--accent-rgb), 1);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportBatchBtn:hover {
|
|
||||||
background: rgba(var(--accent-rgb), 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportClearBtn {
|
|
||||||
border-color: rgba(255, 255, 255, 0.1);
|
|
||||||
background: rgba(255, 255, 255, 0.04);
|
|
||||||
color: rgba(255, 255, 255, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportClearBtn:hover {
|
|
||||||
background: rgba(255, 255, 255, 0.08);
|
|
||||||
color: rgba(255, 255, 255, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autoImportCardMeta {
|
.autoImportCardMeta {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|
@ -1541,11 +1303,6 @@
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autoImportActions button {
|
|
||||||
font-size: 10px;
|
|
||||||
padding: 3px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.autoImportCard {
|
.autoImportCard {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
|
||||||
|
|
@ -79,9 +79,7 @@ function ImportHeader({
|
||||||
</h1>
|
</h1>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={`${styles.importPageRefreshBtn} ${
|
variant="secondary"
|
||||||
refreshing ? styles.importPageRefreshBtnRefreshing : ''
|
|
||||||
}`}
|
|
||||||
title="Re-scan import folder"
|
title="Re-scan import folder"
|
||||||
aria-busy={refreshing}
|
aria-busy={refreshing}
|
||||||
disabled={refreshing}
|
disabled={refreshing}
|
||||||
|
|
@ -121,7 +119,8 @@ function ImportProcessingQueue() {
|
||||||
<span className={styles.importPageQueueTitle}>Processing</span>
|
<span className={styles.importPageQueueTitle}>Processing</span>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.importPageQueueClear}
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
id="import-page-queue-clear"
|
id="import-page-queue-clear"
|
||||||
style={{ display: hasFinished ? undefined : 'none' }}
|
style={{ display: hasFinished ? undefined : 'none' }}
|
||||||
onClick={clearFinishedJobs}
|
onClick={clearFinishedJobs}
|
||||||
|
|
|
||||||
|
|
@ -169,13 +169,13 @@ export function SinglesImportPanel({
|
||||||
}) {
|
}) {
|
||||||
const selectedCount = files.filter((file) => selected.has(getStagingFileKey(file))).length;
|
const selectedCount = files.filter((file) => selected.has(getStagingFileKey(file))).length;
|
||||||
const allSelected = files.length > 0 && selectedCount === files.length;
|
const allSelected = files.length > 0 && selectedCount === files.length;
|
||||||
const processVariant = selectedCount > 0 ? 'primary' : 'default';
|
const processVariant = selectedCount > 0 ? 'primary' : 'secondary';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.importPageSinglesHeader}>
|
<div className={styles.importPageSinglesHeader}>
|
||||||
<div className={styles.importPageSinglesActions}>
|
<div className={styles.importPageSinglesActions}>
|
||||||
<Button type="button" className={styles.importPageSecondaryBtn} onClick={onSelectAll}>
|
<Button type="button" variant="secondary" size="sm" onClick={onSelectAll}>
|
||||||
<span id="import-page-select-all-text">
|
<span id="import-page-select-all-text">
|
||||||
{allSelected ? 'Deselect All' : 'Select All'}
|
{allSelected ? 'Deselect All' : 'Select All'}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -236,13 +236,14 @@ export function SinglesImportPanel({
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.importPageSingleActions}>
|
<div className={styles.importPageSingleActions}>
|
||||||
<button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.importPageIdentifyBtn}
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
onClick={() => onOpenSearch(file)}
|
onClick={() => onOpenSearch(file)}
|
||||||
>
|
>
|
||||||
🔍 Identify
|
🔍 Identify
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
{openSearchKey === fileKey ? (
|
{openSearchKey === fileKey ? (
|
||||||
<SingleSearchPanel
|
<SingleSearchPanel
|
||||||
|
|
@ -292,7 +293,8 @@ function SingleSearchPanel({
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className={styles.importPageSingleSearchGo}
|
variant="primary"
|
||||||
|
size="sm"
|
||||||
onClick={() => onRunSearch(fileKey, query)}
|
onClick={() => onRunSearch(fileKey, query)}
|
||||||
>
|
>
|
||||||
Search
|
Search
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue