Skip to content

Commit

Permalink
Merge pull request #178 from allen-cell-animated/fix/metadata-viewer-…
Browse files Browse the repository at this point in the history
…tweaks

Fix/metadata viewer tweaks
  • Loading branch information
toloudis authored Dec 14, 2023
2 parents 83499fc + 02ebc34 commit ff301ca
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 62 deletions.
73 changes: 35 additions & 38 deletions src/aics-image-viewer/components/MetadataViewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,72 @@ import React from "react";
import { MetadataEntry, MetadataRecord } from "../../shared/types";
import "./styles.css";

interface MetadataTableProps {
type MetadataTableProps = {
metadata: MetadataRecord;
// Track whether a category title will abut another category title below when in the collapsed state.
// If so, this category title should not render a bottom border when collapsed, otherwise the border will double
// up with the top border of the lower category and create the appearance of a single thick, uneven border.
// (there is not a way to prevent this with pure CSS to my knowledge)
categoryFollows: boolean;
}
topLevel?: boolean;
};

interface CollapsibleCategoryProps extends MetadataTableProps {
type CollapsibleCategoryProps = {
metadata: MetadataRecord;
title: string;
}
};

const isCategory = (entry: MetadataEntry): entry is MetadataRecord => typeof entry === "object" && entry !== null;

const sortCategoriesFirst = (entry: MetadataEntry): MetadataEntry => {
if (!isCategory(entry) || Array.isArray(entry)) {
return entry;
}

const isCategory = (val: MetadataEntry): val is MetadataRecord => typeof val === "object" && val !== null;
const cats: MetadataRecord = {};
const vals: MetadataRecord = {};
for (const key in entry) {
if (isCategory(entry[key])) {
cats[key] = entry[key];
} else {
vals[key] = entry[key];
}
}

return { ...cats, ...vals };
};

/** Component to hold collapse state */
const MetadataCollapsibleCategory: React.FC<CollapsibleCategoryProps> = ({ metadata, title, categoryFollows }) => {
const MetadataCategory: React.FC<CollapsibleCategoryProps> = ({ metadata, title }) => {
const [collapsed, setCollapsed] = React.useState(true);
const toggleCollapsed = (): void => setCollapsed(!collapsed);
const collapsedClass = collapsed ? " metadata-collapse-collapsed" : "";

return (
<>
<tr
className={
"metadata-collapse-title" + (categoryFollows && collapsed ? " metadata-collapse-no-bottom-border" : "")
}
onClick={toggleCollapsed}
>
<tr className={"metadata-row-collapse-title" + collapsedClass} onClick={() => setCollapsed(!collapsed)}>
<td colSpan={2}>
<span className="metadata-collapse-caret">
<Icon type="right" style={{ transform: `rotate(${collapsed ? 0 : 90}deg)` }} />
</span>
{title}
</td>
</tr>
<tr className={"metadata-collapse-content-row" + (collapsed ? " metadata-collapse-collapsed" : "")}>
<tr className={"metadata-row-collapse-content" + collapsedClass}>
<td className="metadata-collapse-content" colSpan={2}>
<MetadataTable metadata={metadata} categoryFollows={categoryFollows} />
<MetadataTable metadata={metadata} />
</td>
</tr>
</>
);
};

const MetadataTable: React.FC<MetadataTableProps> = ({ metadata, categoryFollows }) => {
const MetadataTable: React.FC<MetadataTableProps> = ({ metadata, topLevel }) => {
const metadataKeys = Object.keys(metadata);
const metadataIsArray = Array.isArray(metadata);

return (
<table className="viewer-metadata-table">
<table className={"viewer-metadata-table" + (topLevel ? " metadata-top-level" : "")}>
<tbody>
{metadataKeys.map((key, idx) => {
const metadataValue = metadataIsArray ? metadata[idx] : metadata[key];
const metadataValue = sortCategoriesFirst(metadataIsArray ? metadata[idx] : metadata[key]);

if (isCategory(metadataValue)) {
// Determine whether this category is followed by another category, ignoring data hierarchy:
// - If this is the last element in the table, this category has another category below if the table does.
// - Otherwise, just check if the next element in this table is a category.
const nextItem = metadataIsArray ? metadata[idx + 1] : metadata[metadataKeys[idx + 1]];
const categoryBelow = idx + 1 >= metadataKeys.length ? isCategory(nextItem) : categoryFollows;

return (
<MetadataCollapsibleCategory
key={key}
metadata={metadataValue}
title={key}
categoryFollows={categoryBelow}
/>
);
return <MetadataCategory key={key} metadata={metadataValue} title={key} />;
} else {
return (
<tr key={key}>
Expand All @@ -87,7 +84,7 @@ const MetadataTable: React.FC<MetadataTableProps> = ({ metadata, categoryFollows
};

const MetadataViewer: React.FC<{ metadata: MetadataRecord }> = ({ metadata }) => (
<MetadataTable metadata={metadata} categoryFollows={false} />
<MetadataTable metadata={metadata} topLevel={true} />
);

export default MetadataViewer;
56 changes: 32 additions & 24 deletions src/aics-image-viewer/components/MetadataViewer/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,47 @@
padding: 10px;
}

/* Table rows */
tr {
&:nth-child(odd) {
background-color: #3a3a3a;
/* On the top nest level, the top border is given by the panel header, and the bottom by the containing table */
&.metadata-top-level {
border-bottom: 1px solid #6e6e6e;

> tbody > tr.metadata-row-collapse-title:first-child {
border-top: none;
}
}

&.metadata-collapse-collapsed {
visibility: collapse;
height: 0px;
display: none;
/* ----- TABLE ROWS ----- */
tr {
&:nth-child(odd):not(.metadata-row-collapse-content) {
background-color: #3a3a3a;
}

&.metadata-collapse-title {
/* CATEGORY TITLE */
&.metadata-row-collapse-title {
color: white;
background-color: #4b4b4b;
&:not(.metadata-collapse-no-bottom-border) {
border-bottom: 1px solid #6e6e6e;
}
&.metadata-collapse-no-bottom-border > td {
background-color: #4b4b4b !important;

/* Keeps borders aligned when this category opens and closes */
&:not(.metadata-collapse-collapsed) > td {
padding-bottom: 5px;
}
&:not(:first-child) {
border-top: 1px solid #6e6e6e;
}
}

&.metadata-collapse-content-row {
background-color: #313131;
/* CATEGORY CONTENT */
&.metadata-row-collapse-content.metadata-collapse-collapsed {
visibility: collapse;
height: 0px;
display: none;
}

/* ROW BORDERS: all categories have top borders; any row which follows a category provides its bottom border */
tr.metadata-row-collapse-title,
&.metadata-row-collapse-content + tr {
border-top: 1px solid #6e6e6e;
}
}

/* Table cells */
/* ----- TABLE CELLS ----- */
td {
padding: 6px 0;
overflow-wrap: break-word;
Expand All @@ -49,7 +58,7 @@
}

&.metadata-key {
padding-left: 24px;
padding-left: 16px;
}

&.metadata-value {
Expand All @@ -59,13 +68,12 @@
}

&:last-child {
padding-right: 16px;
padding-right: 8px;
}

&.metadata-collapse-content {
padding: 0;
padding-left: 16px;
border-bottom: none;
padding-left: 24px;
}

i {
Expand Down

0 comments on commit ff301ca

Please sign in to comment.