карточки редизайн
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
"@radix-ui/react-dialog": "^1.1.14",
|
"@radix-ui/react-dialog": "^1.1.14",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
"@radix-ui/react-dropdown-menu": "^2.1.15",
|
||||||
"@radix-ui/react-label": "^2.1.7",
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
|
"@radix-ui/react-popover": "^1.1.14",
|
||||||
"@radix-ui/react-radio-group": "^1.3.7",
|
"@radix-ui/react-radio-group": "^1.3.7",
|
||||||
"@radix-ui/react-select": "^2.2.5",
|
"@radix-ui/react-select": "^2.2.5",
|
||||||
"@radix-ui/react-separator": "^1.1.7",
|
"@radix-ui/react-separator": "^1.1.7",
|
||||||
|
|||||||
28
src/component/ui/popover.tsx
Normal file
28
src/component/ui/popover.tsx
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
import * as PopoverPrimitive from '@radix-ui/react-popover'
|
||||||
|
import * as React from 'react'
|
||||||
|
|
||||||
|
const Popover = PopoverPrimitive.Root
|
||||||
|
const PopoverTrigger = PopoverPrimitive.Trigger
|
||||||
|
const PopoverAnchor = PopoverPrimitive.Anchor
|
||||||
|
|
||||||
|
const PopoverContent = React.forwardRef<
|
||||||
|
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||||
|
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
|
||||||
|
<PopoverPrimitive.Portal>
|
||||||
|
<PopoverPrimitive.Content
|
||||||
|
ref={ref}
|
||||||
|
align={align}
|
||||||
|
sideOffset={sideOffset}
|
||||||
|
className={cn(
|
||||||
|
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</PopoverPrimitive.Portal>
|
||||||
|
))
|
||||||
|
PopoverContent.displayName = PopoverPrimitive.Content.displayName
|
||||||
|
|
||||||
|
export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger }
|
||||||
@@ -132,6 +132,31 @@ export const DEFAULT_FUNCTIONS: Record<string, ExcelFunction> = {
|
|||||||
date.setHours(0, 0, 0, 0)
|
date.setHours(0, 0, 0, 0)
|
||||||
return date.getTime()
|
return date.getTime()
|
||||||
},
|
},
|
||||||
|
ДАТАПРОТОКОЛА: (дата: number | Date) => {
|
||||||
|
try {
|
||||||
|
const months = [
|
||||||
|
'',
|
||||||
|
'января', 'февраля', 'марта',
|
||||||
|
'апреля', 'мая', 'июня',
|
||||||
|
'июля', 'августа', 'сентября',
|
||||||
|
'октября', 'ноября', 'декабря',
|
||||||
|
]
|
||||||
|
let dateObj: Date
|
||||||
|
if (typeof дата === 'number') {
|
||||||
|
dateObj = new Date(дата)
|
||||||
|
} else if (дата instanceof Date) {
|
||||||
|
dateObj = дата
|
||||||
|
} else {
|
||||||
|
return 'Неверный формат даты'
|
||||||
|
}
|
||||||
|
const day = dateObj.getDate().toString().padStart(2, '0')
|
||||||
|
const month = months[dateObj.getMonth() + 1]
|
||||||
|
const year = dateObj.getFullYear()
|
||||||
|
return `${day} ${month} ${year}`
|
||||||
|
} catch (e) {
|
||||||
|
return 'Неверный формат даты'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Отладочная функция
|
// Отладочная функция
|
||||||
ТЕСТ: (значение: any = 'Функция работает!') => {
|
ТЕСТ: (значение: any = 'Функция работает!') => {
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export const TemplatesOverviewPage = () => {
|
|||||||
<header className="flex items-center gap-2 border-b px-4 py-2">
|
<header className="flex items-center gap-2 border-b px-4 py-2">
|
||||||
<SidebarTrigger />
|
<SidebarTrigger />
|
||||||
<Separator orientation="vertical" className="mr-2 h-4" />
|
<Separator orientation="vertical" className="mr-2 h-4" />
|
||||||
<h1 className="text-lg font-semibold">Шаблоны</h1>
|
<h1 className="text-lg font-semibold">Карточки протоколов</h1>
|
||||||
|
|
||||||
<div className="ml-auto flex items-center gap-2">
|
<div className="ml-auto flex items-center gap-2">
|
||||||
{selectionMode && (
|
{selectionMode && (
|
||||||
@@ -263,8 +263,8 @@ export const TemplatesOverviewPage = () => {
|
|||||||
|
|
||||||
<section
|
<section
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'grid gap-6',
|
'grid gap-4',
|
||||||
'grid-cols-1 md:grid-cols-2 lg:grid-cols-3'
|
'grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 2xl:grid-cols-5'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{filteredTemplates.map(t => (
|
{filteredTemplates.map(t => (
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
import { Button } from '@/component/ui/button'
|
import { Button } from '@/component/ui/button'
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from '@/component/ui/card'
|
import { Card, CardContent, CardHeader, CardTitle } from '@/component/ui/card'
|
||||||
|
import { Popover, PopoverContent, PopoverTrigger } from '@/component/ui/popover'
|
||||||
import { Template } from '@/type/template'
|
import { Template } from '@/type/template'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
import { CheckCircle, Circle, FileText, Settings, Wrench } from 'lucide-react'
|
import {
|
||||||
|
Check,
|
||||||
|
FileText,
|
||||||
|
MoreVertical,
|
||||||
|
Pencil,
|
||||||
|
Settings,
|
||||||
|
Wrench,
|
||||||
|
} from 'lucide-react'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
@@ -35,11 +43,13 @@ const TemplateCard: React.FC<TemplateCardProps> = ({
|
|||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
'relative', // <-- добавьте этот класс!
|
||||||
|
'border-2 ring-4 ring-offset-2',
|
||||||
selectionMode && 'hover:cursor-pointer',
|
selectionMode && 'hover:cursor-pointer',
|
||||||
selectionMode &&
|
selectionMode && isSelected
|
||||||
isSelected &&
|
? 'border-primary ring-primary/30'
|
||||||
'border-2 border-primary ring-4 ring-primary/30 ring-offset-2',
|
: 'border-border ring-transparent',
|
||||||
'hover:border-2 hover:border-primary'
|
'hover:border-primary'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{selectionMode && (
|
{selectionMode && (
|
||||||
@@ -58,9 +68,38 @@ const TemplateCard: React.FC<TemplateCardProps> = ({
|
|||||||
'focus-visible:ring-2 focus-visible:ring-accent'
|
'focus-visible:ring-2 focus-visible:ring-accent'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{isSelected ? <CheckCircle size={18} /> : <Circle size={18} />}
|
{isSelected ? <Check size={18} /> : null}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
|
{/* Popover-меню с действиями, только если не selectionMode */}
|
||||||
|
{!selectionMode && (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
tabIndex={0}
|
||||||
|
aria-label="Действия"
|
||||||
|
className={clsx(
|
||||||
|
'absolute right-3 top-3 z-10 flex h-7 w-7 items-center justify-center rounded-full border border-border bg-white text-muted-foreground transition-all',
|
||||||
|
'hover:text-accent-foreground',
|
||||||
|
'focus-visible:ring-2 focus-visible:ring-accent'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<MoreVertical className="h-4 w-4" />
|
||||||
|
</button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent align="end" className="w-40 p-1">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="flex w-full items-center gap-2 rounded px-2 py-2 text-sm transition-colors hover:bg-accent hover:text-accent-foreground"
|
||||||
|
>
|
||||||
|
<Pencil className="h-4 w-4" />
|
||||||
|
Редактировать
|
||||||
|
</button>
|
||||||
|
{/* Здесь можно добавить другие действия */}
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
|
|
||||||
<CardHeader className="pb-4">
|
<CardHeader className="pb-4">
|
||||||
<CardTitle className="text-base font-medium">{template.name}</CardTitle>
|
<CardTitle className="text-base font-medium">{template.name}</CardTitle>
|
||||||
|
|||||||
36
yarn.lock
36
yarn.lock
@@ -485,6 +485,27 @@
|
|||||||
aria-hidden "^1.2.4"
|
aria-hidden "^1.2.4"
|
||||||
react-remove-scroll "^2.6.3"
|
react-remove-scroll "^2.6.3"
|
||||||
|
|
||||||
|
"@radix-ui/react-popover@^1.1.14":
|
||||||
|
version "1.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.14.tgz#5496d1986f0287cdfc77e73f70a887e4cb77ad08"
|
||||||
|
integrity sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==
|
||||||
|
dependencies:
|
||||||
|
"@radix-ui/primitive" "1.1.2"
|
||||||
|
"@radix-ui/react-compose-refs" "1.1.2"
|
||||||
|
"@radix-ui/react-context" "1.1.2"
|
||||||
|
"@radix-ui/react-dismissable-layer" "1.1.10"
|
||||||
|
"@radix-ui/react-focus-guards" "1.1.2"
|
||||||
|
"@radix-ui/react-focus-scope" "1.1.7"
|
||||||
|
"@radix-ui/react-id" "1.1.1"
|
||||||
|
"@radix-ui/react-popper" "1.2.7"
|
||||||
|
"@radix-ui/react-portal" "1.1.9"
|
||||||
|
"@radix-ui/react-presence" "1.1.4"
|
||||||
|
"@radix-ui/react-primitive" "2.1.3"
|
||||||
|
"@radix-ui/react-slot" "1.2.3"
|
||||||
|
"@radix-ui/react-use-controllable-state" "1.2.2"
|
||||||
|
aria-hidden "^1.2.4"
|
||||||
|
react-remove-scroll "^2.6.3"
|
||||||
|
|
||||||
"@radix-ui/react-popper@1.2.7":
|
"@radix-ui/react-popper@1.2.7":
|
||||||
version "1.2.7"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.2.7.tgz#531cf2eebb3d3270d58f7d8136e4517646429978"
|
resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.2.7.tgz#531cf2eebb3d3270d58f7d8136e4517646429978"
|
||||||
@@ -834,7 +855,14 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.4.0"
|
tslib "^2.4.0"
|
||||||
|
|
||||||
"@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1":
|
"@types/hoist-non-react-statics@^3.3.0":
|
||||||
|
version "3.3.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz#306e3a3a73828522efa1341159da4846e7573a6c"
|
||||||
|
integrity sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==
|
||||||
|
dependencies:
|
||||||
|
hoist-non-react-statics "^3.3.0"
|
||||||
|
|
||||||
|
"@types/hoist-non-react-statics@^3.3.1":
|
||||||
version "3.3.6"
|
version "3.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz#6bba74383cdab98e8db4e20ce5b4a6b98caed010"
|
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz#6bba74383cdab98e8db4e20ce5b4a6b98caed010"
|
||||||
integrity sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==
|
integrity sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==
|
||||||
@@ -1687,9 +1715,9 @@ eastasianwidth@^0.2.0:
|
|||||||
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
|
integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
|
||||||
|
|
||||||
electron-to-chromium@^1.5.173:
|
electron-to-chromium@^1.5.173:
|
||||||
version "1.5.187"
|
version "1.5.190"
|
||||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.187.tgz#8c58854e065962351dc87e95614dd78d50425966"
|
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.190.tgz#f0ac8be182291a45e8154dbb12f18d2b2318e4ac"
|
||||||
integrity sha512-cl5Jc9I0KGUoOoSbxvTywTa40uspGJt/BDBoDLoxJRSBpWh4FFXBsjNRHfQrONsV/OoEjDfHUmZQa2d6Ze4YgA==
|
integrity sha512-k4McmnB2091YIsdCgkS0fMVMPOJgxl93ltFzaryXqwip1AaxeDqKCGLxkXODDA5Ab/D+tV5EL5+aTx76RvLRxw==
|
||||||
|
|
||||||
emoji-regex@^8.0.0:
|
emoji-regex@^8.0.0:
|
||||||
version "8.0.0"
|
version "8.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user