From e366f53d686249cf28fc5a018f9f6fede304089f Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Mon, 1 Jul 2024 14:50:39 +0200 Subject: [PATCH 1/4] chore: add a table tippy theme --- .../utils/{tippy.ts => tippy/index.ts} | 1 + .../src/components/utils/tippy/themes.scss | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+) rename packages/visualizations/src/components/utils/{tippy.ts => tippy/index.ts} (94%) create mode 100644 packages/visualizations/src/components/utils/tippy/themes.scss diff --git a/packages/visualizations/src/components/utils/tippy.ts b/packages/visualizations/src/components/utils/tippy/index.ts similarity index 94% rename from packages/visualizations/src/components/utils/tippy.ts rename to packages/visualizations/src/components/utils/tippy/index.ts index 4efddb000..2802b9b8f 100644 --- a/packages/visualizations/src/components/utils/tippy.ts +++ b/packages/visualizations/src/components/utils/tippy/index.ts @@ -1,5 +1,6 @@ import tippy, { Props } from 'tippy.js'; import 'tippy.js/dist/tippy.css'; +import './themes.scss'; export default function tippyAction(node: HTMLElement, initialProps: Partial) { const instance = tippy(node, initialProps); diff --git a/packages/visualizations/src/components/utils/tippy/themes.scss b/packages/visualizations/src/components/utils/tippy/themes.scss new file mode 100644 index 000000000..47cc2a390 --- /dev/null +++ b/packages/visualizations/src/components/utils/tippy/themes.scss @@ -0,0 +1,26 @@ +$table-theme: 'ods-visualization-table'; +$table-background-color: white; +$tippy-box-shadow: 0 6px 13px 0 rgba(0, 0, 0, 0.26); + +.tippy-box[data-theme~='#{$table-theme}'] { + background-color: $table-background-color; + box-shadow: $tippy-box-shadow; +} + +.tippy-box[data-theme~='#{$table-theme}'] > .tippy-content { + padding: 6px; + border-radius: 6px; +} + +.tippy-box[data-theme~='#{$table-theme}'][data-placement^='top'] > .tippy-arrow::before { + border-top-color: $table-background-color; +} +.tippy-box[data-theme~='#{$table-theme}'][data-placement^='bottom'] > .tippy-arrow::before { + border-bottom-color: $table-background-color; +} +.tippy-box[data-theme~='#{$table-theme}'][data-placement^='left'] > .tippy-arrow::before { + border-left-color: $table-background-color; +} +.tippy-box[data-theme~='#{$table-theme}'][data-placement^='right'] > .tippy-arrow::before { + border-right-color: $table-background-color; +} From d9d5a15e0790477d830398d82848c63fe2d50587 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Mon, 1 Jul 2024 14:55:49 +0200 Subject: [PATCH 2/4] chore(Table): add media column Render image in a tooltip on hover/tab --- .../stories/Table/data.ts | 9 +++ .../stories/Table/options.ts | 5 ++ .../Table/Cell/Format/MediaFormat.svelte | 59 +++++++++++++++++++ .../src/components/Table/Cell/Format/index.ts | 2 + .../src/components/Table/constants.ts | 1 + .../src/components/Table/types.ts | 14 ++++- 6 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 packages/visualizations/src/components/Table/Cell/Format/MediaFormat.svelte diff --git a/packages/visualizations-react/stories/Table/data.ts b/packages/visualizations-react/stories/Table/data.ts index e3017b246..2397083df 100644 --- a/packages/visualizations-react/stories/Table/data.ts +++ b/packages/visualizations-react/stories/Table/data.ts @@ -8,6 +8,7 @@ export default [ wordCount: 1200, readingTime: 5.5, url: 'https://example.com/lorem-ipsum', + media: 'https://gravatar.com/avatar/1?s=400&d=robohash', }, { title: 'pellentesque nec blog post', @@ -19,6 +20,7 @@ export default [ wordCount: 800, readingTime: 3.8, url: 'https://example.com/pellentesque-nec', + media: 'https://gravatar.com/unkown-url', }, { title: 'fusce sit amet blog post', @@ -30,6 +32,7 @@ export default [ wordCount: 1500, readingTime: 7.2, url: 'https://example.com/fusce-sit-amet', + media: 'https://loremflickr.com/cache/resized/65535_52821605306_fb553abe7e_k_673_1280_nofilter.jpg', }, { title: 'vestibulum nec blog post', @@ -40,6 +43,7 @@ export default [ wordCount: 1000, readingTime: 4.5, url: 'https://example.com/vestibulum-nec', + media: 'https://gravatar.com/avatar/4?s=400&d=robohash', }, { title: 'Cras At Blog Post', @@ -51,6 +55,7 @@ export default [ wordCount: 1300, readingTime: 6.0, url: 'https://example.com/cras-at', + media: 'https://gravatar.com/avatar/5?s=400&d=robohash', }, { title: 'Quisque A Blog Post', @@ -62,6 +67,7 @@ export default [ wordCount: 900, readingTime: 4.0, url: 'https://example.com/quisque-a', + media: 'https://gravatar.com/avatar/6?s=400&d=robohash', }, { title: 'Ut Vitae Blog Post', @@ -73,6 +79,7 @@ export default [ wordCount: 1100, readingTime: 5.0, url: 'https://example.com/ut-vitae', + media: 'https://gravatar.com/avatar/7?s=400&d=robohash', }, { title: 'Integer Id Blog Post', @@ -84,6 +91,7 @@ export default [ wordCount: 950, readingTime: 4.2, url: 'https://example.com/integer-id', + media: 'https://gravatar.com/avatar/8?s=400&d=robohash', }, { title: 'Undefined row', @@ -94,6 +102,7 @@ export default [ wordCount: undefined, readingTime: null, url: undefined, + media: undefined, }, { title: 'Empty row', diff --git a/packages/visualizations-react/stories/Table/options.ts b/packages/visualizations-react/stories/Table/options.ts index 4fe14796a..a9701746f 100644 --- a/packages/visualizations-react/stories/Table/options.ts +++ b/packages/visualizations-react/stories/Table/options.ts @@ -71,6 +71,11 @@ export const columns: Column[] = [ display: () => 'link', }, }, + { + title: 'Media', + key: 'media', + dataFormat: 'media', + }, ]; const options: TableOptions = { diff --git a/packages/visualizations/src/components/Table/Cell/Format/MediaFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/MediaFormat.svelte new file mode 100644 index 000000000..43c8a4e47 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/MediaFormat.svelte @@ -0,0 +1,59 @@ + + +{#if isImage} +
+
{display(rawValue)}
+
+ {alt(rawValue)} +
+
+{:else} + {display(rawValue)} +{/if} + + diff --git a/packages/visualizations/src/components/Table/Cell/Format/index.ts b/packages/visualizations/src/components/Table/Cell/Format/index.ts index 7c6c60fb8..d55b1427a 100644 --- a/packages/visualizations/src/components/Table/Cell/Format/index.ts +++ b/packages/visualizations/src/components/Table/Cell/Format/index.ts @@ -4,6 +4,7 @@ import NumberFormat from './NumberFormat.svelte'; import URLFormat from './URLFormat.svelte'; import ShortTextFormat from './ShortTextFormat.svelte'; import LongTextFormat from './LongTextFormat.svelte'; +import MediaFormat from './MediaFormat.svelte'; import { isValidRawValue } from './utils'; const Format = { @@ -13,6 +14,7 @@ const Format = { 'long-text': LongTextFormat, url: URLFormat, number: NumberFormat, + media: MediaFormat, }; export { isValidRawValue }; diff --git a/packages/visualizations/src/components/Table/constants.ts b/packages/visualizations/src/components/Table/constants.ts index e78d688d4..88ddac129 100644 --- a/packages/visualizations/src/components/Table/constants.ts +++ b/packages/visualizations/src/components/Table/constants.ts @@ -6,4 +6,5 @@ export const DATA_FORMAT = { number: 'number', boolean: 'boolean', url: 'url', + media: 'media', } as const; diff --git a/packages/visualizations/src/components/Table/types.ts b/packages/visualizations/src/components/Table/types.ts index e0050e832..506defb43 100644 --- a/packages/visualizations/src/components/Table/types.ts +++ b/packages/visualizations/src/components/Table/types.ts @@ -85,13 +85,25 @@ export type URLColumn = BaseColumn & { }; }; +/** + * Render an interactive text that displays an image in a tooltip on tab/hover. + */ +export type MediaColumn = BaseColumn & { + dataFormat: typeof DATA_FORMAT.media; + options?: { + display?: (v: string) => string; + alt?: (v: string) => string; + }; +}; + export type Column = | ShortTextColumn | LongTextColumn | NumberColumn | DateColumn | BooleanColumn - | URLColumn; + | URLColumn + | MediaColumn; export type TableOptions = { columns: Column[]; From f73d635855e522409687e0d7c3b999cd00bc8e7a Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Tue, 2 Jul 2024 17:37:48 +0200 Subject: [PATCH 3/4] chore(Table): restrict media column to image column --- .../stories/Table/custom-style.css | 22 ++++++ .../stories/Table/data.ts | 18 ++--- .../stories/Table/options.ts | 9 ++- .../Table/Cell/Format/ImageFormat.svelte | 79 +++++++++++++++++++ .../Table/Cell/Format/MediaFormat.svelte | 59 -------------- .../src/components/Table/Cell/Format/index.ts | 4 +- .../src/components/Table/constants.ts | 2 +- .../src/components/Table/types.ts | 8 +- .../src/components/utils/tippy/themes.scss | 1 + 9 files changed, 125 insertions(+), 77 deletions(-) create mode 100644 packages/visualizations/src/components/Table/Cell/Format/ImageFormat.svelte delete mode 100644 packages/visualizations/src/components/Table/Cell/Format/MediaFormat.svelte diff --git a/packages/visualizations-react/stories/Table/custom-style.css b/packages/visualizations-react/stories/Table/custom-style.css index 17ff38b70..5e127953f 100644 --- a/packages/visualizations-react/stories/Table/custom-style.css +++ b/packages/visualizations-react/stories/Table/custom-style.css @@ -32,6 +32,28 @@ color: #808080; } +.ods-visualization-table__image-error-container { + color: red; +} + +.ods-visualization-table__image-loading-container .loader { + 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; } diff --git a/packages/visualizations-react/stories/Table/data.ts b/packages/visualizations-react/stories/Table/data.ts index 2397083df..1c35cb7d1 100644 --- a/packages/visualizations-react/stories/Table/data.ts +++ b/packages/visualizations-react/stories/Table/data.ts @@ -8,7 +8,7 @@ export default [ wordCount: 1200, readingTime: 5.5, url: 'https://example.com/lorem-ipsum', - media: 'https://gravatar.com/avatar/1?s=400&d=robohash', + image: 'https://gravatar.com/avatar/1?s=400&d=robohash', }, { title: 'pellentesque nec blog post', @@ -20,7 +20,7 @@ export default [ wordCount: 800, readingTime: 3.8, url: 'https://example.com/pellentesque-nec', - media: 'https://gravatar.com/unkown-url', + image: 'https://gravatar.com/unkown-url', }, { title: 'fusce sit amet blog post', @@ -32,7 +32,7 @@ export default [ wordCount: 1500, readingTime: 7.2, url: 'https://example.com/fusce-sit-amet', - media: 'https://loremflickr.com/cache/resized/65535_52821605306_fb553abe7e_k_673_1280_nofilter.jpg', + image: 'https://loremflickr.com/cache/resized/65535_52821605306_fb553abe7e_k_673_1280_nofilter.jpg', }, { title: 'vestibulum nec blog post', @@ -43,7 +43,7 @@ export default [ wordCount: 1000, readingTime: 4.5, url: 'https://example.com/vestibulum-nec', - media: 'https://gravatar.com/avatar/4?s=400&d=robohash', + image: 'https://gravatar.com/avatar/4?s=400&d=robohash', }, { title: 'Cras At Blog Post', @@ -55,7 +55,7 @@ export default [ wordCount: 1300, readingTime: 6.0, url: 'https://example.com/cras-at', - media: 'https://gravatar.com/avatar/5?s=400&d=robohash', + image: 'https://gravatar.com/avatar/5?s=400&d=robohash', }, { title: 'Quisque A Blog Post', @@ -67,7 +67,7 @@ export default [ wordCount: 900, readingTime: 4.0, url: 'https://example.com/quisque-a', - media: 'https://gravatar.com/avatar/6?s=400&d=robohash', + image: 'https://gravatar.com/avatar/6?s=400&d=robohash', }, { title: 'Ut Vitae Blog Post', @@ -79,7 +79,7 @@ export default [ wordCount: 1100, readingTime: 5.0, url: 'https://example.com/ut-vitae', - media: 'https://gravatar.com/avatar/7?s=400&d=robohash', + image: 'https://gravatar.com/avatar/7?s=400&d=robohash', }, { title: 'Integer Id Blog Post', @@ -91,7 +91,7 @@ export default [ wordCount: 950, readingTime: 4.2, url: 'https://example.com/integer-id', - media: 'https://gravatar.com/avatar/8?s=400&d=robohash', + image: 'https://gravatar.com/avatar/8?s=400&d=robohash', }, { title: 'Undefined row', @@ -102,7 +102,7 @@ export default [ wordCount: undefined, readingTime: null, url: undefined, - media: undefined, + image: undefined, }, { title: 'Empty row', diff --git a/packages/visualizations-react/stories/Table/options.ts b/packages/visualizations-react/stories/Table/options.ts index a9701746f..e751de010 100644 --- a/packages/visualizations-react/stories/Table/options.ts +++ b/packages/visualizations-react/stories/Table/options.ts @@ -72,9 +72,12 @@ export const columns: Column[] = [ }, }, { - title: 'Media', - key: 'media', - dataFormat: 'media', + title: 'Image', + key: 'image', + dataFormat: 'image', + options: { + loadingContent: () => '
' + } }, ]; diff --git a/packages/visualizations/src/components/Table/Cell/Format/ImageFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/ImageFormat.svelte new file mode 100644 index 000000000..a505d9b19 --- /dev/null +++ b/packages/visualizations/src/components/Table/Cell/Format/ImageFormat.svelte @@ -0,0 +1,79 @@ + + +
+
{display(rawValue)}
+
+ {#if imageLoaded} + {@html image?.outerHTML} + {:else if hasError} +
+ {@html errorContent(rawValue)} +
+ {:else} +
+ {@html loadingContent(rawValue)} +
+ {/if} +
+
+ + diff --git a/packages/visualizations/src/components/Table/Cell/Format/MediaFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/MediaFormat.svelte deleted file mode 100644 index 43c8a4e47..000000000 --- a/packages/visualizations/src/components/Table/Cell/Format/MediaFormat.svelte +++ /dev/null @@ -1,59 +0,0 @@ - - -{#if isImage} -
-
{display(rawValue)}
-
- {alt(rawValue)} -
-
-{:else} - {display(rawValue)} -{/if} - - diff --git a/packages/visualizations/src/components/Table/Cell/Format/index.ts b/packages/visualizations/src/components/Table/Cell/Format/index.ts index d55b1427a..6d8c06b2e 100644 --- a/packages/visualizations/src/components/Table/Cell/Format/index.ts +++ b/packages/visualizations/src/components/Table/Cell/Format/index.ts @@ -4,7 +4,7 @@ import NumberFormat from './NumberFormat.svelte'; import URLFormat from './URLFormat.svelte'; import ShortTextFormat from './ShortTextFormat.svelte'; import LongTextFormat from './LongTextFormat.svelte'; -import MediaFormat from './MediaFormat.svelte'; +import ImageFormat from './ImageFormat.svelte'; import { isValidRawValue } from './utils'; const Format = { @@ -14,7 +14,7 @@ const Format = { 'long-text': LongTextFormat, url: URLFormat, number: NumberFormat, - media: MediaFormat, + image: ImageFormat, }; export { isValidRawValue }; diff --git a/packages/visualizations/src/components/Table/constants.ts b/packages/visualizations/src/components/Table/constants.ts index 88ddac129..9d1607173 100644 --- a/packages/visualizations/src/components/Table/constants.ts +++ b/packages/visualizations/src/components/Table/constants.ts @@ -6,5 +6,5 @@ export const DATA_FORMAT = { number: 'number', boolean: 'boolean', url: 'url', - media: 'media', + image: 'image', } as const; diff --git a/packages/visualizations/src/components/Table/types.ts b/packages/visualizations/src/components/Table/types.ts index 506defb43..753ec3c65 100644 --- a/packages/visualizations/src/components/Table/types.ts +++ b/packages/visualizations/src/components/Table/types.ts @@ -88,11 +88,13 @@ export type URLColumn = BaseColumn & { /** * Render an interactive text that displays an image in a tooltip on tab/hover. */ -export type MediaColumn = BaseColumn & { - dataFormat: typeof DATA_FORMAT.media; +export type ImageColumn = BaseColumn & { + dataFormat: typeof DATA_FORMAT.image; options?: { display?: (v: string) => string; alt?: (v: string) => string; + loadingContent?: (v: string) => string; + errorContent?: (v: string) => string; }; }; @@ -103,7 +105,7 @@ export type Column = | DateColumn | BooleanColumn | URLColumn - | MediaColumn; + | ImageColumn; export type TableOptions = { columns: Column[]; diff --git a/packages/visualizations/src/components/utils/tippy/themes.scss b/packages/visualizations/src/components/utils/tippy/themes.scss index 47cc2a390..45426e37a 100644 --- a/packages/visualizations/src/components/utils/tippy/themes.scss +++ b/packages/visualizations/src/components/utils/tippy/themes.scss @@ -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 { From 17c572def06df5b14d2c944617dfc942f6822cc0 Mon Sep 17 00:00:00 2001 From: Kevin Fabre Date: Mon, 15 Jul 2024 14:53:00 +0200 Subject: [PATCH 4/4] simplify ImageColumn API --- .../stories/Table/custom-style.css | 4 +-- .../stories/Table/options.ts | 2 +- .../Table/Cell/Format/ImageFormat.svelte | 28 +++++++++---------- .../src/components/Table/types.ts | 6 ++-- .../src/components/utils/tippy/themes.scss | 2 +- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/visualizations-react/stories/Table/custom-style.css b/packages/visualizations-react/stories/Table/custom-style.css index 282a5c443..18cde8e5b 100644 --- a/packages/visualizations-react/stories/Table/custom-style.css +++ b/packages/visualizations-react/stories/Table/custom-style.css @@ -41,11 +41,11 @@ color: #808080; } -.ods-visualization-table__image-error-container { +.ods-viz-image-error-container { color: red; } -.ods-visualization-table__image-loading-container .loader { +.ods-viz-image-loading-container { display: inline-block; width: 50px; height: 50px; diff --git a/packages/visualizations-react/stories/Table/options.ts b/packages/visualizations-react/stories/Table/options.ts index 21c870c8f..8c2b980a5 100644 --- a/packages/visualizations-react/stories/Table/options.ts +++ b/packages/visualizations-react/stories/Table/options.ts @@ -76,7 +76,7 @@ export const columns: Column[] = [ key: 'image', dataFormat: 'image', options: { - loadingContent: () => '
' + loadingMessage: '', } }, { diff --git a/packages/visualizations/src/components/Table/Cell/Format/ImageFormat.svelte b/packages/visualizations/src/components/Table/Cell/Format/ImageFormat.svelte index a505d9b19..306517897 100644 --- a/packages/visualizations/src/components/Table/Cell/Format/ImageFormat.svelte +++ b/packages/visualizations/src/components/Table/Cell/Format/ImageFormat.svelte @@ -1,14 +1,14 @@