From cc6a231b3c9785306304f6e5a6b074cad8ef2472 Mon Sep 17 00:00:00 2001 From: Mathew Pareles Date: Wed, 5 Mar 2025 22:03:01 -0800 Subject: [PATCH] fix markdown stylings with prose --- package-lock.json | 53 +++++- package.json | 3 +- .../contrib/void/browser/react/build.js | 2 +- .../react/src/markdown/ChatMarkdownRender.tsx | 162 ++++++++---------- .../browser/react/src/sidebar-tsx/Sidebar.tsx | 9 +- .../contrib/void/browser/react/src/styles.css | 24 +++ .../void/browser/react/src/util/services.tsx | 6 +- .../react/src/void-settings-tsx/Settings.tsx | 16 +- .../void/browser/react/tailwind.config.js | 137 +++++---------- 9 files changed, 207 insertions(+), 205 deletions(-) diff --git a/package-lock.json b/package-lock.json index b83fb86d..4a403917 100644 --- a/package-lock.json +++ b/package-lock.json @@ -75,6 +75,7 @@ "devDependencies": { "@playwright/test": "^1.50.0", "@stylistic/eslint-plugin-ts": "^2.8.0", + "@tailwindcss/typography": "^0.5.16", "@types/cookie": "^0.3.3", "@types/debug": "^4.1.5", "@types/diff": "^7.0.1", @@ -168,7 +169,7 @@ "pump": "^1.0.1", "rcedit": "^1.1.0", "rimraf": "^2.7.1", - "scope-tailwind": "^1.0.6", + "scope-tailwind": "^1.0.9", "sinon": "^12.0.1", "sinon-test": "^3.1.3", "source-map": "0.6.1", @@ -3598,6 +3599,36 @@ "node": ">=10" } }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz", + "integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + } + }, + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@thisismanta/pessimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@thisismanta/pessimist/-/pessimist-1.2.0.tgz", @@ -14039,6 +14070,13 @@ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY= sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "dev": true }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.clone": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", @@ -14057,6 +14095,13 @@ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -18820,9 +18865,9 @@ "dev": true }, "node_modules/scope-tailwind": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/scope-tailwind/-/scope-tailwind-1.0.6.tgz", - "integrity": "sha512-tkISLsaesYKKXL9YrLsRWFOD/FhrRVGKeinjgTuFtEidryLzwlBB3G17ArmHWHYcfdMp00XwnRMcGFkF8wwG6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/scope-tailwind/-/scope-tailwind-1.0.9.tgz", + "integrity": "sha512-sxtAKxJq143lYK/RCE36YGq13ficBZ9/9Z0TZa78k0AEiKNT5nH4kfhD8YAfEXR/qPR+G7tl9KL4UoHh+Cs93g==", "dev": true, "license": "AGPL-3.0-only", "dependencies": { diff --git a/package.json b/package.json index 91cf98d0..52387a3e 100644 --- a/package.json +++ b/package.json @@ -136,6 +136,7 @@ "devDependencies": { "@playwright/test": "^1.50.0", "@stylistic/eslint-plugin-ts": "^2.8.0", + "@tailwindcss/typography": "^0.5.16", "@types/cookie": "^0.3.3", "@types/debug": "^4.1.5", "@types/diff": "^7.0.1", @@ -229,7 +230,7 @@ "pump": "^1.0.1", "rcedit": "^1.1.0", "rimraf": "^2.7.1", - "scope-tailwind": "^1.0.6", + "scope-tailwind": "^1.0.9", "sinon": "^12.0.1", "sinon-test": "^3.1.3", "source-map": "0.6.1", diff --git a/src/vs/workbench/contrib/void/browser/react/build.js b/src/vs/workbench/contrib/void/browser/react/build.js index ab4ea921..26b5bc37 100755 --- a/src/vs/workbench/contrib/void/browser/react/build.js +++ b/src/vs/workbench/contrib/void/browser/react/build.js @@ -74,7 +74,7 @@ function saveStylesFile() { } catch (err) { console.error('[scope-tailwind] Error saving styles.css:', err); } - }, 3000); + }, 4000); } const args = process.argv.slice(2); diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx index 65786cfe..b4f6232c 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx @@ -14,10 +14,6 @@ export type ChatMessageLocation = { messageIdx: number; } - -const cn = (className: string) => className?.split(' ').map(c => c ? `void-${c}` : '').join(' ') - - type ApplyBoxLocation = ChatMessageLocation & { tokenIdx: string } const getApplyBoxId = ({ threadId, messageIdx, tokenIdx }: ApplyBoxLocation) => { @@ -26,6 +22,7 @@ const getApplyBoxId = ({ threadId, messageIdx, tokenIdx }: ApplyBoxLocation) => + // all classnames must go in tailwind.config.js/safelist export const noSpaceStyles = { blockquote: 'pl-4 border-l-4 border-void-bg-2 italic', @@ -88,31 +85,17 @@ const defaultStyles = { text: '', } - - -type TokenClasses = typeof defaultStyles - -const RenderToken = ({ token, nested, chatMessageLocationForApply, tokenIdx, classes }: { token: Token | string, nested?: boolean, chatMessageLocationForApply?: ChatMessageLocation, tokenIdx: string, classes?: TokenClasses }): JSX.Element => { - +const RenderToken = ({ token, nested, chatMessageLocationForApply, tokenIdx }: { token: Token | string, nested?: boolean, chatMessageLocationForApply?: ChatMessageLocation, tokenIdx: string }): JSX.Element => { // deal with built-in tokens first (assume marked token) const t = token as MarkedToken - if(t.raw.trim() ===''){ + if (t.raw.trim() === '') { return <>; } - // compute the className - const defaultClassName = defaultStyles[t.type] - const classNameOverride = classes?.[t.type] - const _className = classNameOverride ?? defaultClassName - let className: string = '' - if (typeof defaultClassName === 'string') { - className = _className as string - } - if (t.type === "space") { - return {t.raw} + return {t.raw} } if (t.type === "code") { @@ -123,7 +106,7 @@ const RenderToken = ({ token, nested, chatMessageLocationForApply, tokenIdx, cla tokenIdx: tokenIdx, }) : null - return
+ return
{t.text} + return {t.text} } if (t.type === "table") { return ( -
- +
+
- + {t.header.map((cell: any, index: number) => ( - ))} @@ -160,13 +137,9 @@ const RenderToken = ({ token, nested, chatMessageLocationForApply, tokenIdx, cla {t.rows.map((row: any[], rowIndex: number) => ( - + {row.map((cell: any, cellIndex: number) => ( - ))} @@ -176,20 +149,54 @@ const RenderToken = ({ token, nested, chatMessageLocationForApply, tokenIdx, cla
+ {cell.raw}
+ {cell.raw}
) + // return ( + //
+ // + // + // + // {t.header.map((cell: any, index: number) => ( + // + // ))} + // + // + // + // {t.rows.map((row: any[], rowIndex: number) => ( + // + // {row.map((cell: any, cellIndex: number) => ( + // + // ))} + // + // ))} + // + //
+ // {cell.raw} + //
+ // {cell.raw} + //
+ //
+ // ) } if (t.type === "hr") { - return
+ return
} if (t.type === "blockquote") { - return
{t.text}
+ return
{t.text}
} if (t.type === 'list_item') { -
  • - - !!!!!!!!!!!!! + return
  • + +
  • @@ -198,68 +205,49 @@ const RenderToken = ({ token, nested, chatMessageLocationForApply, tokenIdx, cla if (t.type === "list") { const ListTag = t.ordered ? "ol" : "ul" - const itemClassName = classes?.['list_item'] ?? defaultStyles['list_item'] - return ( - + {t.items.map((item, index) => ( -
  • +
  • {item.task && ( - + )} - +
  • ))}
    ) - // attempt at indentation - // return ( - // - // {t.items.map((item, index) => ( - //
  • - // {item.task && ( - // - // )} - // - // - // - //
  • - // ))} - //
    - // ) } if (t.type === "paragraph") { const contents = <> {t.tokens.map((token, index) => ( - // assign a unique tokenId to nested components + ))} + if (nested) return contents - return

    + return

    {contents}

    } if (t.type === "html") { return ( -

    +

    {t.raw}

    ) } if (t.type === "text" || t.type === "escape") { - return {t.raw} + return {t.raw} } if (t.type === "def") { @@ -269,10 +257,10 @@ const RenderToken = ({ token, nested, chatMessageLocationForApply, tokenIdx, cla if (t.type === "link") { return ( { window.open(t.href) }} href={t.href} title={t.title ?? undefined} + className='underline cursor-pointer hover:brightness-90 transition-all duration-200' > {t.text} @@ -284,52 +272,50 @@ const RenderToken = ({ token, nested, chatMessageLocationForApply, tokenIdx, cla src={t.href} alt={t.text} title={t.title ?? undefined} - className={cn(className)} + /> } if (t.type === "strong") { - return {t.text} + return {t.text} } if (t.type === "em") { - return {t.text} + return {t.text} } // inline code if (t.type === "codespan") { return ( - + {t.text} ) } if (t.type === "br") { - return
    + return
    } // strikethrough if (t.type === "del") { - return {t.text} + return {t.text} } // default return (
    - Unknown type: - {t.type} - {t.raw} + Unknown token rendered...
    ) } -export const ChatMarkdownRender = ({ string, nested = false, classes, chatMessageLocationForApply }: { string: string, nested?: boolean, classes?: TokenClasses, chatMessageLocationForApply?: ChatMessageLocation }) => { +export const ChatMarkdownRender = ({ string, nested = false, chatMessageLocationForApply }: { string: string, nested?: boolean, chatMessageLocationForApply?: ChatMessageLocation }) => { const tokens = marked.lexer(string); // https://marked.js.org/using_pro#renderer return ( <> {tokens.map((token, index) => ( - + ))} ) diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx index 839a6679..dd49d08a 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/Sidebar.tsx @@ -2,11 +2,6 @@ * Copyright 2025 Glass Devtools, Inc. All rights reserved. * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. *--------------------------------------------------------------------------------------*/ -import React, { useEffect, useState } from 'react' -import { mountFnGenerator } from '../util/mountFnGenerator.js' - -// import { SidebarSettings } from './SidebarSettings.js'; - import { useIsDark, useSidebarState } from '../util/services.js'; // import { SidebarThreadSelector } from './SidebarThreadSelector.js'; @@ -20,9 +15,9 @@ export const Sidebar = ({ className }: { className: string }) => { const sidebarState = useSidebarState() const { currentTab: tab } = sidebarState - // const isDark = useIsDark() + const isDark = useIsDark() return
    { colorThemeState = themeService.getColorTheme().type disposables.push( - themeService.onDidColorThemeChange(theme => { - colorThemeState = theme.theme.type + themeService.onDidColorThemeChange(({ theme }) => { + colorThemeState = theme.type colorThemeStateListeners.forEach(l => l(colorThemeState)) }) ) diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx index 1ebbefc9..79c8fdb8 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx @@ -15,7 +15,7 @@ import { isWindows, isLinux, isMacintosh } from '../../../../../../../base/commo import { URI } from '../../../../../../../base/common/uri.js' import { env } from '../../../../../../../base/common/process.js' import { ModelDropdown } from './ModelDropdown.js' -import { ChatMarkdownRender, noSpaceStyles } from '../markdown/ChatMarkdownRender.js' +import { ChatMarkdownRender } from '../markdown/ChatMarkdownRender.js' import { WarningBox } from './WarningBox.js' import { os } from '../../../../common/helpers/systemInfo.js' @@ -293,7 +293,7 @@ const ProviderSetting = ({ providerName, settingName }: { providerName: Provider isPasswordField={isPasswordField} /> {subTextMd === undefined ? null :
    - +
    }
    @@ -412,12 +412,12 @@ export const FeaturesTab = () => { {/*

    {`Instructions:`}

    */} {/*

    {`Void can access any model that you host locally. We automatically detect your local models by default.`}

    */}

    {`Void can access any model that you host locally. We automatically detect your local models by default.`}

    -
    - - - - - +
    + + + + + {/* TODO we should create UI for downloading models without user going into terminal */}
    diff --git a/src/vs/workbench/contrib/void/browser/react/tailwind.config.js b/src/vs/workbench/contrib/void/browser/react/tailwind.config.js index 228b2847..be4f9a13 100644 --- a/src/vs/workbench/contrib/void/browser/react/tailwind.config.js +++ b/src/vs/workbench/contrib/void/browser/react/tailwind.config.js @@ -9,6 +9,29 @@ module.exports = { content: ['./src2/**/*.{jsx,tsx}'], // uses these files to decide how to transform the css file theme: { extend: { + typography: { + DEFAULT: { + css: { + '--tw-prose-body': 'var(--void-fg-1)', + '--tw-prose-headings': 'var(--void-fg-1)', + '--tw-prose-lead': 'var(--void-fg-2)', + '--tw-prose-links': 'var(--void-link-color)', + '--tw-prose-bold': 'var(--void-fg-1)', + '--tw-prose-counters': 'var(--void-fg-3)', + '--tw-prose-bullets': 'var(--void-fg-3)', + '--tw-prose-hr': 'var(--void-border-4)', + '--tw-prose-quotes': 'var(--void-fg-1)', + '--tw-prose-quote-borders': 'var(--void-border-2)', + '--tw-prose-captions': 'var(--void-fg-3)', + '--tw-prose-code': 'var(--void-fg-0)', + '--tw-prose-pre-code': 'var(--void-fg-0)', + '--tw-prose-pre-bg': 'var(--void-bg-1)', + '--tw-prose-th-borders': 'var(--void-border-4)', + '--tw-prose-td-borders': 'var(--void-border-4)', + }, + }, + + }, fontSize: { xs: '10px', sm: '11px', @@ -27,27 +50,29 @@ module.exports = { // common colors to use, ordered light to dark colors: { - 'void-bg-1': 'var(--vscode-input-background)', - 'void-bg-1-alt': 'var(--vscode-badge-background)', - 'void-bg-2': 'var(--vscode-sideBar-background)', - 'void-bg-2-alt': 'color-mix(in srgb, var(--vscode-sideBar-background) 30%, var(--vscode-editor-background) 70%)', - 'void-bg-3': 'var(--vscode-editor-background)', + 'void-bg-1': 'var(--void-bg-1)', + 'void-bg-1-alt': 'var(--void-bg-1-alt)', + 'void-bg-2': 'var(--void-bg-2)', + 'void-bg-2-alt': 'var(--void-bg-2-alt)', + 'void-bg-3': 'var(--void-bg-3)', - 'void-fg-1': 'var(--vscode-editor-foreground)', - 'void-fg-2': 'var(--vscode-input-foreground)', - 'void-fg-3': 'var(--vscode-input-placeholderForeground)', + 'void-fg-0': 'var(--void-fg-0)', + 'void-fg-1': 'var(--void-fg-1)', + 'void-fg-2': 'var(--void-fg-2)', + 'void-fg-3': 'var(--void-fg-3)', // 'void-fg-4': 'var(--vscode-tab-inactiveForeground)', - 'void-fg-4': 'var(--vscode-list-deemphasizedForeground)', + 'void-fg-4': 'var(--void-fg-4)', + 'void-warning': 'var(--void-warning)', - 'void-warning': 'var(--vscode-charts-yellow)', - - 'void-border-1': 'var(--vscode-commandCenter-activeBorder)', - 'void-border-2': 'var(--vscode-commandCenter-border)', - 'void-border-3': 'var(--vscode-commandCenter-inactiveBorder)', - 'void-border-4': 'var(--vscode-editorGroup-border)', + 'void-border-1': 'var(--void-border-1)', + 'void-border-2': 'var(--void-border-2)', + 'void-border-3': 'var(--void-border-3)', + 'void-border-4': 'var(--void-border-4)', + 'void-ring-color': 'var(--void-ring-color)', + 'void-link-color': 'var(--void-link-color)', vscode: { // see: https://code.visualstudio.com/api/extension-guides/webview#theming-webview-content @@ -166,83 +191,9 @@ module.exports = { }, }, }, - plugins: [], - prefix: 'void-', - safelist: [ - // Background colors - 'void-bg-void-bg-1', - - // Borders - 'void-border-b', - 'void-border-l-4', - 'void-border-t', - 'void-border-void-bg-2', - - // Typography - 'void-text-2xl', - 'void-text-3xl', - 'void-text-4xl', - 'void-text-base', - 'void-text-lg', - 'void-text-xl', - 'void-text-gray-600', - 'void-font-medium', - 'void-font-mono', - 'void-font-semibold', - 'void-italic', - 'void-line-through', - 'void-underline', - - // Spacing - 'void-mt-1', - 'void-mt-2', - 'void-mt-4', - 'void-mt-6', - 'void-mb-1', - 'void-mb-2', - 'void-mb-4', - 'void-mx-1', - 'void-mx-2', - 'void-mx-4', - 'void-my-1', - 'void-my-2', - 'void-my-4', - 'void-my-6', - 'void-pb-1', - 'void-pb-2', - 'void-pb-4', - 'void-pl-1', - 'void-pl-2', - 'void-pl-4', - 'void-px-1', - 'void-px-2', - 'void-px-4', - - // Sizing and layout - 'void-h-auto', - 'void-max-w-full', - 'void-overflow-x-auto', - - // Lists - 'void-list-inside', - 'void-list-decimal', - 'void-list-disc', - - // Effects and decoration - 'void-cursor-pointer', - 'void-ring-8', - 'void-ring-[#123456]', - 'void-rounded', - 'void-rounded-sm', - - // misc - 'void-break-all', - 'void-bg-void-bg-1', - 'void-px-1', - 'void-rounded-sm', - 'void-font-mono', - 'void-font-medium', - 'void-break-all' - ] + plugins: [ + require('@tailwindcss/typography') + ], + prefix: 'void-' }