Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] New table column type: media #252

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions packages/visualizations-react/stories/Table/custom-style.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,28 @@
color: #808080;
}

.ods-viz-image-error-container {
color: red;
}

.ods-viz-image-loading-container {
display: inline-block;
width: 50px;
height: 50px;
border: 3px solid white;
border-radius: 50%;
border-top-color: red;
animation: spin 1s ease-in-out infinite;
-webkit-animation: spin 1s ease-in-out infinite;
}

@keyframes spin {
to { -webkit-transform: rotate(360deg); }
}
@-webkit-keyframes spin {
to { -webkit-transform: rotate(360deg); }
}

.design-system {
color: blue;
}
Expand Down
9 changes: 9 additions & 0 deletions packages/visualizations-react/stories/Table/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default [
url: 'https://example.com/lorem-ipsum',
geopoint: [2.357573,48.837904],
geoshape: 'centre-val-de-loire',
image: 'https://gravatar.com/avatar/1?s=400&d=robohash',
},
{
title: 'pellentesque nec blog post',
Expand All @@ -23,6 +24,7 @@ export default [
url: 'https://example.com/pellentesque-nec',
geopoint: [2.357573,48.837904],
geoshape: 'bretagne',
image: 'https://gravatar.com/unkown-url',
},
{
title: 'fusce sit amet blog post',
Expand All @@ -36,6 +38,7 @@ export default [
url: 'https://example.com/fusce-sit-amet',
geopoint: [2.357573,48.837904],
geoshape: 'nouvelle-aquitaine',
image: 'https://loremflickr.com/cache/resized/65535_52821605306_fb553abe7e_k_673_1280_nofilter.jpg',
},
{
title: 'vestibulum nec blog post',
Expand All @@ -48,6 +51,7 @@ export default [
url: 'https://example.com/vestibulum-nec',
geopoint: [2.357573,48.837904],
geoshape: 'occitanie',
image: 'https://gravatar.com/avatar/4?s=400&d=robohash',
},
{
title: 'Cras At Blog Post',
Expand All @@ -61,6 +65,7 @@ export default [
url: 'https://example.com/cras-at',
geopoint: [2.357573,48.837904],
geoshape: 'provence-alpes-cote-d-azur',
image: 'https://gravatar.com/avatar/5?s=400&d=robohash',
},
{
title: 'Quisque A Blog Post',
Expand All @@ -74,6 +79,7 @@ export default [
url: 'https://example.com/quisque-a',
geopoint: [2.357573,48.837904],
geoshape: 'auvergne-rhone-alpes',
image: 'https://gravatar.com/avatar/6?s=400&d=robohash',
},
{
title: 'Ut Vitae Blog Post',
Expand All @@ -87,6 +93,7 @@ export default [
url: 'https://example.com/ut-vitae',
geopoint: [2.357573,48.837904],
geoshape: 'bourgogne-franche-comte',
image: 'https://gravatar.com/avatar/7?s=400&d=robohash',
},
{
title: 'Integer Id Blog Post',
Expand All @@ -100,6 +107,7 @@ export default [
url: 'https://example.com/integer-id',
geopoint: [2.357573,48.837904],
geoshape: 'grand-est',
image: 'https://gravatar.com/avatar/8?s=400&d=robohash',
},
{
title: 'Undefined row',
Expand All @@ -112,6 +120,7 @@ export default [
url: undefined,
geopoint: undefined,
geoshape: undefined,
image: undefined,
},
{
title: 'Empty row',
Expand Down
8 changes: 8 additions & 0 deletions packages/visualizations-react/stories/Table/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ export const columns: Column[] = [
display: () => 'link',
},
},
{
title: 'Image',
key: 'image',
dataFormat: 'image',
options: {
loadingMessage: '',
}
},
{
title: 'Geo point',
key: 'geopoint',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<script lang="ts">
import type { Instance } from 'tippy.js';

import tippy from 'components/utils/tippy';
import { warn } from './utils';

export let rawValue: string;
export let display = (v: string) => v;
export let alt = '';
export let loadingMessage = 'Loading...';
export let errorMessage = 'Error while fetching image';

let tooltipContent: Element;
let image: HTMLImageElement | null = null;
let imageLoaded = false;
let hasError = false;

async function loadImage(tippyInstance: Instance) {
if (image !== null || hasError) return;
image = new Image();
image.src = rawValue;
try {
await image.decode();
image.alt = alt;
image.classList.add('ods-viz-table-image');
imageLoaded = true;
} catch (error) {
warn(rawValue, 'Image');
hasError = true;
}
tippyInstance.setContent(tooltipContent);
}
</script>

<div
role="button"
tabindex="0"
use:tippy={{
content: tooltipContent,
theme: 'ods-viz-table',
delay: [500, 0],
duration: [275, 0],
maxWidth: 'none',
onTrigger(instance) {
loadImage(instance);
},
}}
>
<div class="ods-viz-image-label">{display(rawValue)}</div>
<div bind:this={tooltipContent}>
{#if imageLoaded}
{@html image?.outerHTML}
{:else if hasError}
<div class="ods-viz-image-error-container">
{errorMessage}
</div>
{:else}
<div class="ods-viz-image-loading-container">
{loadingMessage}
</div>
{/if}
</div>
</div>

<style lang="scss">
div[role='button'] {
display: inline-block;
}
:global(.ods-viz-image-label) {
cursor: pointer;
text-decoration: underline;
}
:global(.ods-viz-table-image) {
object-fit: contain;
border-radius: 3px;
width: 360px;
height: 240px;
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import URLFormat from './URLFormat.svelte';
import ShortTextFormat from './ShortTextFormat.svelte';
import LongTextFormat from './LongTextFormat.svelte';
import GeoFormat from './GeoFormat.svelte';
import ImageFormat from './ImageFormat.svelte';
import { isValidRawValue } from './utils';

const Format = {
Expand All @@ -15,6 +16,7 @@ const Format = {
url: URLFormat,
number: NumberFormat,
geo: GeoFormat,
image: ImageFormat,
};

export { isValidRawValue };
Expand Down
1 change: 1 addition & 0 deletions packages/visualizations/src/components/Table/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export const DATA_FORMAT = {
boolean: 'boolean',
url: 'url',
geo: 'geo',
image: 'image',
} as const;
16 changes: 15 additions & 1 deletion packages/visualizations/src/components/Table/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,28 @@ export type GeoColumn = BaseColumn & {
}>;
};

/**
* Render an interactive text that displays an image in a tooltip on tab/hover.
*/
export type ImageColumn = BaseColumn & {
dataFormat: typeof DATA_FORMAT.image;
options?: {
display?: (v: string) => string;
alt?: string;
loadingMessage?: string;
errorMessage?: string;
};
};

export type Column =
| ShortTextColumn
| LongTextColumn
| NumberColumn
| DateColumn
| BooleanColumn
| URLColumn
| GeoColumn;
| GeoColumn
| ImageColumn;

export type TableOptions = {
columns: Column[];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$table-theme: 'ods-visualization-table';
$table-theme: 'ods-viz-table';
$table-background-color: white;
$tippy-box-shadow: 0 6px 13px 0 rgba(0, 0, 0, 0.26);

Expand All @@ -10,6 +10,7 @@ $tippy-box-shadow: 0 6px 13px 0 rgba(0, 0, 0, 0.26);
.tippy-box[data-theme~='#{$table-theme}'] > .tippy-content {
padding: 6px;
border-radius: 6px;
color: black;
}

.tippy-box[data-theme~='#{$table-theme}'][data-placement^='top'] > .tippy-arrow::before {
Expand Down