From f7661d5d6ce6369804dfe2097c788aee77d397e8 Mon Sep 17 00:00:00 2001 From: David Wertheimer Date: Tue, 17 Oct 2023 13:06:36 -0700 Subject: [PATCH] plugin directory html wip --- dwertheimer.ReactSkeleton/readme.md | 2 +- helpers/HTMLView.js | 2 +- helpers/colors.js | 33 +++++++++ np.plugin-test/plugin.json | 2 +- np.plugin-test/requiredFiles/css.plugin.css | 68 ++++++++++++++++--- np.plugin-test/src/commandListGenerator.js | 16 ++--- np.plugin-test/src/pluginCommandsPopup.js | 14 ++-- .../src/react/PluginListingPage.jsx | 17 ++++- np.plugin-test/src/react/WebView.jsx | 2 +- 9 files changed, 126 insertions(+), 30 deletions(-) create mode 100644 helpers/colors.js diff --git a/dwertheimer.ReactSkeleton/readme.md b/dwertheimer.ReactSkeleton/readme.md index fdc6350b0..ee5cbc9d1 100644 --- a/dwertheimer.ReactSkeleton/readme.md +++ b/dwertheimer.ReactSkeleton/readme.md @@ -217,7 +217,7 @@ In your React Components, if you want to access the theme colors, they will be a "menuItemColor": "#c5c5c0", "toolbarIconColor": "#c5c5c0", "tintColor2": "#73B3C0", - "altBackgroundColor": "#2E2F30", + "altColor": "#2E2F30", "backgroundColor": "#1D1E1F", "toolbarBackgroundColor": "#2E2F30" }, diff --git a/helpers/HTMLView.js b/helpers/HTMLView.js index 7b350dc82..a77c5b635 100644 --- a/helpers/HTMLView.js +++ b/helpers/HTMLView.js @@ -155,7 +155,7 @@ const getBasicColors = (themeJSON: any) => { h3: RGBColourConvert(themeJSON.styles?.title3?.color ?? '#E9C062'), h4: RGBColourConvert(themeJSON.styles?.title4?.color ?? '#E9C062'), tintColor: RGBColourConvert(themeJSON.editor?.tintColor) ?? '#E9C0A2', - altColor: RGBColourConvert(themeJSON.editor?.altBackgroundColor) ?? '#2E2F30', + altColor: RGBColourConvert(themeJSON.editor?.altBackgroundColor) ?? (RGBColourConvert(themeJSON.editor?.altColor) || '#2E2F30'), baseFontSize: Number(DataStore.preference('fontSize')) ?? 14, } } diff --git a/helpers/colors.js b/helpers/colors.js new file mode 100644 index 000000000..3d6ec94ef --- /dev/null +++ b/helpers/colors.js @@ -0,0 +1,33 @@ +// Helper functions for working with colors +// Uses chroma.js, a fantastic utility for deriving colors https://gka.github.io/chroma.js/ + +import chroma from 'chroma-js' + +export const isDark = (bgColor) => chroma(bgColor).luminance() < 0.5 +export const isLight = (bgColor) => !isDark(bgColor) + +/** + * Calculate a lightly-offset altColor based on the background color + * Useful for striped rows (default) and highlight on hover + * @param {string} bgColor + * @param {number} strength - 0-1 (default 0.2) + * @returns {string} - the calculated altColor in #hex format + */ +// export const getAltColor = (bgColor: string, strength: number = 0.2): string => { +// NOTE: DO NOT FLOW TYPE THIS FUNCTION. IT IS IMPORTED BY JSX FILE AND FOR SOME REASON, ROLLUP CHOKES ON FLOW +export const getAltColor = (bgColor, strength = 0.2) => { + const calcAltFromBGColor = isLight(bgColor) ? chroma(bgColor).darken(strength).css() : chroma(bgColor).brighten(strength).css() + // if (!altColor || chroma.deltaE(bgColor,altColor) < ) return calcAltFromBGColor + return calcAltFromBGColor +} + +/** + * Calculate Computes CEI color difference (0-100 where 0 is identical and 100 is maximally different) + * Useful for knowing if text will be readable on a background or calculating stripes + * @param {string} a + * @param {string} b + * @returns {number} - the deltaE difference between the two colors (0-100) or null if one number is not valid + */ +// export const howDifferentAreTheseColors = (a: string, b: string): number => chroma.deltaE(a, b) +// NOTE: DO NOT FLOW TYPE THIS FUNCTION. IT IS IMPORTED BY JSX FILE AND FOR SOME REASON, ROLLUP CHOKES ON FLOW +export const howDifferentAreTheseColors = (a, b) => (a && b ? chroma.deltaE(a, b) : null) diff --git a/np.plugin-test/plugin.json b/np.plugin-test/plugin.json index 9dbf3a403..5ebee0847 100644 --- a/np.plugin-test/plugin.json +++ b/np.plugin-test/plugin.json @@ -6,7 +6,7 @@ "plugin.name": "🔌 Plugin Information & Tester", "plugin.description": "View Plugin Commands and Test that Plugins are working.", "plugin.author": "@dwertheimer", - "plugin.version": "1.4.0-beta2", + "plugin.version": "1.4.0-beta4", "plugin.lastUpdateInfo": "1.4.0-betaX: The beginning of a searchable plugin repository", "plugin.dependencies": [], "plugin.requiredFiles": [ diff --git a/np.plugin-test/requiredFiles/css.plugin.css b/np.plugin-test/requiredFiles/css.plugin.css index 0bafc4860..aa7d6c551 100644 --- a/np.plugin-test/requiredFiles/css.plugin.css +++ b/np.plugin-test/requiredFiles/css.plugin.css @@ -1,7 +1,16 @@ /* Plugin-specific CSS */ /* This file is loaded last to override any other CSS */ /* It's a file rather than baked into the plugin to make fast editing/visual changes easier */ -body { padding-left: 15px; padding-right: 15px; } +body { } + +element.style { + margin-top: 0px; +} +h1, h2, h3, h4, h5, h6 { + margin-top: 0px; + font-weight: 500; + line-height: 1.2; +} .monospace { font-family: 'ui-monospace'; } .monospaceData { font-family: 'ui-monospace'; font-size: 10px; white-space: pre-wrap } /* loading spinner */ @@ -20,17 +29,20 @@ body { padding-left: 15px; padding-right: 15px; } html, body { max-width: 100vw; - overflow-x: hidden; overscroll-behavior-y: none; } .container { - align-items: center; - background-color: white; + padding: 1rem; display: flex; + flex-wrap: wrap; height: 100vh; - justify-content: center; width: 100vw; + max-width: 100vw; + padding-left: 0px; /* edge to edge */ + padding-right: 0px; + /* align-items: center; */ /* vertical */ + justify-content: center; /* horizontal */ } @keyframes sk-scaleout { @@ -59,12 +71,11 @@ body { padding-left: 15px; padding-right: 15px; } } .PluginListingPage { - padding: 0px; padding-top: 25px; } .plugin-section { - padding: 8px; + padding: 10px; } .pluginName { @@ -101,11 +112,48 @@ body { padding-left: 15px; padding-right: 15px; } } .sticky { + width: 100vw; position: fixed; top: 0; z-index: 100; /* optional: to ensure the div stays on top of other elements */ - display: 'flex'; - justify-content: 'flex-end'; - gap: '10px'; + display: flex; + justify-content: flex-start; padding-right: '20px; + flex-wrap: wrap; /* allow to wrap on phone */ } + + + /** + * Responsive + * for phones + */ + + @media only screen and (min-width: 375px) + and (max-width: 767px) { + .container { + padding-left: 0px; /* edge to edge */ + padding-right: 0px; } + + h1 { + font-size: 1.5rem; + } + + .button { + padding: 0.5rem 1rem; + font-size: 0.875rem; + } + + .sticky { + position: fixed; + top: 0; + z-index: 100; + justify-content: flex-end; + padding-top: 5px; + padding-right: 40px; /* make room for X */ + flex-wrap: wrap; /* allow to wrap on phone */ + } + + .PluginListingPage { + margin-top: 55px; + } + } \ No newline at end of file diff --git a/np.plugin-test/src/commandListGenerator.js b/np.plugin-test/src/commandListGenerator.js index 458b2d12f..b0b531aff 100644 --- a/np.plugin-test/src/commandListGenerator.js +++ b/np.plugin-test/src/commandListGenerator.js @@ -16,9 +16,9 @@ async function getPluginList(showInstalledOnly: boolean = false, installedPlugin // clo(installedPlugins, ` generatePluginCommandList installedPlugins`) // .listPlugins(showLoading, showHidden, skipMatchingLocalPlugins) const githubReleasedPlugins = await DataStore.listPlugins(true, false, true) //released plugins .isOnline is true for all of them - githubReleasedPlugins.forEach((p) => logDebug(`generatePluginCommandList githubPlugins`, `${p.id}`)) + // githubReleasedPlugins.forEach((p) => logDebug(`generatePluginCommandList githubPlugins`, `${p.id}`)) const localOnlyPlugins = installedPlugins.filter((p) => !githubReleasedPlugins.find((q) => q.id === p.id)) - localOnlyPlugins.forEach((p) => logDebug(`generatePluginCommandList localOnlyPlugins`, `${p.id}`)) + // localOnlyPlugins.forEach((p) => logDebug(`generatePluginCommandList localOnlyPlugins`, `${p.id}`)) const allLocalAndReleasedPlugins = [...installedPlugins, ...githubReleasedPlugins] let allLatestPlugins = allLocalAndReleasedPlugins.reduce((acc, p) => { const pluginsWithThisID = allLocalAndReleasedPlugins.filter((f) => f.id === p.id) @@ -35,12 +35,12 @@ async function getPluginList(showInstalledOnly: boolean = false, installedPlugin return acc }, []) allLatestPlugins = sortListBy(allLatestPlugins, 'name') - allLatestPlugins.forEach((p) => logDebug(`generatePluginCommandList allLatestPlugins`, `${p.name} (${p.id})`)) + // allLatestPlugins.forEach((p) => logDebug(`generatePluginCommandList allLatestPlugins`, `${p.name} (${p.id})`)) const plugins = showInstalledOnly ? installedPlugins : allLatestPlugins - logDebug( - `generatePluginCommandList`, - `installedPlugins ${installedPlugins.length} githubPlugins ${githubReleasedPlugins.length} allLocalAndReleasedPlugins ${allLocalAndReleasedPlugins.length}`, - ) + // logDebug( + // `generatePluginCommandList`, + // `installedPlugins ${installedPlugins.length} githubPlugins ${githubReleasedPlugins.length} allLocalAndReleasedPlugins ${allLocalAndReleasedPlugins.length}`, + // ) // clo(installedPlugins[0], 'generatePluginCommandList installedPlugins') // clo(allPlugins[0], 'generatePluginCommandList allPlugins') const pluginListWithUpdateField = plugins.map((plugin) => { @@ -124,7 +124,7 @@ export type PluginObjectWithUpdateField = { export async function getFilteredPluginData(showInstalledOnly: boolean): Promise> { const installedPlugins = DataStore.installedPlugins() const plugins: Array = await getPluginList(showInstalledOnly, installedPlugins) - clo(plugins, `generatePluginCommandList ${plugins.length} plugins`) + // clo(plugins, `generatePluginCommandList ${plugins.length} plugins`) const pluginsFiltered = [] plugins.forEach((plugin) => { const installedVersion = installedPlugins.find((p) => p.id === plugin.id) diff --git a/np.plugin-test/src/pluginCommandsPopup.js b/np.plugin-test/src/pluginCommandsPopup.js index d4fdb3c58..98ff3e813 100644 --- a/np.plugin-test/src/pluginCommandsPopup.js +++ b/np.plugin-test/src/pluginCommandsPopup.js @@ -1,5 +1,7 @@ // @flow +const DEBUG = false // change to quickly turn debugging code on/off + import pluginJson from '../plugin.json' import { getGlobalSharedData, sendToHTMLWindow, sendBannerMessage } from '../../helpers/HTMLView' import { getFilteredPluginData } from './commandListGenerator' @@ -35,7 +37,9 @@ export async function getDataObjectForReactView(): Promise { // get whatever pluginData you want the React window to start with and include it in the object below. This all gets passed to the React window const pluginData = await getData() // make sure to change np.plugin-test to your plugin name below - const ENV_MODE = 'production' /* helps during development. ouputs passed variables on the page and attaches react-devtools. set to 'production' when ready to release */ + const ENV_MODE = DEBUG + ? 'development' + : 'production' /* helps during development. ouputs passed variables on the page and attaches react-devtools. set to 'production' when ready to release */ const dataToPass: PassedData = { pluginData, title: `Plugin Command List`, @@ -103,15 +107,15 @@ export async function openReactPluginCommandsWindow() { try { logDebug(pluginJson, `testReactWindow starting up`) await DataStore.installOrUpdatePluginsByID(['np.Shared'], false, false, true) // you must have np.Shared code in order to open up a React Window - logDebug(pluginJson, `testReactWindow: installOrUpdatePluginsByID ['np.Shared'] completed`) + // logDebug(pluginJson, `testReactWindow: installOrUpdatePluginsByID ['np.Shared'] completed`) const data = await getDataObjectForReactView() - clo(data) // Note the first tag below uses the w3.css scaffolding for basic UI elements. You can delete that line if you don't want to use it // w3.css reference: https://www.w3schools.com/w3css/defaulT.asp // The second line needs to be updated to your pluginID in order to load any specific CSS you want to include for the React Window (in requiredFiles) const cssTagsString = ` - \n` + + \n` const windowOptions = { savedFilename: `../../${pluginJson['plugin.id']}/savedOutput.html` /* for saving a debug version of the html file */, headerTags: cssTagsString, @@ -119,7 +123,7 @@ export async function openReactPluginCommandsWindow() { } logDebug(`===== testReactWindow Calling React after ${timer(data.startTime || new Date())} =====`) logDebug(pluginJson, `testReactWindow invoking window. testReactWindow stopping here. It's all React from this point forward`) - clo(data, `testReactWindow data object passed`) + // clo(data, `testReactWindow data object passed`) await DataStore.invokePluginCommandByName('openReactWindow', 'np.Shared', [data, windowOptions]) } catch (error) { logError(pluginJson, JSP(error)) diff --git a/np.plugin-test/src/react/PluginListingPage.jsx b/np.plugin-test/src/react/PluginListingPage.jsx index fd6ae6329..37550e13a 100644 --- a/np.plugin-test/src/react/PluginListingPage.jsx +++ b/np.plugin-test/src/react/PluginListingPage.jsx @@ -1,6 +1,14 @@ // @flow +declare var NP_THEME: { + editor: { + backgroundColor: string, + altColor: string, + }, +} + import React, { useState } from 'react' +import { howDifferentAreTheseColors, getAltColor } from '../../../helpers/colors' import { filterCommands } from './support/filterFunctions.jsx' /**************************************************************************************************************************** @@ -106,8 +114,11 @@ type PluginSectionProps = { function PluginSection({ plugin, viewOption, index }: PluginSectionProps): React$Node { const installedDisplayString = plugin.isInstalled ? 'installed' : 'install' const updateIsAvailableString = plugin.updateIsAvailable ? '(update available)' : '' + const colorDiff = howDifferentAreTheseColors(NP_THEME.editor.backgroundColor, NP_THEME.editor.altColor) + const altColor = !colorDiff || colorDiff < 20 ? getAltColor(NP_THEME.editor.backgroundColor) : NP_THEME.editor.altColor + const pluginSectionStyle = { - backgroundColor: index % 2 === 1 ? NP_THEME.editor.altBackgroundColor : 'inherit', + backgroundColor: index % 2 === 0 ? altColor : 'inherit', } return (
@@ -187,10 +198,10 @@ function PluginListingPage(props: Props): React$Node { }) const filteredPluginsAndCommands = filterCommands({ pluginList: filteredPlugins ?? [], filter: filter, categoryFilter: categoryFilter, returnOnlyMatchingCommands: true }) console.log('filteredPluginsAndCommands SAMPLE OUPUT', JSON.stringify(filteredPluginsAndCommands.filter((plugin, index) => index < 1))) - + const filterDivStyle = { backgroundColor: NP_THEME.editor.backgroundColor } return ( <> -
+
diff --git a/np.plugin-test/src/react/WebView.jsx b/np.plugin-test/src/react/WebView.jsx index c8c18e3d3..ed7c3908d 100644 --- a/np.plugin-test/src/react/WebView.jsx +++ b/np.plugin-test/src/react/WebView.jsx @@ -172,7 +172,7 @@ export function WebView({ data, dispatch }: Props): Node { ****************************************************************************************************************************/ return ( -
+
)