Skip to content

Commit

Permalink
Merge pull request #514 from FlowFuse/theming-updates
Browse files Browse the repository at this point in the history
Theming updates
  • Loading branch information
joepavitt authored Jan 24, 2024
2 parents 5443f3c + d8a937e commit 168344f
Show file tree
Hide file tree
Showing 20 changed files with 524 additions and 295 deletions.
35 changes: 24 additions & 11 deletions docs/components/PropsTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,41 @@
<thead>
<tr>
<th>Prop</th>
<th>Dynamic</th>
<th v-if="!hideDynamic">Dynamic</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr v-for="(value, property) in page.frontmatter?.props" :key="property">
<td>{{ property }}</td>
<td style="text-align: center;">{{ value.dynamic ? '&#x2713;' : '' }}</td>
<tr v-for="(value, p) in properties" :key="p">
<td>{{ p }}</td>
<td v-if="!hideDynamic" style="text-align: center;">{{ value.dynamic ? '&#x2713;' : '' }}</td>
<td v-html="value.description || value"></td>
</tr>
</tbody>
</table>
</template>

<script setup>
import { useData } from 'vitepress' // eslint-disable-line import/named
const { page } = useData()
</script>

<script>
export default {
name: 'PropsTable'
name: 'PropsTable',
props: {
property: {
type: String,
default: null
},
hideDynamic: {
type: Boolean,
default: false
}
},
computed: {
properties: function () {
if (!this.property) {
return this.$frontmatter?.props || {}
} else {
return this.$frontmatter[this.property] || {}
}
}
}
}
</script>
2 changes: 1 addition & 1 deletion docs/nodes/config/ui-base.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ Some details here about the ui-base config node

## Properties

<PropsTable/>
<PropsTable :hide-dynamic="true"/>
2 changes: 1 addition & 1 deletion docs/nodes/config/ui-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ Each group is rendered within a `ui-page` as part of a [Layout](../../contributi

## Properties

<PropsTable/>
<PropsTable :hide-dynamic="true"/>
2 changes: 1 addition & 1 deletion docs/nodes/config/ui-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ Each page will be rendered in a navigation drawer within the UI, and can be acce

## Properties

<PropsTable/>
<PropsTable :hide-dynamic="true"/>
15 changes: 13 additions & 2 deletions docs/nodes/config/ui-theme.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
---
props:
colors:
Surface: Controls the color of the navigation and side menus
Primary: Any interactive element is styled with this color, including buttons, sliders and focus state of input fields.
Pages - Background: The background color of the full page
Groups - Background: The background color of any groups rendered on the page
Groups - Outline: The color of the border of any groups rendered on the page
sizes:
Page Padding: The spacing that surrounds all of the groups on a page. Applicable for Grid & Fixed layouts and Notebook layouts where the screen width is narrower than 1024px.</br></br>You can define the padding for each side of the page separately by using <a href="https://www.w3schools.com/css/css_padding.asp#:~:text=Padding%20%2D%20Shorthand%20Property" target="_blank">CSS Shorthand notation</a>
Group Gap: "The gap between each group in a layout. Default: 12px"
Group Border Radius: "The border radius of the surrunding of each group on a page. Default: 4px"
Widget Gap: "The gap between each widget within a group. Default: 12px"
---

<script setup>
Expand All @@ -16,7 +21,11 @@ Each page can be assigned a theme, which will be used to render the page. The th

## Colors

<PropsTable/>
<PropsTable property="colors" :hide-dynamic="true"/>

## Sizes

<PropsTable property="sizes" :hide-dynamic="true"/>

## Example

Expand All @@ -27,3 +36,5 @@ Example Config of `ui-theme` in Node-RED:
Resulting Dashboard with the theme applied:

![Resulting Dashboard with applied theme](/images/theme-example.png "Resulting Dashboard with applied theme"){data-zoomable}

Colors here were chosen to make it easier to differentiate between the different groups rather than it being aesthetically pleasing.
Binary file modified docs/public/images/theme-config.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/images/theme-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions nodes/config/locales/en-US/ui_base.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"label": {
"category": "dashboard 2",
"layout": "Layout",
"theming": "Theming",
"settings": "Settings",
"sidebar": "Sidebar Options",
"showPath": "Include Page Path in Label"
Expand All @@ -15,6 +16,9 @@
"collapse": "Collapse",
"expand": "Expand"
},
"themes": {
"header": "Themes"
},
"colors": {
"light": "var(--nrdb-node-light)",
"medium": "var(--nrdb-node-medium)",
Expand Down
112 changes: 94 additions & 18 deletions nodes/config/ui_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
font-size: 8pt;
line-height: 12pt;
}
.nrdb2-layout-order-editor--pages {
.nrdb2-sidebar-header {
display: flex;
justify-content: space-between;
align-items: center;
Expand All @@ -97,6 +97,21 @@
overflow: hidden;
white-space: nowrap;
}
.nrdb2-sb-list-header .nrdb2-sb-info {
font-size: 0.75rem;
opacity: 0.5;
}
.nrdb2-sb-list-header .nrdb2-sb-palette {
display: flex;
gap: 2px;
}
.nrdb2-sb-list-header .nrdb2-sb-palette-color {
width: 12px;
height: 12px;
background-color: black;
border: 1px solid #d4d4d4;
border-radius: 2px;
}
.nrdb2-sb-list-header-actions {
position: absolute;
gap: 4px;
Expand Down Expand Up @@ -293,29 +308,29 @@
}

// watch for nodes changed, added, removed - use this to refresh the sidebar
const refreshLayoutEditorDebounced = debounce(refreshLayoutEditor, 300)
const refreshSidebarEditorDebounced = debounce(refreshSidebarEditors, 300)
RED.events.on('nodes:change', function (event) {
if (RED._db2debug) { console.log('nodes:change', event) }
if (event.dirty && event.type && event.type.startsWith('ui-')) {
if (RED._db2debug) { console.log('nodes:change - this is a ui- node! queuing a call to refreshLayoutEditor') }
// debounce the call to refreshLayoutEditor as multiple events can be fired in quick succession
refreshLayoutEditorDebounced()
if (RED._db2debug) { console.log('nodes:change - this is a ui- node! queuing a call to refreshSidebarEditors') }
// debounce the call to refreshSidebarEditors as multiple events can be fired in quick succession
refreshSidebarEditorDebounced()
}
})
RED.events.on('nodes:add', function (event) {
if (RED._db2debug) { console.log('nodes:add', event) }
if (event.dirty && event.type && event.type.startsWith('ui-')) {
if (RED._db2debug) { console.log('nodes:add - this is a ui- node! queuing a call to refreshLayoutEditor') }
// debounce the call to refreshLayoutEditor as multiple events can be fired in quick succession
refreshLayoutEditorDebounced()
if (RED._db2debug) { console.log('nodes:add - this is a ui- node! queuing a call to refreshSidebarEditors') }
// debounce the call to refreshSidebarEditors as multiple events can be fired in quick succession
refreshSidebarEditorDebounced()
}
})
RED.events.on('nodes:remove', function (event) {
if (RED._db2debug) { console.log('nodes:remove', event) }
if (event.dirty && event.type && event.type.startsWith('ui-')) {
if (RED._db2debug) { console.log('nodes:remove - this is a ui- node! queuing a call to refreshLayoutEditor') }
// debounce the call to refreshLayoutEditor as multiple events can be fired in quick succession
refreshLayoutEditorDebounced()
if (RED._db2debug) { console.log('nodes:remove - this is a ui- node! queuing a call to refreshSidebarEditors') }
// debounce the call to refreshSidebarEditors as multiple events can be fired in quick succession
refreshSidebarEditorDebounced()
}
})

Expand All @@ -325,7 +340,7 @@
* @param {Object} item - The page/group/widget that these actions are bound to
*/
function addRowActions (parent, item) {
const configNodes = ['ui-base', 'ui-page', 'ui-group']
const configNodes = ['ui-base', 'ui-page', 'ui-group', 'ui-theme']
const btnGroup = $('<div>', { class: 'nrdb2-sb-list-header-button-group', id: item.id }).appendTo(parent)
if (!configNodes.includes(item.type)) {
const focusButton = $('<a href="#" class="nr-db-sb-tab-focus-button editor-button editor-button-small nr-db-sb-list-header-button"><i class="fa fa-bullseye"></i> ' + c_('layout.focus') + '</a>').appendTo(btnGroup)
Expand Down Expand Up @@ -611,7 +626,7 @@
const divTabs = $('.nrdb2-layout-order-editor').length ? $('.nrdb2-layout-order-editor') : $('<div>', { class: 'nrdb2-layout-order-editor nrdb2-sidebar-tab-content' }).appendTo(parent)

// section header - Pages
const pagesHeader = $('<div>', { class: 'nrdb2-layout-order-editor--pages' }).appendTo(divTabs)
const pagesHeader = $('<div>', { class: 'nrdb2-sidebar-header' }).appendTo(divTabs)
$('<b>').html(c_('layout.pages')).appendTo(pagesHeader)

// toggle "all" buttons
Expand Down Expand Up @@ -718,17 +733,77 @@
updateLayoutVisibility(layoutDisplayLevel)
}

function refreshLayoutEditor () {
if (RED._db2debug) { console.log('refreshLayoutEditor called') }
function buildThemesEditor (parent) {
console.log('BUILD THEMES EDITOR')
// layout/order editor
const divTabs = $('.nrdb2-themes-editor').length ? $('.nrdb2-themes-editor') : $('<div>', { class: 'nrdb2-themes-editor nrdb2-sidebar-tab-content' }).appendTo(parent)

// section header - Pages
const themeHeader = $('<div>', { class: 'nrdb2-sidebar-header' }).appendTo(divTabs)
$('<b>').html(c_('themes.header')).appendTo(themeHeader)

divTabs.append('<div class="nrdb2-layout-helptext">Here you can can get quick access to your UI Themes, defined on your Dashboard.</div>')

const themes = {}

// get all themes
RED.nodes.eachConfig(function (n) {
if (n.type === 'ui-theme') {
themes[n.id] = n
}
})

const themesOL = $('<ol>', { class: 'nrdb2-sb-pages-list' }).appendTo(divTabs).editableList({
sortable: '.nrdb2-sb-pages-list-header',
addButton: false,
addItem: function (container, i, theme) {
container.addClass('nrdb2-sb-pages-list-item')

console.log(theme)

const titleRow = $('<div>', { class: 'nrdb2-sb-list-header nrdb2-sb-themes-list-header' }).appendTo(container)
const tabicon = 'fa-paint-brush'
$('<i>', { class: 'nrdb2-sb-icon nrdb2-sb-tab-icon fa ' + tabicon }).appendTo(titleRow)
$('<span>', { class: 'nrdb2-sb-title' }).text(theme.name || theme.id).appendTo(titleRow)
$('<span>', { class: 'nrdb2-sb-info' }).text(theme.users.length + ' Page' + (theme.users.length > 1 ? 's' : '')).appendTo(titleRow)

const palette = $('<div>', { class: 'nrdb2-sb-palette' }).appendTo(titleRow)
const colors = theme.colors

palette.append($('<div>', { class: 'nrdb2-sb-palette-color', style: `background-color: ${colors.surface}` }))
palette.append($('<div>', { class: 'nrdb2-sb-palette-color', style: `background-color: ${colors.primary}` }))
palette.append($('<div>', { class: 'nrdb2-sb-palette-color', style: `background-color: ${colors.bgPage}` }))
palette.append($('<div>', { class: 'nrdb2-sb-palette-color', style: `background-color: ${colors.groupBg}` }))
palette.append($('<div>', { class: 'nrdb2-sb-palette-color', style: `background-color: ${colors.groupOutline}` }))

// theme - actions
const actions = $('<div>', { class: 'nrdb2-sb-list-header-actions' }).appendTo(titleRow)
addRowActions(actions, theme)
}
})

Object.values(themes).forEach(function (theme) {
themesOL.editableList('addItem', theme)
})
}

function refreshSidebarEditors () {
if (RED._db2debug) { console.log('refreshSidebarEditors called') }
const layoutOrderDiv = $('.nrdb2-layout-order-editor')
const themesDiv = $('.nrdb2-themes-editor')
// empty the list if any items exist
if (layoutOrderDiv.length) {
// TODO: create a lookup of which items are expanded / collapsed
layoutOrderDiv.empty()
}
if (themesDiv.length) {
// TODO: create a lookup of which items are expanded / collapsed
themesDiv.empty()
}

// now rebuild
buildLayoutOrderEditor()
buildThemesEditor()

// finally, restore previous state of expanded/collapsed items
// TODO: expand/collapse any items that were expanded before
Expand Down Expand Up @@ -767,11 +842,10 @@

const ulDashboardTabs = $('<ul id="dashboard-tabs-list"></ul>').appendTo(divTab)

const layoutLabel = c_('label.layout')

// Add in Tabs
// Tab - Pages
const pagesContent = addSidebarTab(layoutLabel, 'pages', ulDashboardTabs, sidebar)
const pagesContent = addSidebarTab(c_('label.layout'), 'pages', ulDashboardTabs, sidebar)
const themesContent = addSidebarTab(c_('label.theming'), 'themes', ulDashboardTabs, sidebar)

// check for any third-party tab definitions
RED.plugins.getPluginsByType('node-red-dashboard-2').forEach(plugin => {
Expand Down Expand Up @@ -801,6 +875,8 @@

// add page/layout editor
buildLayoutOrderEditor(pagesContent)
// add Themes View
buildThemesEditor(themesContent)
}
})
}
Expand Down
Loading

0 comments on commit 168344f

Please sign in to comment.