style: Enhance Styling & Accessibility (#5956)

*  feat: Enhance UI Components with Shadows and Accessibility Improvements

* 🔧 fix: Correct Category Labels and Values in API Model & Adjust Button Class in Prompt List
This commit is contained in:
Marco Beretta 2025-02-20 22:17:43 +01:00 committed by GitHub
parent fdb3cf3f58
commit fe7013562b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 59 additions and 47 deletions

View file

@ -3,40 +3,40 @@ const { logger } = require('~/config');
const options = [
{
label: 'idea',
value: 'com_ui_idea',
label: 'com_ui_idea',
value: 'idea',
},
{
label: 'travel',
value: 'com_ui_travel',
label: 'com_ui_travel',
value: 'travel',
},
{
label: 'teach_or_explain',
value: 'com_ui_teach_or_explain',
label: 'com_ui_teach_or_explain',
value: 'teach_or_explain',
},
{
label: 'write',
value: 'com_ui_write',
label: 'com_ui_write',
value: 'write',
},
{
label: 'shop',
value: 'com_ui_shop',
label: 'com_ui_shop',
value: 'shop',
},
{
label: 'code',
value: 'com_ui_code',
label: 'com_ui_code',
value: 'code',
},
{
label: 'misc',
value: 'com_ui_misc',
label: 'com_ui_misc',
value: 'misc',
},
{
label: 'roleplay',
value: 'com_ui_roleplay',
label: 'com_ui_roleplay',
value: 'roleplay',
},
{
label: 'finance',
value: 'com_ui_finance',
label: 'com_ui_finance',
value: 'finance',
},
];

View file

@ -44,7 +44,7 @@ const Command = ({
}
return (
<div className="rounded-xl border border-border-light">
<div className="rounded-xl border border-border-light shadow-md">
<h3 className="flex h-10 items-center gap-1 pl-4 text-sm text-text-secondary">
<SquareSlash className="icon-sm" aria-hidden="true" />
<Input

View file

@ -41,7 +41,7 @@ const Description = ({
}
return (
<div className="rounded-xl border border-border-light">
<div className="rounded-xl border border-border-light shadow-md">
<h3 className="flex h-10 items-center gap-1 pl-4 text-sm text-text-secondary">
<Info className="icon-sm" aria-hidden="true" />
<Input

View file

@ -32,7 +32,7 @@ export default function List({
<div className="flex w-full justify-end">
<Button
variant="outline"
className="w-full bg-transparent px-3"
className={`w-full bg-transparent ${isChatRoute ? '' : 'mx-2'}`}
onClick={() => navigate('/d/prompts/new')}
>
<Plus className="size-4" aria-hidden />

View file

@ -81,7 +81,7 @@ const PromptEditor: React.FC<Props> = ({ name, isEditing, setIsEditing }) => {
<div
role="button"
className={cn(
'w-full flex-1 overflow-auto rounded-b-xl border border-border-light p-2 transition-all duration-150 sm:p-4',
'w-full flex-1 overflow-auto rounded-b-xl border border-border-light p-2 shadow-md transition-all duration-150 sm:p-4',
{
'cursor-pointer bg-surface-primary hover:bg-surface-secondary active:bg-surface-tertiary':
!isEditing,
@ -105,6 +105,7 @@ const PromptEditor: React.FC<Props> = ({ name, isEditing, setIsEditing }) => {
isEditing ? (
<TextareaAutosize
{...field}
autoFocus
className="w-full resize-none overflow-y-auto rounded bg-transparent text-sm text-text-primary focus:outline-none sm:text-base"
minRows={3}
maxRows={14}

View file

@ -237,7 +237,6 @@ const PromptForm = () => {
payload: { name: groupName, category: value },
})
}
className="w-full"
/>
<div className="mt-2 flex flex-row items-center justify-center gap-x-2 lg:mt-0">
{hasShareAccess && <SharePrompt group={group} disabled={isLoadingGroup} />}
@ -349,7 +348,7 @@ const PromptForm = () => {
{isLoadingPrompts ? (
<Skeleton className="h-96" aria-live="polite" />
) : (
<div className="flex h-full flex-col gap-4">
<div className="mb-2 flex h-full flex-col gap-4">
<PromptEditor name="prompt" isEditing={isEditing} setIsEditing={setIsEditing} />
<PromptVariables promptText={promptText} />
<Description

View file

@ -71,7 +71,7 @@ const PromptVariables = ({
</span>
</div>
<div>
<span className="text-text-text-primary text-sm font-medium">
<span className="text-sm font-medium text-text-primary">
{localize('com_ui_dropdown_variables')}
</span>
<span className="text-sm text-text-secondary">

View file

@ -33,7 +33,7 @@ export default function Parameters({
return value ?? '';
}, [providerOption]);
const models = useMemo(
() => (provider ? modelsData[provider] ?? [] : []),
() => (provider ? (modelsData[provider] ?? []) : []),
[modelsData, provider],
);
@ -99,6 +99,7 @@ export default function Parameters({
{/* Endpoint aka Provider for Agents */}
<div className="mb-4">
<label
id="provider-label"
className="text-token-text-primary model-panel-label mb-2 block font-medium"
htmlFor="provider"
>
@ -111,6 +112,10 @@ export default function Parameters({
render={({ field, fieldState: { error } }) => (
<>
<SelectDropDown
id="provider"
aria-labelledby="provider-label"
aria-label={localize('com_ui_provider')}
aria-required="true"
emptyTitle={true}
value={field.value ?? ''}
title={localize('com_ui_provider')}
@ -140,6 +145,7 @@ export default function Parameters({
{/* Model */}
<div className="model-panel-section mb-4">
<label
id="model-label"
className={cn(
'text-token-text-primary model-panel-label mb-2 block font-medium',
!provider && 'text-gray-500 dark:text-gray-400',
@ -155,6 +161,10 @@ export default function Parameters({
render={({ field, fieldState: { error } }) => (
<>
<SelectDropDown
id="model"
aria-labelledby="model-label"
aria-label={localize('com_ui_model')}
aria-required="true"
emptyTitle={true}
placeholder={
provider
@ -188,7 +198,6 @@ export default function Parameters({
{parameters && (
<div className="h-auto max-w-full overflow-x-hidden p-2">
<div className="grid grid-cols-4 gap-6">
{' '}
{/* This is the parent element containing all settings */}
{/* Below is an example of an applied dynamic setting, each be contained by a div with the column span specified */}
{parameters.map((setting) => {

View file

@ -1,4 +1,4 @@
import React from 'react';
import React, { useRef } from 'react';
import {
Label,
Listbox,
@ -82,18 +82,14 @@ function SelectDropDown({
}
let title = _title;
if (emptyTitle) {
title = '';
} else if (!(title ?? '')) {
title = localize('com_ui_model');
}
const values = availableValues ?? [];
// Detemine if we should to convert this component into a searchable select. If we have enough elements, a search
// input will appear near the top of the menu, allowing correct filtering of different model menu items. This will
// reset once the component is unmounted (as per a normal search)
// Enable searchable select if enough items are provided.
const [filteredValues, searchRender] = useMultiSearch<string[] | Option[]>({
availableOptions: values,
placeholder: searchPlaceholder,
@ -103,9 +99,10 @@ function SelectDropDown({
});
const hasSearchRender = searchRender != null;
const options = hasSearchRender ? filteredValues : values;
const renderIcon = showOptionIcon && value != null && (value as OptionWithIcon).icon != null;
const buttonRef = useRef<HTMLButtonElement>(null);
return (
<div className={cn('flex items-center justify-center gap-2', containerClassName ?? '')}>
<div className={cn('relative w-full', subContainerClassName ?? '')}>
@ -113,13 +110,21 @@ function SelectDropDown({
{({ open }) => (
<>
<ListboxButton
ref={buttonRef}
data-testid="select-dropdown-button"
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
if (!open && buttonRef.current) {
buttonRef.current.click();
}
}
}}
className={cn(
'relative flex w-full cursor-default flex-col rounded-md border border-black/10 bg-white py-2 pl-3 pr-10 text-left disabled:bg-white dark:border-gray-600 dark:bg-gray-700 sm:text-sm',
'relative flex w-full cursor-default flex-col rounded-md border border-black/10 bg-white py-2 pl-3 pr-10 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:bg-white dark:border-gray-600 dark:bg-gray-700 sm:text-sm',
className ?? '',
)}
>
{' '}
{showLabel && (
<Label
className="block text-xs text-gray-700 dark:text-gray-500"
@ -154,11 +159,9 @@ function SelectDropDown({
if (!value) {
return <span className="text-text-secondary">{placeholder}</span>;
}
if (typeof value !== 'string') {
return value.label ?? '';
}
return value;
})()}
</span>
@ -212,17 +215,17 @@ function SelectDropDown({
if (!option) {
return null;
}
const currentLabel =
typeof option === 'string' ? option : option.label ?? option.value ?? '';
const currentValue = typeof option === 'string' ? option : option.value ?? '';
typeof option === 'string' ? option : (option.label ?? option.value ?? '');
const currentValue = typeof option === 'string' ? option : (option.value ?? '');
const currentIcon =
typeof option === 'string' ? null : (option.icon as React.ReactNode) ?? null;
typeof option === 'string'
? null
: ((option.icon as React.ReactNode) ?? null);
let activeValue: string | number | null | Option = value;
if (typeof activeValue !== 'string') {
activeValue = activeValue?.value ?? '';
}
return (
<ListboxOption
key={i}