Skip to content

Commit

Permalink
feat(v2): conversion settings form (#105)
Browse files Browse the repository at this point in the history
* feat(v2): conversion settings form

* add french translations
  • Loading branch information
murgatt committed Feb 5, 2024
1 parent 12d94b9 commit 7d1d913
Show file tree
Hide file tree
Showing 24 changed files with 461 additions and 12 deletions.
9 changes: 9 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ module.exports = {
},
plugins: ['import', 'prettier', 'unused-imports'],
rules: {
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/consistent-type-exports': 'error',
'@typescript-eslint/member-ordering': [
'error',
{
interfaces: { order: 'alphabetically-case-insensitive' },
typeLiterals: { order: 'alphabetically-case-insensitive' },
},
],
'import/first': 'error',
'import/newline-after-import': 'error',
'import/no-duplicates': 'error',
Expand Down
4 changes: 3 additions & 1 deletion electron/electron-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { IpcRenderer } from 'electron';

/// <reference types="vite-plugin-electron/electron-env" />
declare namespace NodeJS {
interface ProcessEnv {
Expand All @@ -22,5 +24,5 @@ declare namespace NodeJS {

// Used in Renderer process, expose in `preload.ts`
interface Window {
ipcRenderer: import('electron').IpcRenderer;
ipcRenderer: IpcRenderer;
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@radix-ui/react-label": "2.0.2",
"@radix-ui/react-navigation-menu": "1.1.4",
"@radix-ui/react-select": "2.0.0",
"@radix-ui/react-separator": "1.0.3",
"@radix-ui/react-slot": "1.0.2",
"@radix-ui/react-tooltip": "1.0.7",
"class-variance-authority": "0.7.0",
Expand Down
24 changes: 24 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions src/components/ConversionSettings/BitrateSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useTranslation } from 'react-i18next';
import { codecSchema } from 'src/schemas/conversionSettings.schema';
import { FormControl, FormItem, FormLabel } from '../ui/Form';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/Select';
import type { Bitrate, Codec } from 'src/schemas/conversionSettings.schema';

type BitrateSelectProps = {
codec: Codec;
onChange: (value: Bitrate) => void;
value: Bitrate;
};

const bitrateByCodec: Record<Codec, Bitrate[]> = {
default: ['default'],
aac: ['default', '32k', '64k', '96k', '128k', '192k', '256k', '320k'],
ac3: ['default', '128k', '192k', '256k', '320k', '384k', '448k', '512k', '640k'],
eac3: ['default', '192k', '320k', '448k', '640k', '1024k', '2048k', '4096k'],
};

export const BitrateSelect = ({ codec, value, onChange }: BitrateSelectProps) => {
const { t } = useTranslation();
const options = bitrateByCodec[codec];
const isDisabled = codec === codecSchema.enum.default;

return (
<FormItem>
<FormLabel>{t('conversionSettings.bitrate.label')}</FormLabel>
<Select disabled={isDisabled} onValueChange={onChange} value={value}>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
{options.map(option => (
<SelectItem key={option} value={option}>
{t(`conversionSettings.bitrate.values.${option}`)}
</SelectItem>
))}
</SelectContent>
</Select>
</FormItem>
);
};
44 changes: 44 additions & 0 deletions src/components/ConversionSettings/ChannelsSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useTranslation } from 'react-i18next';
import { codecSchema } from 'src/schemas/conversionSettings.schema';
import { FormControl, FormItem, FormLabel } from '../ui/Form';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/Select';
import type { Channels, Codec } from 'src/schemas/conversionSettings.schema';

type ChannelsSelectProps = {
codec: Codec;
onChange: (value: Channels) => void;
value: Channels;
};

const channelsByCodec: Record<Codec, Channels[]> = {
default: ['default'],
aac: ['default', '1', '2', '3', '4', '5', '6', '7', '8'],
ac3: ['default', '1', '2', '3', '4', '5', '6'],
eac3: ['default', '1', '2', '3', '4', '5', '6'],
};

export const ChannelsSelect = ({ codec, onChange, value }: ChannelsSelectProps) => {
const { t } = useTranslation();
const options = channelsByCodec[codec];
const isDisabled = codec === codecSchema.enum.default;

return (
<FormItem>
<FormLabel>{t('conversionSettings.channels.label')}</FormLabel>
<Select disabled={isDisabled} onValueChange={onChange} value={value}>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
{options.map(option => (
<SelectItem key={option} value={option}>
{t(`conversionSettings.channels.values.${option}`)}
</SelectItem>
))}
</SelectContent>
</Select>
</FormItem>
);
};
35 changes: 35 additions & 0 deletions src/components/ConversionSettings/CodecSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useTranslation } from 'react-i18next';
import { codecSchema } from 'src/schemas/conversionSettings.schema';
import { FormControl, FormItem, FormLabel } from '../ui/Form';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/Select';
import type { Codec } from 'src/schemas/conversionSettings.schema';

type CodecSelectProps = {
onChange: (value: Codec) => void;
value: Codec;
};

export const CodecSelect = ({ onChange, value }: CodecSelectProps) => {
const { t } = useTranslation();
const options = codecSchema.options.map(option => option);

return (
<FormItem>
<FormLabel>{t('conversionSettings.codec.label')}</FormLabel>
<Select onValueChange={onChange} value={value}>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
{options.map(option => (
<SelectItem key={option} value={option}>
{t(`conversionSettings.codec.values.${option}`)}
</SelectItem>
))}
</SelectContent>
</Select>
</FormItem>
);
};
57 changes: 57 additions & 0 deletions src/components/ConversionSettings/ConversionSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import { useConversionSettingsForm } from 'src/hooks/useConversionSettingsForm';
import { bitrateSchema, channelsSchema, codecSchema, sampleRateSchema } from 'src/schemas/conversionSettings.schema';
import { Form, FormField } from '../ui/Form';
import { BitrateSelect } from './BitrateSelect';
import { ChannelsSelect } from './ChannelsSelect';
import { CodecSelect } from './CodecSelect';
import { SampleRateSelect } from './SampleRateSelect';

export const ConversionSettings = () => {
const { t } = useTranslation();
const form = useConversionSettingsForm({
defaultValues: {
codec: codecSchema.enum.default,
bitrate: bitrateSchema.enum.default,
sampleRate: sampleRateSchema.enum.default,
channels: channelsSchema.enum.default,
},
});
const { control, setValue, watch } = form;
const codec = watch('codec');

useEffect(() => {
setValue('bitrate', bitrateSchema.enum.default);
setValue('sampleRate', sampleRateSchema.enum.default);
setValue('channels', channelsSchema.enum.default);
}, [codec, setValue]);

return (
<Form {...form}>
<form className="flex flex-col gap-4">
<h2 className="title-sm mb-2">{t('conversionSettings.title')}</h2>
<FormField
control={control}
name="codec"
render={({ field }) => <CodecSelect onChange={field.onChange} value={field.value} />}
/>
<FormField
control={control}
name="bitrate"
render={({ field }) => <BitrateSelect codec={codec} onChange={field.onChange} value={field.value} />}
/>
<FormField
control={control}
name="sampleRate"
render={({ field }) => <SampleRateSelect codec={codec} onChange={field.onChange} value={field.value} />}
/>
<FormField
control={control}
name="channels"
render={({ field }) => <ChannelsSelect codec={codec} onChange={field.onChange} value={field.value} />}
/>
</form>
</Form>
);
};
44 changes: 44 additions & 0 deletions src/components/ConversionSettings/SampleRateSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { useTranslation } from 'react-i18next';
import { codecSchema } from 'src/schemas/conversionSettings.schema';
import { FormControl, FormItem, FormLabel } from '../ui/Form';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/Select';
import type { Codec, SampleRate } from 'src/schemas/conversionSettings.schema';

type SampleRateSelectProps = {
codec: Codec;
onChange: (value: SampleRate) => void;
value: SampleRate;
};

const sampleRateByCodec: Record<Codec, SampleRate[]> = {
default: ['default'],
aac: ['default', '8000', '22050', '32000', '44100', '48000', '96000'],
ac3: ['default', '8000', '22050', '32000', '44100', '48000'],
eac3: ['default', '32000', '44100', '48000'],
};

export const SampleRateSelect = ({ codec, onChange, value }: SampleRateSelectProps) => {
const { t } = useTranslation();
const options = sampleRateByCodec[codec];
const isDisabled = codec === codecSchema.enum.default;

return (
<FormItem>
<FormLabel>{t('conversionSettings.sampleRate.label')}</FormLabel>
<Select disabled={isDisabled} onValueChange={onChange} value={value}>
<FormControl>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
{options.map(option => (
<SelectItem key={option} value={option}>
{t(`conversionSettings.sampleRate.values.${option}`)}
</SelectItem>
))}
</SelectContent>
</Select>
</FormItem>
);
};
1 change: 1 addition & 0 deletions src/components/ConversionSettings/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ConversionSettings } from './ConversionSettings';
2 changes: 1 addition & 1 deletion src/components/ui/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { cn } from 'src/lib/utils';
import { PropsWithClassName } from './shadcn.types';
import type { PropsWithClassName } from './ui.types';

const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement> & PropsWithClassName>(
({ className, ...props }, ref) => (
Expand Down
9 changes: 5 additions & 4 deletions src/components/ui/Form.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as LabelPrimitive from '@radix-ui/react-label';
import { Slot } from '@radix-ui/react-slot';
import * as React from 'react';
import { Controller, ControllerProps, FieldPath, FieldValues, FormProvider, useFormContext } from 'react-hook-form';
import { Controller, FormProvider, useFormContext } from 'react-hook-form';
import { Label } from 'src/components/ui/Label';
import { cn } from 'src/lib/utils';
import { PropsWithClassName } from './shadcn.types';
import type { PropsWithClassName } from './ui.types';
import type * as LabelPrimitive from '@radix-ui/react-label';
import type { ControllerProps, FieldPath, FieldValues } from 'react-hook-form';

const Form = FormProvider;

Expand Down Expand Up @@ -65,7 +66,7 @@ const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivEl

return (
<FormItemContext.Provider value={{ id }}>
<div className={cn('space-y-2', className)} ref={ref} {...props} />
<div className={cn('flex flex-col gap-2', className)} ref={ref} {...props} />
</FormItemContext.Provider>
);
},
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/NavigationMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { cva } from 'class-variance-authority';
import { ChevronDown } from 'lucide-react';
import * as React from 'react';
import { cn } from 'src/lib/utils';
import { PropsWithClassName } from './shadcn.types';
import type { PropsWithClassName } from './ui.types';

const NavigationMenu = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
Expand Down
2 changes: 1 addition & 1 deletion src/components/ui/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as SelectPrimitive from '@radix-ui/react-select';
import { Check, ChevronDown, ChevronUp } from 'lucide-react';
import * as React from 'react';
import { cn } from 'src/lib/utils';
import { PropsWithClassName } from './shadcn.types';
import type { PropsWithClassName } from './ui.types';

const Select = SelectPrimitive.Root;

Expand Down
20 changes: 20 additions & 0 deletions src/components/ui/Separator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as SeparatorPrimitive from '@radix-ui/react-separator';
import * as React from 'react';
import { cn } from 'src/lib/utils';
import type { PropsWithClassName } from './ui.types';

const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root> & PropsWithClassName
>(({ className, orientation = 'horizontal', decorative = true, ...props }, ref) => (
<SeparatorPrimitive.Root
className={cn('shrink-0 bg-border', orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]', className)}
decorative={decorative}
orientation={orientation}
ref={ref}
{...props}
/>
));
Separator.displayName = SeparatorPrimitive.Root.displayName;

export { Separator };
2 changes: 1 addition & 1 deletion src/components/ui/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
import * as React from 'react';
import { cn } from 'src/lib/utils';
import { PropsWithClassName } from './shadcn.types';
import type { PropsWithClassName } from './ui.types';

const TooltipProvider = TooltipPrimitive.Provider;

Expand Down
File renamed without changes.
Loading

0 comments on commit 7d1d913

Please sign in to comment.