mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-22 10:51:02 +01:00
style: condition tab improvements - add button used instead of generic button - added move up / down functionality - streamlined delte button - improved basic styling
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {Plus, InfoIcon} from 'lucide-react';
|
||||
import {InfoIcon} from 'lucide-react';
|
||||
import {usePatterns} from '@hooks/usePatterns';
|
||||
import {createCondition} from './conditions/conditionTypes';
|
||||
import ConditionCard from './conditions/ConditionCard';
|
||||
import AddButton from '@ui/DataBar/AddButton';
|
||||
|
||||
const FormatConditionsTab = ({conditions, onConditionsChange}) => {
|
||||
const {patterns, isLoading, error} = usePatterns();
|
||||
@@ -45,38 +46,50 @@ const FormatConditionsTab = ({conditions, onConditionsChange}) => {
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return <div>Loading patterns...</div>;
|
||||
return (
|
||||
<div className='flex items-center justify-center h-full'>
|
||||
<div className='text-gray-500 dark:text-gray-400'>
|
||||
Loading patterns...
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div>Error loading patterns: {error}</div>;
|
||||
return (
|
||||
<div className='flex items-center justify-center h-full'>
|
||||
<div className='text-red-500 dark:text-red-400'>
|
||||
Error loading patterns: {error}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='h-full flex flex-col space-y-4'>
|
||||
{/* Header with Info and Add Button */}
|
||||
<div className='flex gap-4 items-stretch'>
|
||||
<div className='flex-1 flex gap-2 p-3 text-xs bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800 rounded-lg'>
|
||||
{/* Header Section */}
|
||||
<div className='flex items-center gap-4 h-16'>
|
||||
{/* Info Alert */}
|
||||
<div
|
||||
className='flex-1 flex items-center gap-2 px-3 py-2
|
||||
bg-blue-50 dark:bg-blue-900/20
|
||||
border border-blue-200 dark:border-blue-800
|
||||
rounded-md'>
|
||||
<InfoIcon className='h-4 w-4 text-blue-600 dark:text-blue-400 flex-shrink-0' />
|
||||
<p className='text-blue-700 dark:text-blue-300'>
|
||||
Conditions define how this format matches media
|
||||
releases. Each condition can be marked as required or
|
||||
negated. Required conditions must match for the format
|
||||
to apply, while negated conditions must not match. Use
|
||||
patterns to match against release titles and groups.
|
||||
<p className='text-sm text-blue-700 dark:text-blue-300'>
|
||||
Define matching rules using required and negated
|
||||
conditions to control how formats are applied to media
|
||||
releases.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleAddCondition}
|
||||
className='flex items-center justify-center gap-2 px-4 text-white bg-blue-600 hover:bg-blue-700 rounded-lg'>
|
||||
<Plus className='w-5 h-5' />
|
||||
<span className='text-sm font-medium'>Add</span>
|
||||
</button>
|
||||
|
||||
{/* Add Button */}
|
||||
<AddButton onClick={handleAddCondition} label='Add Condition' />
|
||||
</div>
|
||||
|
||||
{/* Scrollable Conditions List */}
|
||||
<div className='flex-1 overflow-y-auto min-h-0'>
|
||||
<div className='space-y-3'>
|
||||
<div className='flex-1 overflow-y-auto min-h-0 scrollable pr-2'>
|
||||
<div className='space-y-3 pb-4'>
|
||||
{conditions.map((condition, index) => (
|
||||
<ConditionCard
|
||||
key={index}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {CONDITION_TYPES, createCondition} from './conditionTypes';
|
||||
import {ArrowUp, ArrowDown} from 'lucide-react';
|
||||
import {ArrowUp, ArrowDown, X} from 'lucide-react';
|
||||
import BrowserSelect from '@ui/BrowserSelect';
|
||||
|
||||
const ConditionCard = ({
|
||||
@@ -17,17 +17,14 @@ const ConditionCard = ({
|
||||
const conditionType = CONDITION_TYPES[condition.type?.toUpperCase()];
|
||||
const Component = conditionType?.component;
|
||||
|
||||
// Convert condition types to options format
|
||||
const typeOptions = Object.values(CONDITION_TYPES).map(type => ({
|
||||
value: type.id,
|
||||
label: type.name
|
||||
}));
|
||||
|
||||
// When type changes, create a fresh condition of the new type
|
||||
const handleTypeChange = e => {
|
||||
const newType = e.target.value;
|
||||
const newCondition = createCondition(newType);
|
||||
// Preserve the name if it exists
|
||||
if (condition.name) {
|
||||
newCondition.name = condition.name;
|
||||
}
|
||||
@@ -35,10 +32,9 @@ const ConditionCard = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='relative bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg'>
|
||||
{/* Main content with more right padding */}
|
||||
<div className='p-4 pr-16 space-y-4'>
|
||||
{/* Content remains the same */}
|
||||
<div className='relative bg-gray-800 rounded-lg border border-gray-700 shadow-xl'>
|
||||
{/* Main content */}
|
||||
<div className='p-4 pr-14 space-y-4 '>
|
||||
{/* Custom Name Input */}
|
||||
<div className='mb-4'>
|
||||
<input
|
||||
@@ -49,21 +45,23 @@ const ConditionCard = ({
|
||||
onChange({...condition, name: e.target.value})
|
||||
}
|
||||
placeholder='Enter a condition name...'
|
||||
className='w-full px-3 py-2 text-sm border border-gray-300 dark:border-gray-600
|
||||
rounded-md bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100
|
||||
focus:outline-none focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400'
|
||||
className='w-full px-3 py-2 text-sm rounded-md
|
||||
bg-gray-700 border border-gray-700
|
||||
text-gray-200 placeholder:text-gray-400
|
||||
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex items-center gap-4'>
|
||||
<div className='flex items-center gap-4 '>
|
||||
{/* Type Selection */}
|
||||
<BrowserSelect
|
||||
value={condition.type || ''}
|
||||
onChange={handleTypeChange}
|
||||
options={typeOptions}
|
||||
placeholder='Select type...'
|
||||
className='min-w-[140px] px-2 py-1.5 text-sm border border-gray-300 dark:border-gray-600
|
||||
rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100'
|
||||
className='min-w-[140px] px-3 py-2 text-sm rounded-md
|
||||
bg-gray-700 border border-gray-700
|
||||
text-gray-200'
|
||||
/>
|
||||
|
||||
{/* Render the specific condition component */}
|
||||
@@ -76,9 +74,9 @@ const ConditionCard = ({
|
||||
)}
|
||||
|
||||
{/* Universal Controls */}
|
||||
<div className='flex items-center gap-3'>
|
||||
<div className='flex items-center gap-3 ml-auto'>
|
||||
{/* Required Checkbox */}
|
||||
<label className='flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300'>
|
||||
<label className='flex items-center gap-2 cursor-pointer'>
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={condition.required}
|
||||
@@ -88,13 +86,16 @@ const ConditionCard = ({
|
||||
required: e.target.checked
|
||||
})
|
||||
}
|
||||
className='rounded border-gray-300 dark:border-gray-600'
|
||||
className='rounded border-gray-700 bg-gray-900
|
||||
text-blue-500 focus:ring-blue-500'
|
||||
/>
|
||||
Required
|
||||
<span className='text-sm font-medium text-gray-400'>
|
||||
Required
|
||||
</span>
|
||||
</label>
|
||||
|
||||
{/* Negate Checkbox */}
|
||||
<label className='flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300'>
|
||||
<label className='flex items-center gap-2 cursor-pointer'>
|
||||
<input
|
||||
type='checkbox'
|
||||
checked={condition.negate}
|
||||
@@ -104,46 +105,46 @@ const ConditionCard = ({
|
||||
negate: e.target.checked
|
||||
})
|
||||
}
|
||||
className='rounded border-gray-300 dark:border-gray-600'
|
||||
className='rounded border-gray-700 bg-gray-900
|
||||
text-blue-500 focus:ring-blue-500'
|
||||
/>
|
||||
Negate
|
||||
<span className='text-sm font-medium text-gray-400'>
|
||||
Negate
|
||||
</span>
|
||||
</label>
|
||||
|
||||
{/* Delete Button */}
|
||||
<button
|
||||
onClick={onDelete}
|
||||
className='text-gray-400 hover:text-red-500 transition-colors'>
|
||||
<svg
|
||||
className='w-4 h-4'
|
||||
fill='none'
|
||||
stroke='currentColor'
|
||||
viewBox='0 0 24 24'>
|
||||
<path
|
||||
strokeLinecap='round'
|
||||
strokeLinejoin='round'
|
||||
strokeWidth='2'
|
||||
d='M6 18L18 6M6 6l12 12'
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Move Up/Down Buttons - Now positioned further right */}
|
||||
<div className='absolute right-0 top-0 bottom-0 flex flex-col divide-y divide-gray-200 dark:divide-gray-700 border-l border-gray-200 dark:border-gray-700'>
|
||||
{/* Control Buttons */}
|
||||
<div
|
||||
className='absolute right-0 top-0 bottom-0 flex flex-col
|
||||
divide-y divide-gray-700 border-l border-gray-700'>
|
||||
<button
|
||||
onClick={onMoveUp}
|
||||
disabled={isFirst}
|
||||
className='flex items-center justify-center w-8 h-1/2 text-gray-500 hover:text-gray-900 hover:bg-gray-50 dark:text-gray-400 dark:hover:text-gray-100 dark:hover:bg-gray-700/50 disabled:opacity-50 disabled:hover:bg-transparent dark:disabled:hover:bg-transparent disabled:cursor-not-allowed transition-colors'>
|
||||
className='flex items-center justify-center w-10 flex-1
|
||||
text-gray-400 hover:text-gray-200 hover:bg-gray-700
|
||||
disabled:opacity-50 disabled:pointer-events-none
|
||||
transition-colors'>
|
||||
<ArrowUp className='w-4 h-4' />
|
||||
</button>
|
||||
<button
|
||||
onClick={onMoveDown}
|
||||
disabled={isLast}
|
||||
className='flex items-center justify-center w-8 h-1/2 text-gray-500 hover:text-gray-900 hover:bg-gray-50 dark:text-gray-400 dark:hover:text-gray-100 dark:hover:bg-gray-700/50 disabled:opacity-50 disabled:hover:bg-transparent dark:disabled:hover:bg-transparent disabled:cursor-not-allowed transition-colors'>
|
||||
className='flex items-center justify-center w-10 flex-1
|
||||
text-gray-400 hover:text-gray-200 hover:bg-gray-700
|
||||
disabled:opacity-50 disabled:pointer-events-none
|
||||
transition-colors'>
|
||||
<ArrowDown className='w-4 h-4' />
|
||||
</button>
|
||||
<button
|
||||
onClick={onDelete}
|
||||
className='flex items-center justify-center w-10 flex-1
|
||||
text-gray-400 hover:text-red-400 hover:bg-red-400/10
|
||||
transition-colors'>
|
||||
<X className='w-4 h-4' />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user