CardView komponenti
This commit is contained in:
parent
d38e4f851a
commit
412ad236cc
20 changed files with 1446 additions and 83 deletions
|
|
@ -3,6 +3,7 @@
|
|||
public class LayoutDto
|
||||
{
|
||||
public bool Grid { get; set; } = true;
|
||||
public bool Card { get; set; } = true;
|
||||
public bool Pivot { get; set; } = true;
|
||||
public bool Chart { get; set; } = true;
|
||||
public bool Tree { get; set; } = true;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ public class ListFormWizardDto
|
|||
|
||||
public string DefaultLayout { get; set; }
|
||||
public bool Grid { get; set; }
|
||||
public bool Card { get; set; }
|
||||
public bool Pivot { get; set; }
|
||||
public bool Tree { get; set; }
|
||||
public bool Chart { get; set; }
|
||||
|
|
|
|||
|
|
@ -281,7 +281,7 @@ public class ListFormWizardAppService(
|
|||
ExportJson = WizardConsts.DefaultExportJson,
|
||||
IsSubForm = false,
|
||||
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0,
|
||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Card, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||
CultureName = LanguageCodes.En,
|
||||
ListFormCode = input.ListFormCode,
|
||||
Name = nameLangKey,
|
||||
|
|
|
|||
|
|
@ -4680,6 +4680,12 @@
|
|||
"en": "Grid Layout",
|
||||
"tr": "Liste Düzeni"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.DetailsLayoutDto.CardLayout",
|
||||
"en": "Card Layout",
|
||||
"tr": "Kart Düzeni"
|
||||
},
|
||||
{
|
||||
"resourceName": "Platform",
|
||||
"key": "ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout",
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ public static class ListFormSeeder_DefaultJsons
|
|||
public static string DefaultLayoutJson(string DefaultLayout = "grid") => JsonSerializer.Serialize(new LayoutDto()
|
||||
{
|
||||
Grid = true,
|
||||
Card = true,
|
||||
Pivot = true,
|
||||
Chart = true,
|
||||
Tree = true,
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
|||
ExportJson = WizardConsts.DefaultExportJson,
|
||||
IsSubForm = false,
|
||||
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0,
|
||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Card, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||
CultureName = LanguageCodes.En,
|
||||
ListFormCode = input.ListFormCode,
|
||||
Name = nameLangKey,
|
||||
|
|
|
|||
|
|
@ -84,9 +84,10 @@ public static class WizardConsts
|
|||
Margin = 10
|
||||
});
|
||||
|
||||
public static string DefaultLayoutJson(string DefaultLayout = "grid", bool Grid = true, bool Pivot = true, bool Chart = true, bool Tree = true, bool Gantt = true, bool Scheduler = true) => JsonSerializer.Serialize(new
|
||||
public static string DefaultLayoutJson(string DefaultLayout = "grid", bool Grid = true, bool Card = true, bool Pivot = true, bool Chart = true, bool Tree = true, bool Gantt = true, bool Scheduler = true) => JsonSerializer.Serialize(new
|
||||
{
|
||||
Grid = Grid,
|
||||
Card = Card,
|
||||
Pivot = Pivot,
|
||||
Chart = Chart,
|
||||
Tree = Tree,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,22 @@ body {
|
|||
font-size: 14px; /* body’ye font-size uygulanmaz */
|
||||
}
|
||||
|
||||
.list-card-view.dx-cardview {
|
||||
padding: 0;
|
||||
border-radius: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.list-card-view .dx-cardview-card,
|
||||
.list-card-view .dx-cardview-card-header .dx-toolbar,
|
||||
.list-card-view .dx-cardview-card-footer {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.list-card-view .dx-toolbar .dx-button-text {
|
||||
text-transform: none !important;
|
||||
}
|
||||
|
||||
.dx-form-group-with-caption > .dx-form-group-content {
|
||||
padding-top: 2px !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { SelectCommandTypeEnum } from '@/proxy/form/models'
|
||||
import {
|
||||
ListFormWorkflowCriteriaDto,
|
||||
SubFormDto,
|
||||
WidgetEditDto,
|
||||
WorkflowDto,
|
||||
SelectCommandTypeEnum
|
||||
} from '@/proxy/form/models'
|
||||
import { ListViewLayoutType } from '@/views/admin/listForm/edit/types'
|
||||
|
||||
|
|
@ -39,6 +39,7 @@ export interface ListFormWizardDto {
|
|||
|
||||
defaultLayout: ListViewLayoutType
|
||||
grid: boolean
|
||||
card: boolean
|
||||
pivot: boolean
|
||||
tree: boolean
|
||||
chart: boolean
|
||||
|
|
|
|||
|
|
@ -951,6 +951,7 @@ export interface ListFormWorkflowCriteriaDto {
|
|||
|
||||
export interface LayoutDto {
|
||||
grid: boolean
|
||||
card: boolean
|
||||
pivot: boolean
|
||||
tree: boolean
|
||||
chart: boolean
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ const schema = Yup.object().shape({
|
|||
defaultLayout: Yup.string(),
|
||||
layoutDto: Yup.object().shape({
|
||||
grid: Yup.boolean(),
|
||||
card: Yup.boolean(),
|
||||
pivot: Yup.boolean(),
|
||||
chart: Yup.boolean(),
|
||||
tree: Yup.boolean(),
|
||||
|
|
@ -312,6 +313,22 @@ function FormTabDetails(
|
|||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
|
||||
invalid={errors.layoutDto?.card && touched.layoutDto?.card}
|
||||
errorMessage={errors.layoutDto?.card}
|
||||
>
|
||||
<Field
|
||||
className="w-20"
|
||||
autoComplete="off"
|
||||
name="layoutDto.card"
|
||||
placeholder={translate(
|
||||
'::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout',
|
||||
)}
|
||||
component={Checkbox}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
|
||||
invalid={errors.layoutDto?.pivot && touched.layoutDto?.pivot}
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ export const listFormTypeOptions = [
|
|||
|
||||
export const listFormDefaultLayoutOptions = [
|
||||
{ value: 'grid', label: 'Grid' },
|
||||
{ value: 'card', label: 'Card' },
|
||||
{ value: 'pivot', label: 'Pivot' },
|
||||
{ value: 'chart', label: 'Chart' },
|
||||
{ value: 'tree', label: 'Tree' },
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
export type ChartOperation = '' | 'select' | 'insert' | 'update' | 'delete'
|
||||
export type ChartDialogType = '' | 'pane' | 'serie' | 'annotation' | 'axis'
|
||||
export type ListViewLayoutType = 'grid' | 'pivot' | 'tree' | 'chart' | 'gantt' | 'scheduler'
|
||||
export type ListViewLayoutType =
|
||||
| 'grid'
|
||||
| 'card'
|
||||
| 'pivot'
|
||||
| 'tree'
|
||||
| 'chart'
|
||||
| 'gantt'
|
||||
| 'scheduler'
|
||||
|
||||
export const layoutTypes = {
|
||||
grid: 'Grid',
|
||||
card: 'Card',
|
||||
pivot: 'Pivot',
|
||||
tree: 'Tree',
|
||||
chart: 'Chart',
|
||||
|
|
|
|||
|
|
@ -516,6 +516,20 @@ const WizardStep2 = ({
|
|||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
|
||||
invalid={errors?.card && touched?.card}
|
||||
errorMessage={errors?.card}
|
||||
>
|
||||
<Field
|
||||
className="w-20"
|
||||
autoComplete="off"
|
||||
name="card"
|
||||
placeholder={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
|
||||
component={Checkbox}
|
||||
/>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
|
||||
invalid={errors?.pivot && touched?.pivot}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,40 @@ import React from 'react'
|
|||
const NO_IMAGE = '/img/others/no-image.png'
|
||||
|
||||
let previewElement: HTMLDivElement | null = null
|
||||
let previewTarget: HTMLElement | null = null
|
||||
let previewListenersBound = false
|
||||
|
||||
const hidePreviewElement = () => {
|
||||
previewTarget = null
|
||||
if (previewElement) {
|
||||
previewElement.style.opacity = '0'
|
||||
previewElement.style.display = 'none'
|
||||
}
|
||||
}
|
||||
|
||||
const bindPreviewDismissListeners = () => {
|
||||
if (previewListenersBound) return
|
||||
previewListenersBound = true
|
||||
|
||||
document.addEventListener(
|
||||
'pointermove',
|
||||
(event) => {
|
||||
const target = event.target as Node | null
|
||||
if (
|
||||
previewTarget &&
|
||||
(!previewTarget.isConnected || !target || !previewTarget.contains(target))
|
||||
) {
|
||||
hidePreviewElement()
|
||||
}
|
||||
},
|
||||
{ passive: true },
|
||||
)
|
||||
document.addEventListener('scroll', hidePreviewElement, true)
|
||||
window.addEventListener('blur', hidePreviewElement)
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.hidden) hidePreviewElement()
|
||||
})
|
||||
}
|
||||
|
||||
const getPreviewElement = () => {
|
||||
if (!previewElement) {
|
||||
|
|
@ -31,6 +65,7 @@ const getPreviewElement = () => {
|
|||
element.appendChild(image)
|
||||
document.body.appendChild(element)
|
||||
previewElement = element
|
||||
bindPreviewDismissListeners()
|
||||
}
|
||||
|
||||
return previewElement
|
||||
|
|
@ -38,6 +73,7 @@ const getPreviewElement = () => {
|
|||
|
||||
export const showImageHoverPreview = (src: string, event: React.MouseEvent<HTMLElement>) => {
|
||||
const element = getPreviewElement()
|
||||
previewTarget = event.currentTarget
|
||||
const image = element.querySelector('img') as HTMLImageElement
|
||||
image.onerror = () => {
|
||||
image.onerror = null
|
||||
|
|
@ -65,13 +101,11 @@ export const showImageHoverPreview = (src: string, event: React.MouseEvent<HTMLE
|
|||
}
|
||||
|
||||
export const hideImageHoverPreview = () => {
|
||||
if (previewElement) {
|
||||
previewElement.style.opacity = '0'
|
||||
previewElement.style.display = 'none'
|
||||
}
|
||||
hidePreviewElement()
|
||||
}
|
||||
|
||||
export const openImageInNewTab = (url: string) => {
|
||||
hidePreviewElement()
|
||||
if (!url.startsWith('data:image/')) {
|
||||
window.open(url, '_blank', 'noopener,noreferrer')
|
||||
return
|
||||
|
|
|
|||
1234
ui/src/views/list/CardView.tsx
Normal file
1234
ui/src/views/list/CardView.tsx
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -15,6 +15,7 @@ import { ListViewLayoutType } from '../admin/listForm/edit/types'
|
|||
|
||||
import {
|
||||
FaChartArea,
|
||||
FaThLarge,
|
||||
FaList,
|
||||
FaSitemap,
|
||||
FaTable,
|
||||
|
|
@ -26,6 +27,7 @@ import {
|
|||
🔥 LAZY VIEW IMPORTS
|
||||
======================= */
|
||||
const Grid = React.lazy(() => import('./Grid'))
|
||||
const CardView = React.lazy(() => import('./CardView'))
|
||||
const Pivot = React.lazy(() => import('./Pivot'))
|
||||
const Tree = React.lazy(() => import('./Tree'))
|
||||
const Chart = React.lazy(() => import('./Chart'))
|
||||
|
|
@ -34,6 +36,7 @@ const SchedulerView = React.lazy(() => import('./SchedulerView'))
|
|||
|
||||
function isLayoutValid(dto: GridDto, layout: ListViewLayoutType | undefined): boolean {
|
||||
if (!layout || layout === 'grid') return true
|
||||
if (layout === 'card') return true
|
||||
if (layout === 'pivot') return !!dto.gridOptions?.layoutDto?.pivot
|
||||
if (layout === 'chart') return !!dto.gridOptions?.layoutDto?.chart
|
||||
if (layout === 'tree')
|
||||
|
|
@ -125,6 +128,7 @@ const List: React.FC = () => {
|
|||
const preload = useMemo(
|
||||
() => ({
|
||||
grid: () => import('./Grid'),
|
||||
card: () => import('./CardView'),
|
||||
pivot: () => import('./Pivot'),
|
||||
tree: () => import('./Tree'),
|
||||
chart: () => import('./Chart'),
|
||||
|
|
@ -200,6 +204,16 @@ const List: React.FC = () => {
|
|||
onMouseEnter={() => preload.grid()}
|
||||
></Button>
|
||||
|
||||
{gridDto.gridOptions.layoutDto.card && (
|
||||
<Button
|
||||
size="sm"
|
||||
icon={<FaThLarge />}
|
||||
variant={viewMode === 'card' ? 'solid' : 'default'}
|
||||
onClick={() => setLayout('card')}
|
||||
onMouseEnter={() => preload.card()}
|
||||
></Button>
|
||||
)}
|
||||
|
||||
{gridDto.gridOptions.layoutDto.pivot && (
|
||||
<Button
|
||||
size="sm"
|
||||
|
|
@ -235,6 +249,15 @@ const List: React.FC = () => {
|
|||
/>
|
||||
)}
|
||||
|
||||
{viewMode === 'card' && (
|
||||
<CardView
|
||||
listFormCode={listFormCode}
|
||||
searchParams={searchParams}
|
||||
isSubForm={false}
|
||||
gridDto={gridDto}
|
||||
/>
|
||||
)}
|
||||
|
||||
{viewMode === 'pivot' && (
|
||||
<Pivot
|
||||
listFormCode={listFormCode}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
GridDto,
|
||||
PlatformEditorTypes,
|
||||
UiLookupDataSourceTypeEnum,
|
||||
EditingFormItemDto
|
||||
EditingFormItemDto,
|
||||
} from '@/proxy/form/models'
|
||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||
import Scheduler, {
|
||||
|
|
@ -307,7 +307,9 @@ const SchedulerView = (props: SchedulerViewProps) => {
|
|||
if (i.editorOptions) {
|
||||
editorOptions = JSON.parse(i.editorOptions)
|
||||
}
|
||||
} catch {}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
const fieldName = i.dataField.split(':')[0]
|
||||
const listFormField = gridDto.columnFormats.find((x: any) => x.fieldName === fieldName)
|
||||
|
|
|
|||
|
|
@ -14,12 +14,14 @@ import dxDataGrid from 'devextreme/ui/data_grid'
|
|||
import dxPivotGrid from 'devextreme/ui/pivot_grid'
|
||||
import dxTreeList from 'devextreme/ui/tree_list'
|
||||
import dxGantt from 'devextreme/ui/gantt'
|
||||
import dxCardView from 'devextreme/ui/card_view'
|
||||
import { Dispatch, MutableRefObject, SetStateAction, useEffect, useState } from 'react'
|
||||
import { setGridPanelColor } from './Utils'
|
||||
import { usePermission } from '@/utils/hooks/usePermission'
|
||||
import { usePWA } from '@/utils/hooks/usePWA'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import type { GanttRef } from 'devextreme-react/cjs/gantt'
|
||||
import type { CardViewRef } from 'devextreme-react/card-view'
|
||||
import { useStoreState } from '@/store'
|
||||
import { MULTIVALUE_DELIMITER } from '@/constants/app.constant'
|
||||
import { createReportQueryString } from '../report/reportRouteParams'
|
||||
|
|
@ -29,7 +31,7 @@ export interface ISelectBoxData {
|
|||
label?: string
|
||||
}
|
||||
|
||||
type GridInstance = dxDataGrid | dxPivotGrid | dxTreeList | dxGantt
|
||||
type GridInstance = dxDataGrid | dxPivotGrid | dxTreeList | dxGantt | dxCardView
|
||||
type FilterToolbarActionId =
|
||||
| 'openDynamicGridReport'
|
||||
| 'saveActiveFilter'
|
||||
|
|
@ -50,68 +52,46 @@ type FilterToolbarAction = {
|
|||
|
||||
// Grid tipini kontrol eden yardımcı fonksiyonlar
|
||||
const isDataGrid = (grid: GridInstance): grid is dxDataGrid => {
|
||||
return 'clearFilter' in grid
|
||||
return 'state' in grid && 'getVisibleColumns' in grid && !('getRootNode' in grid)
|
||||
}
|
||||
|
||||
const isTreeList = (grid: GridInstance): grid is dxTreeList => {
|
||||
return 'getRootNode' in grid
|
||||
}
|
||||
|
||||
const isCardView = (grid: GridInstance): grid is dxCardView => {
|
||||
return 'getSelectedCardKeys' in grid
|
||||
}
|
||||
|
||||
const supportsState = (grid: GridInstance): grid is dxDataGrid | dxTreeList => {
|
||||
return 'state' in grid && typeof (grid as any).state === 'function'
|
||||
}
|
||||
|
||||
const setToolbarItemValue = (grid: GridInstance, itemName: string, value: any) => {
|
||||
if (isDataGrid(grid)) {
|
||||
const toolbarOptions = grid.option('toolbar')
|
||||
if (toolbarOptions?.items) {
|
||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
||||
if (index > -1 && toolbarOptions.items[index]) {
|
||||
const item = toolbarOptions.items[index] as any
|
||||
if (item.options) {
|
||||
item.options.value = value
|
||||
grid.option('toolbar', toolbarOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isTreeList(grid)) {
|
||||
const toolbarOptions = grid.option('toolbar')
|
||||
if (toolbarOptions?.items) {
|
||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
||||
if (index > -1 && toolbarOptions.items[index]) {
|
||||
const item = toolbarOptions.items[index] as any
|
||||
if (item.options) {
|
||||
item.options.value = value
|
||||
grid.option('toolbar', toolbarOptions)
|
||||
}
|
||||
const component = grid as any
|
||||
const toolbarOptions = component.option('toolbar')
|
||||
if (toolbarOptions?.items) {
|
||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
||||
if (index > -1 && toolbarOptions.items[index]) {
|
||||
const item = toolbarOptions.items[index] as any
|
||||
if (item.options) {
|
||||
item.options.value = value
|
||||
component.option('toolbar', toolbarOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const setToolbarItemItems = (grid: GridInstance, itemName: string, items: any[]) => {
|
||||
if (isDataGrid(grid)) {
|
||||
const toolbarOptions = grid.option('toolbar')
|
||||
if (toolbarOptions?.items) {
|
||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
||||
if (index > -1 && toolbarOptions.items[index]) {
|
||||
const item = toolbarOptions.items[index] as any
|
||||
if (item.options) {
|
||||
item.options.items = items
|
||||
grid.option('toolbar', toolbarOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isTreeList(grid)) {
|
||||
const toolbarOptions = grid.option('toolbar')
|
||||
if (toolbarOptions?.items) {
|
||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
||||
if (index > -1 && toolbarOptions.items[index]) {
|
||||
const item = toolbarOptions.items[index] as any
|
||||
if (item.options) {
|
||||
item.options.items = items
|
||||
grid.option('toolbar', toolbarOptions)
|
||||
}
|
||||
const component = grid as any
|
||||
const toolbarOptions = component.option('toolbar')
|
||||
if (toolbarOptions?.items) {
|
||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
||||
if (index > -1 && toolbarOptions.items[index]) {
|
||||
const item = toolbarOptions.items[index] as any
|
||||
if (item.options) {
|
||||
item.options.items = items
|
||||
component.option('toolbar', toolbarOptions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -140,34 +120,23 @@ const fitColumns = (grid: GridInstance) => {
|
|||
}
|
||||
|
||||
const clearGridFilter = (grid: GridInstance) => {
|
||||
if (isDataGrid(grid)) {
|
||||
grid.clearFilter()
|
||||
} else if (isTreeList(grid)) {
|
||||
grid.clearFilter()
|
||||
}
|
||||
;(grid as any).clearFilter?.()
|
||||
}
|
||||
|
||||
const setFilterPanelVisible = (grid: GridInstance, visible: boolean) => {
|
||||
if (isDataGrid(grid)) {
|
||||
grid.option('filterPanel', { visible })
|
||||
} else if (isTreeList(grid)) {
|
||||
grid.option('filterPanel', { visible })
|
||||
}
|
||||
;(grid as any).option('filterPanel', { visible })
|
||||
}
|
||||
|
||||
const setFilterValue = (grid: GridInstance, value: any) => {
|
||||
if (isDataGrid(grid)) {
|
||||
grid.option('filterValue', value)
|
||||
} else if (isTreeList(grid)) {
|
||||
grid.option('filterValue', value)
|
||||
}
|
||||
;(grid as any).option('filterValue', value)
|
||||
}
|
||||
|
||||
const resetGridState = (grid: GridInstance) => {
|
||||
if (isDataGrid(grid)) {
|
||||
grid.state(null)
|
||||
} else if (isTreeList(grid)) {
|
||||
if (supportsState(grid)) {
|
||||
grid.state(null)
|
||||
} else if (isCardView(grid)) {
|
||||
grid.option('filterValue', undefined)
|
||||
grid.option('selectedCardKeys', [])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -305,6 +274,7 @@ const useFilters = ({
|
|||
| MutableRefObject<PivotGridRef | undefined>
|
||||
| MutableRefObject<TreeListRef<any, any> | undefined>
|
||||
| MutableRefObject<GanttRef | undefined>
|
||||
| MutableRefObject<CardViewRef | undefined>
|
||||
listFormCode: string
|
||||
saveGridState?: (state: any) => Promise<void>
|
||||
}): {
|
||||
|
|
|
|||
|
|
@ -68,6 +68,40 @@ const cellTemplateMultiValue = (
|
|||
|
||||
// Hover preview overlay — singleton, tüm grid hücreleri tarafından paylaşılır
|
||||
let __imgPreviewEl: HTMLDivElement | null = null
|
||||
let __imgPreviewTarget: HTMLElement | null = null
|
||||
let __imgPreviewListenersBound = false
|
||||
|
||||
function hideImgPreview() {
|
||||
__imgPreviewTarget = null
|
||||
if (__imgPreviewEl) {
|
||||
__imgPreviewEl.style.opacity = '0'
|
||||
__imgPreviewEl.style.display = 'none'
|
||||
}
|
||||
}
|
||||
|
||||
function bindImgPreviewDismissListeners() {
|
||||
if (__imgPreviewListenersBound) return
|
||||
__imgPreviewListenersBound = true
|
||||
|
||||
document.addEventListener(
|
||||
'pointermove',
|
||||
(event) => {
|
||||
const target = event.target as Node | null
|
||||
if (
|
||||
__imgPreviewTarget &&
|
||||
(!__imgPreviewTarget.isConnected || !target || !__imgPreviewTarget.contains(target))
|
||||
) {
|
||||
hideImgPreview()
|
||||
}
|
||||
},
|
||||
{ passive: true },
|
||||
)
|
||||
document.addEventListener('scroll', hideImgPreview, true)
|
||||
window.addEventListener('blur', hideImgPreview)
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.hidden) hideImgPreview()
|
||||
})
|
||||
}
|
||||
|
||||
function getImgPreview(): HTMLDivElement {
|
||||
if (!__imgPreviewEl) {
|
||||
|
|
@ -97,12 +131,14 @@ function getImgPreview(): HTMLDivElement {
|
|||
el.appendChild(img)
|
||||
document.body.appendChild(el)
|
||||
__imgPreviewEl = el
|
||||
bindImgPreviewDismissListeners()
|
||||
}
|
||||
return __imgPreviewEl
|
||||
}
|
||||
|
||||
function showImgPreview(src: string, e: MouseEvent) {
|
||||
const el = getImgPreview()
|
||||
__imgPreviewTarget = e.currentTarget instanceof HTMLElement ? e.currentTarget : null
|
||||
const imgEl = el.querySelector('img') as HTMLImageElement
|
||||
imgEl.onerror = () => {
|
||||
imgEl.onerror = null
|
||||
|
|
@ -132,13 +168,6 @@ function showImgPreview(src: string, e: MouseEvent) {
|
|||
el.style.opacity = '1'
|
||||
}
|
||||
|
||||
function hideImgPreview() {
|
||||
if (__imgPreviewEl) {
|
||||
__imgPreviewEl.style.opacity = '0'
|
||||
__imgPreviewEl.style.display = 'none'
|
||||
}
|
||||
}
|
||||
|
||||
const cellTemplateImage = (
|
||||
cellElement: HTMLElement,
|
||||
cellInfo: DataGridTypes.ColumnCellTemplateData<any, any>,
|
||||
|
|
@ -166,7 +195,10 @@ const cellTemplateImage = (
|
|||
img.addEventListener('mouseenter', (e) => showImgPreview(url, e as MouseEvent))
|
||||
img.addEventListener('mousemove', (e) => showImgPreview(url, e as MouseEvent))
|
||||
img.addEventListener('mouseleave', hideImgPreview)
|
||||
img.addEventListener('click', () => openImageSource(url))
|
||||
img.addEventListener('click', () => {
|
||||
hideImgPreview()
|
||||
openImageSource(url)
|
||||
})
|
||||
|
||||
cellElement.appendChild(img)
|
||||
})
|
||||
|
|
|
|||
Loading…
Reference in a new issue