- Default
- Hover - only applied to default Rows (not Header)
- NOTE: The "Objektliste" page has a unique background color Grey 90, so the Hover color for this component is Grey 86.
ObjectList
Organism
This component displays a list of all existing projects. Information about each project is displayed to help users navigate the list. Users can sort the list by column information or search for keywords from all of the information. Users can open projects by clicking anywhere on their row, indicated by the hover state. The default list has 7 columns, but columns can be hidden and renamed depending on the individual program’s requirements.
Properties
ts
export interface ObjectListProps {
rows?: Row[];
columns?: Column[];
contextMenuProps?: Omit<Partial<ContextMenuProps>, 'position'>
& { openOnRightClick?: boolean; };
}
export interface Row {
id: string | number;
[key: string]: ObjectListCellValue & { class?: string | string[]; };
}
export type ObjectListCellValue = |
{ text: string | number; subtext?: string | number; class?: string | string[]; }
| string | number;
export interface Column {
id: string;
text: string | number;
category?: ObjectListColumnCategory;
width?: string;
class?: string | string[];
}
export type ObjectListColumnCategory = 'text' | 'number' | 'text-multirows';
type CellValueObject = Extract<ObjectListCellValue, { text: string | number; }>;ts
export type ContextMenuOpenDirection = 'bottom-left' | 'bottom-right' | 'top-left' | 'top-right';
export type ContextMenuPosition = { x: number; y: number; };
export interface ContextMenuOption {
id: number;
name: string;
action: string;
icon?: IconName;
locked?: boolean;
}
export interface ContextMenuProps {
options: ContextMenuOption[];
position: ContextMenuPosition;
openDirection?: ContextMenuOpenDirection;
}Playground
| PROJECT | SITE | CUSTOMER | AUTHOR | LAST MODIFIED | STATUS | EXPORTS |
|---|---|---|---|---|---|---|
Office Complex PN-0123 | Alexanderplatz 1 10178, Berlin | Tech GmbH | John Doe 2023-10-01 | Jane Smith 2 days ago | 5 / 45 | 46 |
Shopping Mall PN-2045 | Köln HBf 50667, Köln | Retail Group | This is a custom slot for the author column | Anna Müller 3 weeks ago | 12 / 60 | 78 |
Residential PN-3078 | Marienplatz 5 80331, München | Home Inc. | Michael Schmidt 2023-08-20 | Lisa Becker 1 month ago | 23 / 12 |
<
ObjectList
options
=
"[
{
"id": 1,
"name": "Delete",
"action": "delete",
"icon": "close"
},
{
"id": 2,
"name": "Open on New Tab",
"action": "open-new-tab",
"icon": "error"
},
{
"id": 3,
"name": "Duplicate",
"action": "duplicate",
"icon": "plus",
"locked": true
}
]"
openOnRightClick
/>
Anatomy
- Header Row - Each list has one of these at the top, and should be frozen from scrolling.
- Header Cell - Subcomponent, used for the header cell of columns containing text.
- Header Cell Centred - Subcomponent, used for the header cell of columns containing numbers.
- Row - Each row represents a project and when clicked opens that project. These rows scroll and have hover states.
- Text with Subtext Cell - Subcomponent
- Text Cell - Subcomponent
- Number Cell - Subcomponent
States
Basic Example with Event Handlers
vue
<script setup lang="ts">
import { ObjectList } from './';
import type { IconName } from '@pohlcon/design-system';
import { IconButton } from '@pohlcon/design-system';
import { tableData } from './tableData.json';
const contextMenuProps = ref({
options: [
{ id: 1, name: 'Delete', action: 'delete', icon: 'close' as IconName },
{ id: 2, name: 'Open on New Tab', action: 'open-new-tab', icon: 'error' as IconName },
{ id: 3, name: 'Duplicate', action: 'duplicate', icon: 'plus' as IconName },
],
openDirection: 'top-left'
});
const handleRowClick = (id) => {
console.log('Row clicked:', id);
// Handle row click event here
// Example: navigate to project details, open modal, etc.
};
const handleRowRightClick = (id) => {
console.log('Row right-clicked:', id);
// This event is still emitted, but the context menu will open automatically
// if contextMenuOptions are provided
};
const handleContextMenuSelected = (selection: { action: string; id: string | number; rowId: string | number }) => {
console.log('hello from contextMenuSelected')
console.log('Context menu action:', selection.action);
console.log('Menu item ID:', selection.id);
console.log('Row ID:', selection.rowId);
// Handle the selected action here
// Example: deleteItem(selection.rowId), duplicateItem(selection.rowId), etc.
};
const firstTriggerId = useId();
const secondTriggerId = useId();
</script>
<template>
<ObjectList
v-bind="tableData"
:contextMenuProps="contextMenuProps"
@rowClick="handleRowClick"
@rowRightClick="handleRowRightClick"
@context-menu-selected="handleContextMenuSelected"
>
<template #2-author="{ openContextMenu, isTriggerPressed }">
This is a custom slot for the author column
<IconButton
:icon="'menu'"
:pressed="isTriggerPressed(firstTriggerId)"
@click.stop="openContextMenu($event, firstTriggerId, pg.contextMenuProps?.openDirection)"
/>
</template>
<template #3-exports="{ openContextMenu, isTriggerPressed }">
<IconButton
:icon="'menu'"
:pressed="isTriggerPressed(secondTriggerId)"
@click.stop="openContextMenu($event, secondTriggerId, pg.contextMenuProps?.openDirection)"
/>
</template>
</ObjectList>
</template>
<style lang="scss" scoped>
:deep(section.component-playground) {
grid-auto-flow: row;
grid-template-columns: 1fr;
row-gap: var(--gutter-l);
}
:deep(.red-column) {
color: red !important;
text-align: center;
.object-item__text {
color: red !important;
}
}
</style>json
// tableData.json
{
"columns": [
{
"id": "project",
"text": "Project",
"category": "text-multirows"
},
{
"id": "site",
"text": "Site",
"category": "text-multirows"
},
{
"id": "customer",
"text": "Customer",
"category": "text"
},
{
"id": "author",
"text": "Author",
"category": "text-multirows",
"width": "110px"
},
{
"id": "lastModified",
"text": "Last Modified",
"category": "text-multirows",
"width": "110px"
},
{
"id": "posCompleted",
"text": "status",
"category": "number",
"width": "80px",
"class": "red-column"
},
{
"id": "exports",
"text": "Exports",
"category": "number",
"width": "80px"
}
],
"rows": [
{
"id": 1,
"class": "my-row-class",
"project": {
"text": "Office Complex",
"subtext": "PN-0123",
"class": "test-class"
},
"site": {
"text": "Alexanderplatz 1",
"subtext": "10178, Berlin"
},
"customer": {
"text": "Tech GmbH"
},
"author": {
"text": "John Doe",
"subtext": "2023-10-01"
},
"lastModified": {
"text": "Jane Smith",
"subtext": "2 days ago"
},
"posCompleted": {
"text": "5 / 45"
},
"exports": {
"text": "46"
}
},
{
"id": 2,
"project": {
"text": "Shopping Mall",
"subtext": "PN-2045"
},
"site": {
"text": "Köln HBf",
"subtext": "50667, Köln"
},
"customer": {
"text": "Retail Group"
},
"author": {
"text": "Max Must",
"subtext": "2023-09-15"
},
"lastModified": {
"text": "Anna Müller",
"subtext": "3 weeks ago"
},
"posCompleted": {
"text": "12 / 60"
},
"exports": {
"text": "78"
}
},
{
"id": 3,
"class": "this-is-a-row-class",
"project": {
"text": "Residential",
"subtext": "PN-3078"
},
"site": {
"text": "Marienplatz 5",
"subtext": "80331, München"
},
"customer": {
"text": "Home Inc."
},
"author": {
"text": "Michael Schmidt",
"subtext": "2023-08-20"
},
"lastModified": {
"text": "Lisa Becker",
"subtext": "1 month ago"
},
"posCompleted": {
"text": "23 / 12"
},
"exports": {
"text": "32"
}
}
]
}