From a7c39b0b8dd992578f3c33996e7d98e3d476ed6a Mon Sep 17 00:00:00 2001 From: gabalafou Date: Mon, 13 May 2024 07:23:53 -0400 Subject: [PATCH] a11y - Implement @smeragoel's table designs (#1757) * Implement @smeragoel's data table designs * Working for nbsphinx (plus inside ipywidget) * Add outer and column borders to data table * Rename color vars * Extend data-table styles to all tables * Apply suggestions from code review --- docs/examples/pydata.ipynb | 51 +++++++++++++++++-- .../assets/styles/abstracts/_mixins.scss | 34 +++++++++++++ .../assets/styles/content/_tables.scss | 4 ++ .../assets/styles/extensions/_notebooks.scss | 40 +++++++++++---- .../assets/styles/variables/_color.scss | 16 ++++++ 5 files changed, 131 insertions(+), 14 deletions(-) diff --git a/docs/examples/pydata.ipynb b/docs/examples/pydata.ipynb index 7f2d7d189..c63a73321 100644 --- a/docs/examples/pydata.ipynb +++ b/docs/examples/pydata.ipynb @@ -8,8 +8,13 @@ "\n", "This theme has built-in support and special styling for several major visualization libraries in the PyData ecosystem.\n", "This ensures that the images and output generated by these libraries looks good for both light and dark modes.\n", - "Below are examples of each that we use as a benchmark for reference.\n", - "\n", + "Below are examples of each that we use as a benchmark for reference." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "## Pandas" ] }, @@ -30,6 +35,46 @@ "df" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## IPyWidget" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import ipywidgets as widgets\n", + "from IPython.display import display\n", + "\n", + "tab = widgets.Tab()\n", + "\n", + "descr_str = \"Hello\"\n", + "\n", + "title = widgets.HTML(descr_str)\n", + "\n", + "# create output widgets\n", + "widget_images = widgets.Output()\n", + "widget_annotations = widgets.Output()\n", + "\n", + "# render in output widgets\n", + "with widget_images:\n", + " display(pd.DataFrame(np.random.randn(10,10)))\n", + "with widget_annotations:\n", + " display(pd.DataFrame(np.random.randn(10,10)))\n", + "\n", + "tab.children = [widget_images, widget_annotations]\n", + "tab.titles = [\"Images\", \"Annotations\"]\n", + "\n", + "display(widgets.VBox([title, tab]))" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -143,7 +188,7 @@ }, "language_info": { "name": "python", - "version": "3.10.8" + "version": "3.11.6" } }, "nbformat": 4, diff --git a/src/pydata_sphinx_theme/assets/styles/abstracts/_mixins.scss b/src/pydata_sphinx_theme/assets/styles/abstracts/_mixins.scss index 9aa9873fa..d2375179f 100644 --- a/src/pydata_sphinx_theme/assets/styles/abstracts/_mixins.scss +++ b/src/pydata_sphinx_theme/assets/styles/abstracts/_mixins.scss @@ -21,3 +21,37 @@ border-radius: 0.25rem; padding: 0.5rem; } + +@mixin table-colors { + color: var(--pst-color-table); + border: 1px solid var(--pst-color-table-outer-border); + + th, + td { + ~ th, + ~ td { + border-left: 1px solid var(--pst-color-table-inner-border); + } + } + + thead { + tr { + background-color: var(--pst-color-table-heading-bg); + border-bottom: 2px solid var(--pst-color-primary); + } + } + + tbody { + tr { + &:nth-child(odd) { + background-color: var(--pst-color-table-row-zebra-low-bg); + } + &:nth-child(even) { + background-color: var(--pst-color-table-row-zebra-high-bg); + } + &:hover { + background-color: var(--pst-color-table-row-hover-bg); + } + } + } +} diff --git a/src/pydata_sphinx_theme/assets/styles/content/_tables.scss b/src/pydata_sphinx_theme/assets/styles/content/_tables.scss index c476269c8..b70132374 100644 --- a/src/pydata_sphinx_theme/assets/styles/content/_tables.scss +++ b/src/pydata_sphinx_theme/assets/styles/content/_tables.scss @@ -4,6 +4,8 @@ // ensure table will fit in the article width and make them y-scrollable table { + @include table-colors; + display: table; overflow: auto; @@ -46,6 +48,8 @@ td { // override bootstrap table colors .table { + @include table-colors; + --bs-table-bg: transparent; //background --bs-table-color: var( --pst-color-text-base diff --git a/src/pydata_sphinx_theme/assets/styles/extensions/_notebooks.scss b/src/pydata_sphinx_theme/assets/styles/extensions/_notebooks.scss index ea25ef1e8..b4c77a5f8 100644 --- a/src/pydata_sphinx_theme/assets/styles/extensions/_notebooks.scss +++ b/src/pydata_sphinx_theme/assets/styles/extensions/_notebooks.scss @@ -17,15 +17,27 @@ html .jp-RenderedHTMLCommon { } } -// Dark theme special-cases -html[data-theme="dark"] .bd-content { - .nboutput { - .output_area.rendered_html { - @include cell-output-background; +.bd-content .nboutput { + .output_area { + &.rendered_html, + .jp-RenderedHTMLCommon { + // pandas + table.dataframe { + @include table-colors; + } } - .output_area.stderr { - background-color: var(--pst-color-danger); + // Dark theme special-cases + html[data-theme="dark"] & { + &.rendered_html:not(:has(table.dataframe)), + // ipywidgets + .widget-subarea { + @include cell-output-background; + } + + &.stderr { + background-color: var(--pst-color-danger); + } } } } @@ -44,11 +56,17 @@ div.cell_output .output { overflow-x: auto; } -// Dark theme special-cases -html[data-theme="dark"] .bd-content { - div.cell_output { +.bd-content div.cell_output { + // pandas + table.dataframe { + @include table-colors; + } + + html[data-theme="dark"] & { img, - .text_html { + .text_html:not(:has(table.dataframe)), + // ipywidgets + .widget-subarea { @include cell-output-background; } } diff --git a/src/pydata_sphinx_theme/assets/styles/variables/_color.scss b/src/pydata_sphinx_theme/assets/styles/variables/_color.scss index 55d8fbebe..66b0790fe 100644 --- a/src/pydata_sphinx_theme/assets/styles/variables/_color.scss +++ b/src/pydata_sphinx_theme/assets/styles/variables/_color.scss @@ -209,6 +209,18 @@ $pst-semantic-colors: ( "light": #f3cf95, "dark": #675c04, ), + "table": ( + "light": #{map-deep-get($color-palette, "foundation", "black")}, + "dark": #{map-deep-get($color-palette, "foundation", "white")}, + ), + "table-row-hover": ( + "bg-light": #{map-deep-get($color-palette, "violet", "300")}, + "bg-dark": #{map-deep-get($color-palette, "violet", "600")}, + ), + "table-inner-border": ( + "light": #{map-deep-get($color-palette, "gray", "200")}, + "dark": #364150, + ), // DEPTH COLORS - you can see the elevation colours and shades // in the Figma file https://www.figma.com/file/rUrrHGhUBBIAAjQ82x6pz9/PyData-Design-system---proposal-for-implementation-(2)?node-id=1492%3A922&t=sQeQZehkOzposYEg-1 // background: color of the canvas / the furthest back layer @@ -271,6 +283,10 @@ $pst-semantic-colors: ( & { --pst-color-link: var(--pst-color-primary); --pst-color-link-hover: var(--pst-color-secondary); + --pst-color-table-outer-border: var(--pst-color-surface); + --pst-color-table-heading-bg: var(--pst-color-surface); + --pst-color-table-row-zebra-high-bg: var(--pst-color-on-background); + --pst-color-table-row-zebra-low-bg: var(--pst-color-surface); } // adapt to light/dark-specific content @if $mode == "light" {