Compare commits

...

36 Commits

Author SHA1 Message Date
Elio Struyf 62b9f12494 #673 - git settings 2024-02-05 19:28:16 +01:00
Elio Struyf accb069bab #673 - git enablement 2024-02-05 17:11:17 +01:00
Elio Struyf d869d15694 Fix loading 2024-02-05 16:25:37 +01:00
Elio Struyf e54907daaf Remove node-fetch dependency 2024-02-04 17:11:04 +01:00
Elio Struyf 7b689326e3 Cleanup 2024-02-03 13:08:15 +02:00
Elio Struyf 4a4db839ab #749 - Filter setting 2024-02-02 18:01:36 +02:00
Elio Struyf cc2c878c5c #747 - Add select options 2024-01-31 18:36:34 +02:00
Elio Struyf 273af6d80f Remove of useThemeColors hook 2024-01-31 18:09:58 +02:00
Elio Struyf 11233ba449 Fix localization string 2024-01-30 20:12:45 +01:00
Elio Struyf bb2ba5dbe8 #745 - Fix date field 2024-01-29 12:05:56 +01:00
Elio Struyf 128644eade Merge branch 'dev' of github.com:estruyf/vscode-front-matter into dev 2024-01-29 11:27:06 +01:00
Elio Struyf aced5c550f #731 - Fix in sorting 2024-01-29 11:26:58 +01:00
Elio Struyf 93b096ab3d Only use recently modified when activated 2024-01-26 20:08:09 +01:00
Elio Struyf 4dd27ad98f Added missing localization key + remove getColors 2024-01-26 19:48:13 +01:00
Elio Struyf 01ae0b49cc Reverse spin 2024-01-26 19:37:57 +01:00
Elio Struyf 313533d74d Style updates in data view 2024-01-26 16:52:28 +01:00
Elio Struyf 5f92ad33ff #743 - Fix for storing yaml 2024-01-26 16:42:57 +01:00
Elio Struyf 7240747e86 Add backer link 2024-01-26 10:23:37 +01:00
Elio Struyf fbbfaa572e #741 - content processing message 2024-01-24 15:44:33 +01:00
Elio Struyf b981ed6c4f Issue: Open Preview button stops working #738 2024-01-23 20:25:53 +01:00
Elio Struyf 3eb23d7501 Enhancement: configurable dashboard grid #737 2024-01-22 11:52:11 +01:00
Elio Struyf 965fac68c9 workbench color update 2024-01-19 14:32:29 +01:00
Elio Struyf e2837794f3 Folder optimizations 2024-01-19 13:35:06 +01:00
Elio Struyf ae436e1a0e Reuse text field component 2024-01-19 13:26:42 +01:00
Elio Struyf 0d19abfa8f Updated home icon 2024-01-19 09:30:51 +01:00
Elio Struyf 58d3c8e211 Add website URL info 2024-01-19 09:29:18 +01:00
Elio Struyf 2117dab03e Move functions 2024-01-18 09:01:12 +01:00
Elio Struyf 20ff578c3f Remove useThemeColors 2024-01-18 08:42:26 +01:00
Elio Struyf 3c29526d88 Merge pull request #733 from mayumih387/dev
Added and updated Japanese translations
2024-01-17 14:49:04 +01:00
Elio Struyf a9fb507b28 Opimizations 2024-01-17 14:48:34 +01:00
Elio Struyf d5adc348a2 Internal optimizations 2024-01-17 14:18:23 +01:00
Elio Struyf 71ecca3b85 #734 - fix for file updates 2024-01-17 13:33:13 +01:00
mayumih387 bb29fa344c Added and updated Japanese translations 2024-01-17 15:45:54 +09:00
Elio Struyf c67a1f9870 View action added 2024-01-16 21:12:28 +01:00
Elio Struyf c972325eff Merge branch 'poc/content-tagging' into dev 2024-01-16 14:22:30 +01:00
Elio Struyf 72f830e474 #730 - Verify if update is done after debounce update 2024-01-15 15:49:44 +01:00
142 changed files with 4911 additions and 14852 deletions
+6 -2
View File
@@ -1,5 +1,11 @@
// Place your settings in this file to overwrite default and user settings.
{
"workbench.colorCustomizations": {
"titleBar.activeBackground": "#15c2cb",
"titleBar.inactiveBackground": "#44ffd299",
"titleBar.activeForeground": "#0E131F",
"titleBar.inactiveForeground": "#0E131F99"
},
"files.exclude": {
"out": false // set this to true to hide the "out" folder with the compiled JS files
},
@@ -8,8 +14,6 @@
},
// Turn off tsc task auto detection since we have the necessary tasks as npm scripts
"typescript.tsc.autoDetect": "off",
"eliostruyf.writingstyleguide.terms.isDisabled": true,
"eliostruyf.writingstyleguide.biasFree.isDisabled": true,
"squarl.groups": [
{
"id": "dashboard",
+8
View File
@@ -5,10 +5,15 @@
### ✨ New features
- [#731](https://github.com/estruyf/vscode-front-matter/issues/731): Added the ability to map/unmap taxonomy to multiple pages at once
- [#749](https://github.com/estruyf/vscode-front-matter/issues/749): Ability to set your own filters on the content dashboard with the `frontMatter.content.filters` setting
### 🎨 Enhancements
- [#673](https://github.com/estruyf/vscode-front-matter/pull/673): Added git settings to the welcome view and settings view
- [#727](https://github.com/estruyf/vscode-front-matter/pull/727): Updated Japanese translations thanks to [mayumihara](https://github.com/mayumih387)
- [#737](https://github.com/estruyf/vscode-front-matter/issues/737): Optimize the grid layout of the content and media dashboards
- [#741](https://github.com/estruyf/vscode-front-matter/issues/741): Added message on the content dashboard when content is processed
- [#747](https://github.com/estruyf/vscode-front-matter/issues/747): The `@frontmatter/extensibility` dependency now supports scripts for placeholders
### ⚡️ Optimizations
@@ -17,6 +22,9 @@
- [#721](https://github.com/estruyf/vscode-front-matter/issues/721): Fix keywords regex to support unicode characters
- [#725](https://github.com/estruyf/vscode-front-matter/issues/725): Fix for opening menu of pinned items
- [#730](https://github.com/estruyf/vscode-front-matter/issues/730): Add debounce to the input fields
- [#738](https://github.com/estruyf/vscode-front-matter/issues/738): Fix when re-opening the preview after closing it
- [#743](https://github.com/estruyf/vscode-front-matter/issues/743): Fix for storing data in YAML data files
- [#745](https://github.com/estruyf/vscode-front-matter/issues/745): Fix for date field values in `block` field type
## [9.4.0] - 2023-12-12 - [Release notes](https://beta.frontmatter.codes/updates/v9.4.0)
-78
View File
@@ -1,78 +0,0 @@
import { By, VSBrowser, EditorView, WebView, Workbench, Notification, StatusBar, NotificationType } from "vscode-extension-tester";
import { expect } from "chai";
import { sleep } from "./utils";
import { join } from "path";
// https://github.com/microsoft/vscode-java-dependency/blob/4256fa6adcaff5ec24dbdbb8d9a516fad21431c5/test/ui/index.ts
// https://github.com/microsoft/vscode-java-dependency/blob/4256fa6adcaff5ec24dbdbb8d9a516fad21431c5/test/ui/command.test.ts
describe("Initialization testing", function() {
this.timeout(2 * 60 * 1000 /*ms*/);
let workbench: Workbench;
let view: WebView;
before(async function() {
await VSBrowser.instance.openResources(join(__dirname, '../sample'));
await sleep(3000);
workbench = new Workbench();
await workbench.executeCommand("frontMatter.dashboard");
await sleep(3000);
await new EditorView().openEditor(`FrontMatter Dashboard`);
view = new WebView();
await view.switchToFrame();
});
it("1. Open welcome dashboard", async function() {
const element = await view.findWebElement(By.css('h1'));
const title = await element.getText();
expect(title).has.string(`Front Matter`);
});
it("2. Initialize project", async function() {
const btn = await view.findWebElement(By.css('[data-test="welcome-init"] button'));
expect(btn).to.exist;
await btn.click();
await sleep(1000);
await VSBrowser.instance.driver.wait(() => {
return notificationExists(workbench, 'Front Matter:');
}, 2000) as Notification;
const notifications = await workbench.getNotifications();
let notification!: Notification;
for (const not of notifications) {
console.log(not);
// const message = await not.get;
// console.log(message);
// if (message.includes('Front Matter:')) {
// notification = not;
// }
}
expect(await notification.getMessage()).has.string(`Project initialized successfully.`);
});
it("3. Check if project file is created", async function() {});
});
async function notificationExists(workbench: Workbench, text: string): Promise<Notification | undefined> {
const notifications = await (await (new StatusBar()).openNotificationsCenter()).getNotifications(NotificationType.Info);
for (const notification of notifications) {
const message = await notification.getMessage();
if (message.indexOf(text) >= 0) {
return notification;
}
}
}
-33
View File
@@ -1,33 +0,0 @@
import * as path from 'path'
import * as semver from 'semver'
import { ExTester, ReleaseQuality } from 'vscode-extension-tester'
async function main(): Promise<void> {
const vsCodeVersion: semver.SemVer = new semver.SemVer(`1.66.0`)
const version = vsCodeVersion.version
const storageFolder = path.join(__dirname, '..', 'storage')
const extFolder = path.join(__dirname, '..', 'extensions')
try {
const testPath = path.join(__dirname, 'command.test.js')
const exTester = new ExTester(storageFolder, ReleaseQuality.Stable, extFolder)
await exTester.downloadCode(version)
await exTester.installVsix({ useYarn: false })
// await exTester.installFromMarketplace("eliostruyf.vscode-front-matter");
await exTester.downloadChromeDriver(version)
// await exTester.setupRequirements({vscodeVersion: version});
const result = await exTester.runTests(testPath, {
vscodeVersion: version,
resources: [storageFolder],
})
process.exit(result)
} catch (err) {
console.log(err)
process.exit(1)
}
}
main()
-1
View File
@@ -1 +0,0 @@
export * from './sleep';
-3
View File
@@ -1,3 +0,0 @@
export async function sleep(time: number) {
await new Promise((resolve) => setTimeout(resolve, time));
}
+10 -1
View File
@@ -4,6 +4,7 @@
"common.delete": "削除",
"common.cancel": "キャンセル",
"common.clear": "クリア",
"common.apply": "適用",
"common.clear.value": "値をクリア",
"common.search": "検索",
"common.save": "保存",
@@ -20,6 +21,7 @@
"common.slug": "スラッグ",
"common.support": "サポート",
"common.remove.value": "{0}を削除",
"common.filter": "絞り込み",
"common.filter.value": "{0}で絞り込み",
"common.error.message": "申し訳ありません。エラーが発生しました。",
"common.openOnWebsite": "ウェブサイトで開く",
@@ -32,6 +34,7 @@
"common.yes": "はい",
"common.no": "いいえ",
"common.openSettings": "設定を開く",
"common.back": "戻る",
"notifications.outputChannel.link": "出力ウィンドウ",
"notifications.outputChannel.description": "詳細は{0}を確認してください。",
@@ -117,7 +120,7 @@
"dashboard.header.breadcrumb.home": "ホーム",
"dashboard.header.clearFilters.title": "フィルター・グループ・並べ替えを解除",
"dashboard.header.clearFilters.title": "絞り込み・グループ・並べ替えを解除",
"dashboard.header.filter.default": "なし",
@@ -294,6 +297,10 @@
"dashboard.taxonomyView.taxonomyManager.table.heading.action": "コマンド",
"dashboard.taxonomyView.taxonomyManager.table.row.empty": "{0}はありません",
"dashboard.taxonomyView.taxonomyManager.table.unmapped.title": "設定ファイルに見つかりません",
"dashboard.taxonomyView.taxonomyManager.filterInput.placeholder": "絞り込み",
"dashboard.taxonomyView.taxonomyTagging.pageTitle": "タクソノミー {0} をリマッピング",
"dashboard.taxonomyView.taxonomyTagging.checkbox": "ページにタクソノミー{0}を付ける",
"dashboard.taxonomyView.taxonomyView.navigationBar.title": "タクソノミーを選択",
"dashboard.taxonomyView.taxonomyView.button.import": "タクソノミーをインポート",
@@ -661,9 +668,11 @@
"helpers.taxonomyHelper.createNew.input.placeholder": "作成したいタクソノミー名を入力してください。",
"helpers.taxonomyHelper.createNew.input.validate.noValue": "タクソノミー名は必須です。",
"helpers.taxonomyHelper.createNew.input.validate.exists": "このタクソノミー名は既に存在しています。",
"helpers.taxonomyHelper.process.insert": "{0}: 選択した記事に \"{1}\" を追加しています。",
"helpers.taxonomyHelper.process.edit": "{0}: {2}内の\"{1}\"を{3}に変更しています。",
"helpers.taxonomyHelper.process.merge": "{0}: {2}内の\"{1}\"を{3}にマージしています。",
"helpers.taxonomyHelper.process.delete": "{0}: \"{1}\"を{2}から削除しています。",
"helpers.taxonomyHelper.process.insert.success": "追加しました。",
"helpers.taxonomyHelper.process.edit.success": "変更しました。",
"helpers.taxonomyHelper.process.merge.success": "マージしました。",
"helpers.taxonomyHelper.process.delete.success": "削除しました。",
+11 -1
View File
@@ -36,6 +36,8 @@
"common.openSettings": "Open settings",
"common.back": "Back",
"loading.initPages": "Loading content",
"notifications.outputChannel.link": "output window",
"notifications.outputChannel.description": "Check the {0} for more details.",
@@ -48,6 +50,11 @@
"settings.diagnostic": "Diagnostic",
"settings.diagnostic.description": "You can run the diagnostics to check the whole Front Matter CMS configuration.",
"settings.diagnostic.link": "Run full diagnostics",
"settings.git": "Git synchronization",
"settings.git.enabled": "Enable Git synchronization to easily sync your changes with your repository.",
"settings.git.commitMessage": "Commit message",
"settings.git.submoduleInfo": "When working with Git submodules, you can refer to the submodule settings in the documentation.",
"settings.git.submoduleLink": "Read more about Git submodules",
"settings.commonSettings.website.title": "Website and SSG settings",
"settings.commonSettings.previewUrl": "Preview URL",
@@ -108,6 +115,7 @@
"dashboard.dataView.dataView.getStarted": "Select a data type to get started",
"dashboard.dataView.dataView.noDataFiles": "No data files found",
"dashboard.dataView.dataView.getStarted.link": "Read more to get started using data files",
"dashboard.dataView.dataView.update.message": "Updated your data entries",
"dashboard.dataView.emptyView.heading": "Select your date type first",
@@ -215,7 +223,7 @@
"dashboard.media.media.dragAndDrop": "You can also drag and drop images from your desktop and select them once uploaded.",
"dashboard.media.media.folder.upload": "Upload to {0}",
"dashboard.media.media.folder.default": "No folder selected, files you drop will be added to the {0} folder",
"dashboard.media.media.placeholder": "No media files to show. You can drag &amp; drop new files by holding your [shift] key.",
"dashboard.media.media.placeholder": "No media files to show. You can drag&drop new files by holding your [shift] key.",
"dashboard.media.media.contentFolder": "Content folder",
"dashboard.media.media.publicFolder": "Public folder",
@@ -275,6 +283,8 @@
"dashboard.steps.stepsToGetStarted.contentFolders.information.description": "You can also perform this action by right-clicking on the folder in the explorer view, and selecting register folder",
"dashboard.steps.stepsToGetStarted.tags.name": "Import all tags and categories (optional)",
"dashboard.steps.stepsToGetStarted.tags.description": "Now that Front Matter knows all the content folders. Would you like to import all tags and categories from the available content?",
"dashboard.steps.stepsToGetStarted.git.name": "Do you want to enable Git synchronization?",
"dashboard.steps.stepsToGetStarted.git.description": "Enable Git synchronization to eaily sync your changes with your repository.",
"dashboard.steps.stepsToGetStarted.showDashboard.name": "Show the dashboard",
"dashboard.steps.stepsToGetStarted.showDashboard.description": "Once all actions are completed, the dashboard can be loaded.",
"dashboard.steps.stepsToGetStarted.template.name": "Use a configuration template",
+3813 -13731
View File
File diff suppressed because it is too large Load Diff
+27 -14
View File
@@ -492,6 +492,31 @@
"markdownDescription": "%setting.frontMatter.content.wysiwyg.markdownDescription%",
"scope": "Content"
},
"frontMatter.content.filters": {
"type": "array",
"default": [
"pageFolders",
"tags",
"categories"
],
"markdownDescription": "%setting.frontMatter.content.filters.markdownDescription%",
"items": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"name": {
"type": "string"
}
}
}
]
},
"frontMatter.custom.scripts": {
"type": "array",
"default": [],
@@ -2541,9 +2566,6 @@
"prod:panel": "webpack --mode production --config ./webpack/panel.config.js",
"test-compile": "tsc -p ./",
"clean": "rimraf dist",
"start:site": "cd ./docs && npm run dev",
"clean:test": "rm ./e2e/sample/frontmatter.json || exit 0 && rm -rf ./e2e/sample/.frontmatter || exit 0",
"test": "npm run lint; tsc -p tsconfig.e2e.json && npm run clean:test && npm run i -g @vscode/vsce && node ./e2e/out/runTests.js",
"lint": "eslint --max-warnings=0 ./src/{commands,components}",
"prettier": "prettier --write ./src",
"localization:watch": "node ./scripts/watch-localization.js",
@@ -2563,26 +2585,22 @@
"@sentry/react": "^6.19.7",
"@sentry/tracing": "^6.19.7",
"@tailwindcss/forms": "^0.5.3",
"@types/chai": "^4.3.4",
"@types/glob": "7.1.3",
"@types/invariant": "^2.2.35",
"@types/js-yaml": "3.12.1",
"@types/js-yaml": "^4.0.9",
"@types/lodash.omit": "^4.5.7",
"@types/lodash.uniqby": "4.7.6",
"@types/lodash.xor": "^4.5.7",
"@types/mdast": "^3.0.10",
"@types/mime-types": "^2.1.1",
"@types/mocha": "^5.2.7",
"@types/mustache": "^4.2.2",
"@types/node": "10.17.48",
"@types/node-fetch": "^2.6.2",
"@types/node": "^18.17.1",
"@types/react": "17.0.0",
"@types/react-datepicker": "^4.8.0",
"@types/react-dom": "17.0.0",
"@types/vscode": "^1.73.0",
"@typescript-eslint/eslint-plugin": "^5.50.0",
"@typescript-eslint/parser": "^5.50.0",
"@vscode/codicons": "0.0.20",
"@vscode/l10n": "^0.0.14",
"@vscode/webview-ui-toolkit": "^1.2.2",
"@webpack-cli/serve": "^1.7.0",
@@ -2590,7 +2608,6 @@
"array-move": "^4.0.0",
"assert": "^2.0.0",
"autoprefixer": "^10.4.13",
"chai": "^4.3.7",
"cheerio": "1.0.0-rc.12",
"css-loader": "5.2.7",
"date-fns": "2.23.0",
@@ -2613,9 +2630,7 @@
"lodash.xor": "^4.5.0",
"mdast-util-from-markdown": "1.0.0",
"mime-types": "^2.1.35",
"mocha": "^10.2.0",
"mustache": "^4.2.0",
"node-fetch": "^2.6.9",
"node-json-db": "^2.2.0",
"npm-run-all": "^4.1.5",
"path-browserify": "^1.0.1",
@@ -2633,7 +2648,6 @@
"react-quill": "^2.0.0",
"react-router-dom": "^6.8.0",
"react-sortable-hoc": "^2.0.0",
"react-toastify": "^8.2.0",
"recoil": "^0.4.1",
"remark-gfm": "^3.0.1",
"rimraf": "^3.0.2",
@@ -2648,7 +2662,6 @@
"uniforms-bridge-json-schema": "^3.10.2",
"uniforms-unstyled": "^3.10.2",
"url-join-ts": "^1.0.5",
"vscode-extension-tester": "^5.3.0",
"wc-react": "github:estruyf/wc-react",
"webpack": "^5.75.0",
"webpack-bundle-analyzer": "^4.7.0",
+1
View File
@@ -92,6 +92,7 @@
"setting.frontMatter.content.sorting.items.properties.type.description": "Type of the field value",
"setting.frontMatter.content.supportedFileTypes.markdownDescription": "Specify the file types that you want to use in Front Matter. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.content.supportedfiletypes)",
"setting.frontMatter.content.wysiwyg.markdownDescription": "Specifies if you want to enable/disable the What You See, Is What You Get (WYSIWYG) markdown controls. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.content.wysiwyg)",
"setting.frontMatter.content.filters.markdownDescription": "Specify the filters you want to use for your content dashboard. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.content.filters)",
"setting.frontMatter.custom.scripts.markdownDescription": "Specify the path to a Node.js script to execute. The current file path will be provided as an argument. [Check in the docs](https://frontmatter.codes/docs/settings/overview#frontmatter.custom.scripts)",
"setting.frontMatter.custom.scripts.items.properties.id.description": "ID of the script.",
"setting.frontMatter.custom.scripts.items.properties.title.description": "Title you want to give to your script. Will be shown as the title of the button.",
+3 -3
View File
@@ -13,9 +13,9 @@ import {
TelemetryEvent
} from './../constants';
import * as vscode from 'vscode';
import { CustomPlaceholder, Field, TaxonomyType } from '../models';
import { CustomPlaceholder, Field } from '../models';
import { format } from 'date-fns';
import { ArticleHelper, Settings, SlugHelper, TaxonomyHelper } from '../helpers';
import { ArticleHelper, Settings, SlugHelper } from '../helpers';
import { Notifications } from '../helpers/Notifications';
import { extname, basename, parse, dirname } from 'path';
import { COMMAND_NAME, DefaultFields } from '../constants';
@@ -363,7 +363,7 @@ export class Article {
return;
}
let position = editor.selection.active;
const position = editor.selection.active;
const selectionText = editor.document.getText(editor.selection);
// Check for snippet wrapper
-1
View File
@@ -1,7 +1,6 @@
import { authentication, commands, ExtensionContext } from 'vscode';
import { COMMAND_NAME, CONTEXT } from '../constants';
import { Extension, Logger } from '../helpers';
import fetch from 'node-fetch';
import { Dashboard } from './Dashboard';
import { SettingsListener } from '../listeners/panel';
import { PanelProvider } from '../panelWebView/PanelProvider';
+1 -1
View File
@@ -22,7 +22,7 @@ export class Cache {
await Extension.getInstance().setState(key, data, type);
}
public static async clear(showNotification: boolean = true) {
public static async clear(showNotification = true) {
const ext = Extension.getInstance();
await ext.setState(ExtensionState.Dashboard.Pages.Cache, undefined, 'workspace', true);
-1
View File
@@ -283,7 +283,6 @@ export class Folders {
public static async getInfo(limit?: number): Promise<FolderInfo[] | null> {
const supportedFiles = Settings.get<string[]>(SETTING_CONTENT_SUPPORTED_FILETYPES);
const folders = Folders.get();
const wsFolder = parseWinPath(Folders.getWorkspaceFolder()?.fsPath || '');
if (folders && folders.length > 0) {
const folderInfo: FolderInfo[] = [];
+4 -1
View File
@@ -97,6 +97,9 @@ export class Preview {
const cspSource = webView.webview.cspSource;
webView.onDidDispose(() => {
if (crntFilePath && this.webviews[crntFilePath]) {
delete this.webviews[crntFilePath];
}
webView.dispose();
});
@@ -196,7 +199,7 @@ export class Preview {
* @param filePath
* @param slug
*/
public static async updatePageUrl(filePath: string, slug?: string) {
public static async updatePageUrl(filePath: string, _: string) {
const webView = this.webviews[filePath];
if (webView) {
const localhost = await this.getLocalServerUrl();
+1 -1
View File
@@ -24,7 +24,7 @@ export class Settings {
});
if (newOption) {
let options = (await TaxonomyHelper.get(type)) || [];
const options = (await TaxonomyHelper.get(type)) || [];
if (options.find((o) => o === newOption)) {
Notifications.warning(l10n.t(LocalizationKey.commandsSettingsCreateWarning, taxonomy));
+1 -1
View File
@@ -163,7 +163,7 @@ export class Template {
await copyFileAsync(template.fsPath, newFilePath);
// Update the properties inside the template
let frontMatter = await ArticleHelper.getFrontMatterByPath(newFilePath);
const frontMatter = await ArticleHelper.getFrontMatterByPath(newFilePath);
if (!frontMatter) {
Notifications.warning(l10n.t(LocalizationKey.commonError));
return;
@@ -29,7 +29,7 @@ function ListDel({ disabled, name, readOnly, ...props }: ListDelFieldProps) {
return (
<span
className="autoform__list_del_field"
className="autoform__list_del_field mb-1"
{...filterDOMProps(props)}
onClick={onAction}
onKeyDown={onAction}
@@ -26,6 +26,7 @@ function LongText({
<LabelField label={label} id={id} required={props.required} />
<textarea
className={`block w-full py-2 pr-2 sm:text-sm appearance-none disabled:opacity-50 rounded bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] border-[var(--frontmatter-border)] focus:border-[var(--vscode-focusBorder)] focus:outline-0`}
disabled={disabled}
id={id}
name={name}
@@ -28,6 +28,7 @@ function Text({
<LabelField label={label} id={id} required={props.required} />
<input
className='block w-full py-2 pr-2 sm:text-sm appearance-none disabled:opacity-50 rounded bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] border-[var(--frontmatter-border)] focus:border-[var(--vscode-focusBorder)] focus:outline-0'
autoComplete={autoComplete}
disabled={disabled}
id={id}
+1
View File
@@ -8,6 +8,7 @@ export const GeneralCommands = {
toVSCode: {
openLink: 'openLink',
gitSync: 'gitSync',
gitIsRepo: 'gitIsRepo',
getLocalization: 'getLocalization',
openOnWebsite: 'openOnWebsite'
}
+3
View File
@@ -0,0 +1,3 @@
export const GIT_CONFIG = {
defaultCommitMessage: 'Synced by Front Matter'
};
+2
View File
@@ -8,3 +8,5 @@ export const DOCUMENTATION_SETTINGS_LINK = 'https://frontmatter.codes/docs/setti
export const SENTRY_LINK =
'https://1ac45704bbe74264a7b4674bdc2abf48@o1022172.ingest.sentry.io/5988293';
export const DOCS_SUBMODULES = 'https://frontmatter.codes/docs/git-integration#git-submodules';
+1
View File
@@ -7,6 +7,7 @@ export * from './ExtensionState';
export * from './Features';
export * from './FrameworkDetectors';
export * from './GeneralCommands';
export * from './Git';
export * from './Links';
export * from './LocalStore';
export * from './Navigation';
+1
View File
@@ -60,6 +60,7 @@ export const SETTING_CONTENT_STATIC_FOLDER = 'content.publicFolder';
export const SETTING_CONTENT_FRONTMATTER_HIGHLIGHT = 'content.fmHighlight';
export const SETTING_CONTENT_DRAFT_FIELD = 'content.draftField';
export const SETTING_CONTENT_SORTING = 'content.sorting';
export const SETTING_CONTENT_FILTERS = 'content.filters';
export const SETTING_CONTENT_WYSIWYG = 'content.wysiwyg';
export const SETTING_CONTENT_PLACEHOLDERS = 'content.placeholders';
export const SETTING_CONTENT_SNIPPETS = 'content.snippets';
+1
View File
@@ -1,4 +1,5 @@
export enum DashboardCommand {
initializing = 'initializing',
loading = 'loading',
pages = 'pages',
searchPages = 'searchPages',
+1
View File
@@ -74,6 +74,7 @@ export enum DashboardMessage {
runCustomScript = 'runCustomScript',
sendTelemetry = 'sendTelemetry',
logError = 'logError',
showNotification = 'showNotification',
// Settings
getSettings = 'getSettings',
+2 -2
View File
@@ -30,7 +30,7 @@ export interface IAppProps {
export const App: React.FunctionComponent<IAppProps> = ({
showWelcome
}: React.PropsWithChildren<IAppProps>) => {
const { loading, pages, settings, localeReady } = useMessages();
const { pages, settings, localeReady } = useMessages();
const view = useRecoilValue(DashboardViewSelector);
const mode = useRecoilValue(ModeAtom);
const [isDevMode, setIsDevMode] = useState(false);
@@ -123,7 +123,7 @@ Stack: ${componentStack}`
<Route path={routePaths.welcome} element={<WelcomeScreen settings={settings} />} />
<Route
path={routePaths.contents}
element={<Contents pages={pages} loading={loading} />}
element={<Contents pages={pages} />}
/>
<Route path={routePaths.media} element={<Media />} />
<Route path={routePaths.snippets} element={<Snippets />} />
@@ -1,7 +1,6 @@
import { PaperAirplaneIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import { useCallback } from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -13,7 +12,6 @@ export interface IChatboxProps {
export const Chatbox: React.FunctionComponent<IChatboxProps> = ({ isLoading, onTrigger }: React.PropsWithChildren<IChatboxProps>) => {
const [message, setMessage] = React.useState<string>("");
const [isFocussed, setIsFocussed] = React.useState<boolean>(false);
const { getColors } = useThemeColors();
const callAi = useCallback(() => {
setTimeout(() => {
@@ -29,11 +27,7 @@ export const Chatbox: React.FunctionComponent<IChatboxProps> = ({ isLoading, onT
<div className='chatbox px-4'>
<textarea
className={`
resize-none w-full outline-none border-0 pr-8
${getColors(
'focus:outline-none border-gray-300 text-vulcan-500',
'border-transparent bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-none focus:border-transparent'
)}`}
resize-none w-full outline-none border-0 pr-8 border-transparent bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-none focus:border-transparent`}
placeholder={l10n.t(LocalizationKey.dashboardChatbotChatboxPlaceholder)}
autoFocus={true}
value={message}
@@ -1,7 +1,6 @@
import { Menu } from '@headlessui/react';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import { MenuItem, MenuItems } from '../Menu';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -24,18 +23,13 @@ export const ChoiceButton: React.FunctionComponent<IChoiceButtonProps> = ({
choices,
title
}: React.PropsWithChildren<IChoiceButtonProps>) => {
const { getColors } = useThemeColors();
return (
<span className="relative z-50 inline-flex shadow-sm rounded-md">
<button
type="button"
className={`inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium ${choices.length > 0 ? `rounded-l` : `rounded`
} ${getColors(
`text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 disabled:bg-gray-500`,
`text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`
)
}`}
} text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`}
onClick={onClick}
disabled={disabled}
>
@@ -45,11 +39,7 @@ export const ChoiceButton: React.FunctionComponent<IChoiceButtonProps> = ({
{choices.length > 0 && (
<Menu as="span" className="-ml-px relative block">
<Menu.Button
className={`h-full inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium focus:outline-none rounded-r ${getColors(
`text-white dark:text-vulcan-500 bg-teal-700 hover:bg-teal-800 disabled:bg-gray-500`,
`text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`
)
}`}
className={`h-full inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium focus:outline-none rounded-r text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`}
disabled={disabled}
>
<span className="sr-only">{l10n.t(LocalizationKey.dashboardCommonChoiceButtonOpen)}</span>
@@ -1,7 +1,6 @@
import { format as fnsFormat } from 'date-fns';
import * as React from 'react';
import { DateHelper } from '../../../helpers/DateHelper';
import useThemeColors from '../../hooks/useThemeColors';
export interface IDateFieldProps {
className?: string;
@@ -15,7 +14,6 @@ export const DateField: React.FunctionComponent<IDateFieldProps> = ({
format
}: React.PropsWithChildren<IDateFieldProps>) => {
const [dateValue, setDateValue] = React.useState<string>('');
const { getColors } = useThemeColors();
React.useEffect(() => {
try {
@@ -38,7 +36,7 @@ export const DateField: React.FunctionComponent<IDateFieldProps> = ({
}
return (
<span className={`date__field ${className || ''} text-xs ${getColors(`text-vulcan-100 dark:text-whisper-900`, `text-[var(--vscode-editor-foreground)]`)}`}>
<span className={`date__field ${className || ''} text-xs text-[var(--frontmatter-text)]`}>
{dateValue}
</span>
);
@@ -0,0 +1,18 @@
import * as React from 'react';
export interface ILinkProps {
title: string;
href: string;
className?: string;
}
export const Link: React.FunctionComponent<ILinkProps> = ({ children, title, href, className }: React.PropsWithChildren<ILinkProps>) => {
return (
<a
className={`text-[var(--frontmatter-secondary-text)] hover:text-[var(--frontmatter-link-hover)] ${className || ""}`}
title={title}
href={href}>
{children}
</a>
);
};
@@ -1,5 +1,4 @@
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface ILinkButtonProps {
title: string;
@@ -7,17 +6,10 @@ export interface ILinkButtonProps {
}
export const LinkButton: React.FunctionComponent<ILinkButtonProps> = ({ children, title, onClick }: React.PropsWithChildren<ILinkButtonProps>) => {
const { getColors } = useThemeColors();
return (
<button
type="button"
className={
getColors(
`text-gray-500 hover:text-vulcan-600 dark:text-gray-400 dark:hover:text-whisper-600`,
`text-[var(--frontmatter-secondary-text)] hover:text-[var(--frontmatter-link-hover)]`
)
}
className={`text-[var(--frontmatter-secondary-text)] hover:text-[var(--frontmatter-link-hover)]`}
title={title}
onClick={onClick}>
{children}
@@ -1,9 +1,14 @@
import * as React from 'react';
import { LoadingType } from '../../../models';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
export interface ISpinnerProps { }
export interface ISpinnerProps {
type?: LoadingType;
}
export const Spinner: React.FunctionComponent<ISpinnerProps> = (
_: React.PropsWithChildren<ISpinnerProps>
{ type }: React.PropsWithChildren<ISpinnerProps>
) => {
return (
<div className={`z-50 fixed top-0 left-0 right-0 bottom-0 w-full h-full bg-[var(--vscode-editor-background)] opacity-75`}>
@@ -12,6 +17,15 @@ export const Spinner: React.FunctionComponent<ISpinnerProps> = (
>
<div className={`h-full absolute rounded-sm bg-[var(--vscode-activityBarBadge-background)] animate-[vscode-loader_4s_ease-in-out_infinite]`} />
</div>
{
type === 'initPages' && (
<div className='spinner-msg h-full text-2xl flex justify-center items-center text-[var(--vscode-foreground)]'>
<span>{l10n.t(LocalizationKey.loadingInitPages)}</span>
<span className='dots'></span>
</div>
)
}
</div>
);
};
@@ -0,0 +1,78 @@
import { XCircleIcon } from '@heroicons/react/24/solid';
import * as React from 'react';
export interface ITextFieldProps {
name: string;
value?: string;
placeholder?: string;
icon?: JSX.Element;
disabled?: boolean;
autoFocus?: boolean;
multiline?: boolean;
rows?: number;
onChange?: (value: string) => void;
onReset?: () => void;
}
export const TextField: React.FunctionComponent<ITextFieldProps> = ({
name,
value,
placeholder,
icon,
autoFocus,
multiline,
rows,
disabled,
onChange,
onReset
}: React.PropsWithChildren<ITextFieldProps>) => {
return (
<div className="relative flex justify-center">
{
icon && (
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
{icon}
</div>
)
}
{
multiline ? (
<textarea
rows={rows || 3}
name={name}
className={`block w-full py-2 ${icon ? "pl-10" : "pl-2"} pr-2 sm:text-sm appearance-none disabled:opacity-50 rounded bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] border-[var(--frontmatter-border)] focus:border-[var(--vscode-focusBorder)] focus:outline-0`}
style={{
boxShadow: "none"
}}
placeholder={placeholder || ""}
value={value}
autoFocus={!!autoFocus}
onChange={(e) => onChange && onChange(e.target.value)}
disabled={!!disabled}
/>
) : (
<input
type="text"
name={name}
className={`block w-full py-2 ${icon ? "pl-10" : "pl-2"} pr-2 sm:text-sm appearance-none disabled:opacity-50 rounded bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] border-[var(--frontmatter-border)] focus:border-[var(--vscode-focusBorder)] focus:outline-0`}
style={{
boxShadow: "none"
}}
placeholder={placeholder || ""}
value={value}
autoFocus={!!autoFocus}
onChange={(e) => onChange && onChange(e.target.value)}
disabled={!!disabled}
/>
)
}
{(value && onReset) && (
<button onClick={onReset} className="absolute inset-y-0 right-0 pr-3 flex items-center text-[var(--vscode-input-foreground)] hover:text-[var(--vscode-textLink-activeForeground)]">
<XCircleIcon className={`h-5 w-5`} aria-hidden="true" />
</button>
)}
</div>
);
};
@@ -8,7 +8,6 @@ import { MenuItem, MenuItems, ActionMenuButton, QuickAction } from '../Menu';
import { Alert } from '../Modals/Alert';
import { usePopper } from 'react-popper';
import { useState } from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { useRecoilState, useRecoilValue } from 'recoil';
@@ -36,7 +35,6 @@ export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
}: React.PropsWithChildren<IContentActionsProps>) => {
const [pinnedItems, setPinnedItems] = useRecoilState(PinnedItemsAtom);
const [showDeletionAlert, setShowDeletionAlert] = React.useState(false);
const { getColors } = useThemeColors();
const settings = useRecoilValue(SettingsSelector);
const [referenceElement, setReferenceElement] = useState<any>(null);
@@ -129,11 +127,7 @@ export const ContentActions: React.FunctionComponent<IContentActionsProps> = ({
>
<div
className={`flex items-center border border-transparent rounded-full ${listView ? '' : 'p-2 -mt-4'
} ${getColors(
'group-hover/card:bg-gray-200 dark:group-hover/card:bg-vulcan-200 group-hover/card:border-gray-100 dark:group-hover/card:border-vulcan-50',
'group-hover/card:bg-[var(--vscode-sideBar-background)] group-hover/card:border-[var(--frontmatter-border)]'
)
}`}
} group-hover/card:bg-[var(--vscode-sideBar-background)] group-hover/card:border-[var(--frontmatter-border)]`}
>
<Menu as="div" className={`relative flex text-left`}>
{!listView && (
@@ -1,7 +1,7 @@
import * as React from 'react';
import { useRecoilValue } from 'recoil';
import { Page } from '../../models';
import { SettingsSelector } from '../../state';
import { LoadingAtom, SettingsSelector } from '../../state';
import { Overview } from './Overview';
import { Spinner } from '../Common/Spinner';
import { SponsorMsg } from '../Layout/SponsorMsg';
@@ -14,13 +14,12 @@ import { PageLayout } from '../Layout/PageLayout';
export interface IContentsProps {
pages: Page[];
loading: boolean;
}
export const Contents: React.FunctionComponent<IContentsProps> = ({
pages,
loading
pages
}: React.PropsWithChildren<IContentsProps>) => {
const loading = useRecoilValue(LoadingAtom);
const settings = useRecoilValue(SettingsSelector);
const { pageItems } = usePages(pages);
@@ -34,8 +33,8 @@ export const Contents: React.FunctionComponent<IContentsProps> = ({
return (
<PageLayout folders={pageFolders} totalPages={pageItems.length}>
<div className="w-full flex-grow max-w-full mx-auto pb-6 px-4">
{loading ? <Spinner /> : <Overview pages={pageItems} settings={settings} />}
<div className="w-full flex-grow max-w-full mx-auto pb-6">
{loading ? <Spinner type={loading} /> : <Overview pages={pageItems} settings={settings} />}
</div>
<SponsorMsg
@@ -1,6 +1,5 @@
import * as React from 'react';
import { useRecoilValue } from 'recoil';
import useThemeColors from '../../hooks/useThemeColors';
import { DashboardViewType } from '../../models';
import { ViewSelector } from '../../state';
import * as l10n from '@vscode/l10n';
@@ -12,11 +11,10 @@ export const List: React.FunctionComponent<IListProps> = ({
children
}: React.PropsWithChildren<IListProps>) => {
const view = useRecoilValue(ViewSelector);
const { getColors } = useThemeColors();
let className = '';
if (view === DashboardViewType.Grid) {
className = `grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 gap-4`;
className = `grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 2xl:grid-cols-5 gap-4`;
} else if (view === DashboardViewType.List) {
className = `-mx-4`;
}
@@ -24,8 +22,7 @@ export const List: React.FunctionComponent<IListProps> = ({
return (
<ul role="list" className={className}>
{view === DashboardViewType.List && (
<li className={`px-5 relative uppercase py-2 border-b ${getColors('text-vulcan-100 dark:text-whisper-900 border-vulcan-50', 'text-[var(--vscode-editor-foreground)] border-[var(--frontmatter-border)]')
}`}>
<li className={`px-5 relative uppercase py-2 border-b text-[var(--vscode-editor-foreground)] border-[var(--frontmatter-border)]`}>
<div className={`grid grid-cols-12 gap-x-4 sm:gap-x-6 xl:gap-x-8`}>
<div className="col-span-8">{l10n.t(LocalizationKey.dashboardContentsListTitle)}</div>
<div className="col-span-2">{l10n.t(LocalizationKey.dashboardContentsListDate)}</div>
@@ -6,13 +6,10 @@ import { useRecoilState, useRecoilValue } from 'recoil';
import { groupBy } from '../../../helpers/GroupBy';
import { FrontMatterIcon } from '../../../panelWebView/components/Icons/FrontMatterIcon';
import { GroupOption } from '../../constants/GroupOption';
import { Page } from '../../models/Page';
import { Settings } from '../../models/Settings';
import { GroupingSelector, PageAtom, ViewSelector } from '../../state';
import { Item } from './Item';
import { List } from './List';
import usePagination from '../../hooks/usePagination';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { PinnedItemsAtom } from '../../state/atom/PinnedItems';
@@ -20,7 +17,7 @@ import { messageHandler } from '@estruyf/vscode/dist/client';
import { DashboardMessage } from '../../DashboardMessage';
import { PinIcon } from '../Icons/PinIcon';
import { PinnedItem } from './PinnedItem';
import { DashboardViewType } from '../../models';
import { DashboardViewType, Page, Settings } from '../../models';
export interface IOverviewProps {
pages: Page[];
@@ -36,7 +33,6 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({
const grouping = useRecoilValue(GroupingSelector);
const page = useRecoilValue(PageAtom);
const { pageSetNr } = usePagination(settings?.dashboardState.contents.pagination);
const { getColors } = useThemeColors();
const view = useRecoilValue(ViewSelector);
const pagedPages = useMemo(() => {
@@ -123,8 +119,7 @@ export const Overview: React.FunctionComponent<IOverviewProps> = ({
<div className={`flex items-center justify-center h-full`}>
<div className={`max-w-xl text-center`}>
<FrontMatterIcon
className={`h-32 mx-auto opacity-90 mb-8 ${getColors('text-vulcan-300 dark:text-whisper-800', 'text-[var(--vscode-editor-foreground)]')
}`}
className={`h-32 mx-auto opacity-90 mb-8 text-[var(--vscode-editor-foreground)]`}
/>
{settings && settings?.contentFolders?.length > 0 ? (
<p className={`text-xl font-medium`}>{l10n.t(LocalizationKey.dashboardContentsOverviewNoMarkdown)}</p>
@@ -16,26 +16,21 @@ import { EmptyView } from './EmptyView';
import { Container } from './SortableContainer';
import { SortableItem } from './SortableItem';
import { ChevronRightIcon, CircleStackIcon } from '@heroicons/react/24/outline';
import { ToastContainer, toast, Slide } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import { DataType } from '../../../models/DataType';
import { TelemetryEvent } from '../../../constants';
import { NavigationItem } from '../Layout';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { NavigationType } from '../../models';
export interface IDataViewProps { }
export const DataView: React.FunctionComponent<IDataViewProps> = (
props: React.PropsWithChildren<IDataViewProps>
_: React.PropsWithChildren<IDataViewProps>
) => {
const [selectedData, setSelectedData] = useState<DataFile | null>(null);
const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
const [dataEntries, setDataEntries] = useState<any | any[] | null>(null);
const settings = useRecoilValue(SettingsSelector);
const { getColors } = useThemeColors();
const setSchema = (dataFile: DataFile) => {
setSelectedData(dataFile);
@@ -112,15 +107,7 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
entries: data
});
// Show toast message
toast.success('Updated your data entries', {
position: 'top-right',
autoClose: 2000,
hideProgressBar: true,
closeOnClick: true,
pauseOnHover: false,
transition: Slide
});
Messenger.send(DashboardMessage.showNotification, l10n.t(LocalizationKey.dashboardDataViewDataViewUpdateMessage));
},
[selectedData]
);
@@ -178,27 +165,15 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
<div className="relative w-full flex-grow mx-auto overflow-hidden">
<div className={`flex w-64 flex-col absolute inset-y-0`}>
<aside
className={`flex flex-col flex-grow overflow-y-auto border-r py-6 px-4 overflow-auto ${getColors(
'border-gray-200 dark:border-vulcan-300',
'border-[var(--frontmatter-border)]'
)
}`}
className={`flex flex-col flex-grow overflow-y-auto border-r py-6 px-4 overflow-auto border-[var(--frontmatter-border)]`}
>
<h2 className={`text-lg ${getColors(
`text-gray-500 dark:text-whisper-900`,
`text-[var(--frontmatter-text)]`
)
}`}>
<h2 className={`text-lg text-[var(--frontmatter-text)]`}>
{l10n.t(LocalizationKey.dashboardDataViewDataViewSelect)}
</h2>
<nav className={`flex-1 py-4 -mx-4`}>
<div
className={`divide-y border-t border-b ${getColors(
`divide-gray-200 dark:divide-vulcan-300 border-gray-200 dark:border-vulcan-300`,
`divide-[var(--frontmatter-border)] border-[var(--frontmatter-border)]`
)
}`}
className={`divide-y border-t border-b divide-[var(--frontmatter-border)] border-[var(--frontmatter-border)]`}
>
{dataFiles &&
dataFiles.length > 0 &&
@@ -222,17 +197,9 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
<>
{!selectedData.singleEntry && (
<div
className={`w-1/3 py-6 px-4 flex-1 border-r overflow-auto ${getColors(
`border-gray-200 dark:border-vulcan-300`,
`border-[var(--frontmatter-border)]`
)
}`}
className={`w-1/3 py-6 px-4 flex-1 border-r overflow-auto border-[var(--frontmatter-border)]`}
>
<h2 className={`text-lg ${getColors(
`text-gray-500 dark:text-whisper-900`,
`text-[var(--frontmatter-text)]`
)
}`}>
<h2 className={`text-lg text-[var(--frontmatter-text)]`}>
{l10n.t(LocalizationKey.dashboardDataViewDataViewTitle, selectedData?.title?.toLowerCase() || '')}
</h2>
@@ -258,7 +225,7 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
</>
) : (
<div className={`flex flex-col items-center justify-center`}>
<p className={getColors(`text-gray-500 dark:text-whisper-900`, `text-[var(--frontmatter-text)]`)}>
<p className={`text-[var(--frontmatter-text)]`}>
{l10n.t(LocalizationKey.dashboardDataViewDataViewEmpty, selectedData.title.toLowerCase())}
</p>
</div>
@@ -270,7 +237,7 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
className={`${selectedData.singleEntry ? 'w-full' : 'w-2/3'
} py-6 px-4 overflow-auto`}
>
<h2 className={`text-lg ${getColors(`text-gray-500 dark:text-whisper-900`, `text-[var(--frontmatter-text)]`)}`}>
<h2 className={`text-lg text-[var(--frontmatter-text)]`}>
{l10n.t(LocalizationKey.dashboardDataViewDataViewCreateOrModify, selectedData.title.toLowerCase())}
</h2>
{selectedData ? (
@@ -292,16 +259,12 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
</div>
) : (
<div className="w-full h-full flex items-center justify-center">
<div className={`flex flex-col items-center ${getColors(
'text-gray-500 dark:text-whisper-900',
'text-[var(--frontmatter-text)]'
)
}`}>
<div className={`flex flex-col items-center text-[var(--frontmatter-text)]`}>
<CircleStackIcon className="w-32 h-32" />
<p className="text-3xl mt-2">{l10n.t(LocalizationKey.dashboardDataViewDataViewNoDataFiles)}</p>
<p className="text-xl mt-4">
<a
className={getColors(`text-teal-700 hover:text-teal-900`, `text-[var(--frontmatter-link)] hover:text-[var(--frontmatter-link-hover)]`)}
className={`text-[var(--frontmatter-link)] hover:text-[var(--frontmatter-link-hover)]`}
href={`https://frontmatter.codes/docs/dashboard#data-files-view`}
title={l10n.t(LocalizationKey.dashboardDataViewDataViewGetStartedLink)}
>
@@ -319,8 +282,6 @@ export const DataView: React.FunctionComponent<IDataViewProps> = (
isBacker={settings?.isBacker}
/>
<ToastContainer />
<img className='hidden' src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Ffrontmatter.codes%2Fmetrics%2Fdashboards&slug=DataView" alt="DataView metrics" />
</div >
);
@@ -1,6 +1,5 @@
import { ExclamationCircleIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -9,12 +8,11 @@ export interface IEmptyViewProps { }
export const EmptyView: React.FunctionComponent<IEmptyViewProps> = (
props: React.PropsWithChildren<IEmptyViewProps>
) => {
const { getColors } = useThemeColors();
return (
<div className="flex flex-col items-center justify-center w-full">
<ExclamationCircleIcon className={`w-1/12 opacity-90 ${getColors(`text-gray-500 dark:text-whisper-900`, `text-[var(--frontmatter-secondary-text)]`)}`} />
<h2 className={`text-xl ${getColors(`text-gray-500 dark:text-whisper-900`, `text-[var(--frontmatter-secondary-text)]`)}`}>
<ExclamationCircleIcon className={`w-1/12 opacity-90 text-[var(--frontmatter-secondary-text)]`} />
<h2 className={`text-xl text-[var(--frontmatter-secondary-text)]`}>
{l10n.t(LocalizationKey.dashboardDataViewEmptyViewHeading)}
</h2>
</div>
@@ -1,17 +1,14 @@
import * as React from 'react';
import { SortableContainer } from 'react-sortable-hoc';
import useThemeColors from '../../hooks/useThemeColors';
export interface ISortableContainerProps { }
export const Container = SortableContainer(
({ children }: React.PropsWithChildren<ISortableContainerProps>) => {
const { getColors } = useThemeColors();
return (
<ul
className={`-mx-4 divide-y border-t border-b ${getColors(`divide-gray-200 dark:divide-vulcan-300 border-gray-200 dark:border-vulcan-300`, `divide-[var(--frontmatter-border)] border-[var(--frontmatter-border)]`)
}`}
className={`-mx-4 divide-y border-t border-b divide-[var(--frontmatter-border)] border-[var(--frontmatter-border)]`}
>
{children}
</ul>
@@ -1,7 +1,6 @@
import { PencilIcon, ChevronDownIcon, TrashIcon } from '@heroicons/react/24/outline';
import { PencilIcon, TrashIcon, ChevronUpDownIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import { SortableHandle, SortableElement } from 'react-sortable-hoc';
import useThemeColors from '../../hooks/useThemeColors';
import { LinkButton } from '../Common/LinkButton';
import { Alert } from '../Modals/Alert';
import * as l10n from '@vscode/l10n';
@@ -16,7 +15,7 @@ export interface ISortableItemProps {
onDeleteItem: (index: number) => void;
}
const DragHandle = SortableHandle(() => <ChevronDownIcon className={`w-6 h-6 cursor-move hover:text-[var(--frontmatter-link-hover)]`} />);
const DragHandle = SortableHandle(() => <ChevronUpDownIcon className={`w-6 h-6 mr-2 cursor-move hover:text-[var(--frontmatter-link-hover)]`} />);
export const SortableItem = SortableElement(
({
@@ -27,7 +26,6 @@ export const SortableItem = SortableElement(
onDeleteItem
}: ISortableItemProps) => {
const [showAlert, setShowAlert] = React.useState(false);
const { getColors } = useThemeColors();
const deleteItemConfirm = () => {
setShowAlert(true);
@@ -37,12 +35,8 @@ export const SortableItem = SortableElement(
<>
<li
data-test={`${selectedIndex}-${crntIndex}`}
className={`sortable_item py-2 px-2 w-full flex justify-between content-center cursor-pointer ${selectedIndex === crntIndex ? getColors(`bg-gray-300 dark:bg-vulcan-300`, `bg-[var(--frontmatter-list-selected-background)] text-[var(--frontmatter-list-selected-text)]`) : ``
} ${getColors(
'hover:bg-gray-200 dark:hover:bg-vulcan-400',
'hover:bg-[var(--frontmatter-list-hover-background)]'
)
}`}
className={`sortable_item py-2 px-2 w-full flex justify-between content-center cursor-pointer ${selectedIndex === crntIndex ? `bg-[var(--frontmatter-list-selected-background)] text-[var(--frontmatter-list-selected-text)]` : ``
} hover:bg-[var(--frontmatter-list-hover-background)]`}
>
<div
className="flex items-center w-full"
@@ -1,6 +1,5 @@
import { ExclamationTriangleIcon } from '@heroicons/react/24/solid';
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -9,11 +8,9 @@ export interface IErrorViewProps { }
export const ErrorView: React.FunctionComponent<IErrorViewProps> = (
_: React.PropsWithChildren<IErrorViewProps>
) => {
const { getColors } = useThemeColors();
return (
<main className={`h-full w-full flex flex-col justify-center items-center space-y-2`}>
<ExclamationTriangleIcon className={`w-24 h-24 ${getColors(`text-red-500`, `text-[var(--vscode-editorError-foreground)]`)}`} />
<ExclamationTriangleIcon className={`w-24 h-24 text-[var(--vscode-editorError-foreground)]`} />
<p className="text-xl">{l10n.t(LocalizationKey.commonErrorMessage)}</p>
<p className="text-base">{l10n.t(LocalizationKey.dashboardErrorViewDescription)}</p>
</main>
@@ -1,10 +1,9 @@
import { HomeModernIcon } from '@heroicons/react/24/outline';
import { HomeIcon } from '@heroicons/react/24/outline';
import { basename, join } from 'path';
import * as React from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { HOME_PAGE_NAVIGATION_ID, STATIC_FOLDER_PLACEHOLDER } from '../../../constants';
import { HOME_PAGE_NAVIGATION_ID } from '../../../constants';
import { parseWinPath } from '../../../helpers/parseWinPath';
import useThemeColors from '../../hooks/useThemeColors';
import { SearchAtom, SelectedMediaFolderAtom, SettingsAtom } from '../../state';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -18,7 +17,6 @@ export const Breadcrumb: React.FunctionComponent<IBreadcrumbProps> = (
const [, setSearchValue] = useRecoilState(SearchAtom);
const [folders, setFolders] = React.useState<string[]>([]);
const settings = useRecoilValue(SettingsAtom);
const { getColors } = useThemeColors();
const updateFolder = (folder: string) => {
setSearchValue('');
@@ -86,12 +84,9 @@ export const Breadcrumb: React.FunctionComponent<IBreadcrumbProps> = (
<div className="flex items-center">
<button
onClick={() => setSelectedFolder(HOME_PAGE_NAVIGATION_ID)}
className={getColors(
`text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500`,
`text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)]`
)}
className={`text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)]`}
>
<HomeModernIcon className="flex-shrink-0 h-5 w-5" aria-hidden="true" />
<HomeIcon className="flex-shrink-0 h-5 w-5" aria-hidden="true" />
<span className="sr-only">{l10n.t(LocalizationKey.dashboardHeaderBreadcrumbHome)}</span>
</button>
</div>
@@ -101,11 +96,7 @@ export const Breadcrumb: React.FunctionComponent<IBreadcrumbProps> = (
<li key={folder} className="flex">
<div className="flex items-center">
<svg
className={`flex-shrink-0 h-5 w-5 ${getColors(
`text-gray-300 dark:text-whisper-900`,
`text-[var(--vscode-tab-inactiveForeground)]`
)
}`}
className={`flex-shrink-0 h-5 w-5 text-[var(--vscode-tab-inactiveForeground)]`}
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 20 20"
@@ -116,11 +107,7 @@ export const Breadcrumb: React.FunctionComponent<IBreadcrumbProps> = (
<button
onClick={() => updateFolder(folder)}
className={`ml-4 text-sm font-medium ${getColors(
`text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500`,
`text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)]`
)
}`}
className={`ml-4 text-sm font-medium text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)]`}
>
{basename(folder)}
</button>
@@ -11,11 +11,11 @@ import {
TagAtom,
CategoryAtom,
DEFAULT_TAG_STATE,
DEFAULT_CATEGORY_STATE
DEFAULT_CATEGORY_STATE,
FiltersAtom
} from '../../state';
import { DefaultValue } from 'recoil';
import { useEffect } from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import { useEffect, useMemo } from 'react';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -30,16 +30,17 @@ export const ClearFilters: React.FunctionComponent<IClearFiltersProps> = (
_: React.PropsWithChildren<IClearFiltersProps>
) => {
const [show, setShow] = React.useState(false);
const { getColors } = useThemeColors();
const folder = useRecoilValue(FolderSelector);
const tag = useRecoilValue(TagSelector);
const category = useRecoilValue(CategorySelector);
const filters = useRecoilValue(FiltersAtom);
const resetSorting = useResetRecoilState(SortingAtom);
const resetFolder = useResetRecoilState(FolderAtom);
const resetTag = useResetRecoilState(TagAtom);
const resetCategory = useResetRecoilState(CategoryAtom);
const resetFilters = useResetRecoilState(FiltersAtom);
const reset = () => {
setShow(false);
@@ -47,29 +48,32 @@ export const ClearFilters: React.FunctionComponent<IClearFiltersProps> = (
resetFolder();
resetTag();
resetCategory();
resetFilters();
};
const hasCustomFilters = useMemo(() => {
const names = Object.keys(filters);
return names.some((name) => filters[name]);
}, [filters]);
useEffect(() => {
if (
folder !== DEFAULT_FOLDER_STATE ||
tag !== DEFAULT_TAG_STATE ||
category !== DEFAULT_CATEGORY_STATE
category !== DEFAULT_CATEGORY_STATE ||
hasCustomFilters
) {
setShow(true);
} else {
setShow(false);
}
}, [folder, tag, category]);
}, [folder, tag, category, hasCustomFilters]);
if (!show) return null;
return (
<button
className={`flex items-center ${getColors(
'hover:text-teal-600',
'hover:text-[var(--vscode-textLink-activeForeground)]'
)
}`}
className={`flex items-center hover:text-[var(--vscode-textLink-activeForeground)]`}
onClick={reset}
title={l10n.t(LocalizationKey.dashboardHeaderClearFiltersTitle)}
>
@@ -1,8 +1,8 @@
import { MagnifyingGlassIcon, XCircleIcon } from '@heroicons/react/24/solid';
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { TextField } from '../Common/TextField';
export interface IFilterInputProps {
placeholder: string;
@@ -21,7 +21,6 @@ export const FilterInput: React.FunctionComponent<IFilterInputProps> = ({
onReset,
onChange
}: React.PropsWithChildren<IFilterInputProps>) => {
const { getColors } = useThemeColors();
return (
<div className="flex space-x-4 flex-1">
@@ -29,32 +28,19 @@ export const FilterInput: React.FunctionComponent<IFilterInputProps> = ({
<label htmlFor="search" className="sr-only">
{l10n.t(LocalizationKey.commonSearch)}
</label>
<div className="relative flex justify-center">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<MagnifyingGlassIcon className={`h-5 w-5 ${getColors(`text-gray-400`, 'text-[var(--vscode-input-foreground)]')}`} aria-hidden="true" />
</div>
<input
type="text"
name="search"
className={`block w-full py-2 pl-10 pr-3 sm:text-sm appearance-none disabled:opacity-50 rounded ${getColors(
'bg-white dark:bg-vulcan-300 border border-gray-300 dark:border-vulcan-100 text-vulcan-500 dark:text-whisper-500 placeholder-gray-400 dark:placeholder-whisper-800 focus:outline-none',
'bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] border-[var(--vscode-input-border)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent'
)
}`}
placeholder={placeholder || l10n.t(LocalizationKey.commonSearch)}
value={value}
autoFocus={autoFocus}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => onChange(event.target.value)}
disabled={!isReady}
/>
{value && onReset && (
<button onClick={onReset} className="absolute inset-y-0 right-0 pr-3 flex items-center">
<XCircleIcon className={`h-5 w-5 ${getColors(`text-gray-400`, 'text-[var(--vscode-input-foreground)]')}`} aria-hidden="true" />
</button>
<TextField
name='search'
icon={(
<MagnifyingGlassIcon className={`h-4 w-4 text-[var(--vscode-input-foreground)]`} aria-hidden="true" />
)}
</div>
value={value}
autoFocus={autoFocus}
placeholder={placeholder || l10n.t(LocalizationKey.commonSearch)}
disabled={!isReady}
onChange={onChange}
onReset={onReset}
/>
</div>
</div>
);
@@ -0,0 +1,108 @@
import * as React from 'react';
import { FoldersFilter } from './FoldersFilter';
import { Filter } from './Filter';
import { useRecoilState, useRecoilValue } from 'recoil';
import { CategoryAtom, SettingsSelector, TagAtom, FiltersAtom, FilterValuesAtom } from '../../state';
import { useEffect, useMemo } from 'react';
import { useLocation } from 'react-router-dom';
import { firstToUpper } from '../../../helpers/StringHelpers';
export interface IFiltersProps { }
export const Filters: React.FunctionComponent<IFiltersProps> = (_: React.PropsWithChildren<IFiltersProps>) => {
const [crntFilters, setCrntFilters] = useRecoilState(FiltersAtom);
const [crntTag, setCrntTag] = useRecoilState(TagAtom);
const [crntCategory, setCrntCategory] = useRecoilState(CategoryAtom);
const filterValues = useRecoilValue(FilterValuesAtom);
const settings = useRecoilValue(SettingsSelector);
const location = useLocation();
const otherFilters = useMemo(() => settings?.filters?.filter((filter) => filter !== "pageFolders" && filter !== "tags" && filter !== "categories"), [settings?.filters]);
const otherFilterValues = useMemo(() => {
return otherFilters?.map((filter) => {
const filterName = typeof filter === "string" ? filter : filter.name;
const filterTitle = typeof filter === "string" ? firstToUpper(filter) : filter.title;
const values = filterValues?.[filterName];
if (!values || values.length === 0) {
return null;
}
return (
<Filter
key={filterName}
label={filterTitle}
activeItem={crntFilters[filterName]}
items={values}
onClick={(value) => setCrntFilters((prev) => {
let clone = Object.assign({}, prev);
if (!clone[filterName] && value) {
clone[filterName] = value;
} else {
clone[filterName] = value || "";
}
return clone;
})}
/>
)
})
}, [otherFilters, crntFilters, filterValues, setCrntFilters]);
useEffect(() => {
if (location.search) {
const searchParams = new URLSearchParams(location.search);
const taxonomy = searchParams.get('taxonomy');
const value = searchParams.get('value');
if (taxonomy && value) {
if (taxonomy === 'tags') {
setCrntTag(value);
} else if (taxonomy === 'categories') {
setCrntCategory(value);
}
}
return;
}
setCrntFilters({});
setCrntTag('');
setCrntCategory('');
}, [location.search]);
return (
<>
{
settings?.filters?.includes("pageFolders") && (
<FoldersFilter />
)
}
{
settings?.filters?.includes("tags") && (
<Filter
label={`Tag`}
activeItem={crntTag}
items={settings?.tags || []}
onClick={(value) => setCrntTag(value)}
/>
)
}
{
settings?.filters?.includes("categories") && (
<Filter
label={`Category`}
activeItem={crntCategory}
items={settings?.categories || []}
onClick={(value) => setCrntCategory(value)}
/>
)
}
{otherFilterValues}
</>
);
};
@@ -6,11 +6,11 @@ import { MenuButton, MenuItem, MenuItems } from '../Menu';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
export interface IFoldersProps { }
export interface IFoldersFilterProps { }
export const Folders: React.FunctionComponent<
IFoldersProps
> = ({ }: React.PropsWithChildren<IFoldersProps>) => {
export const FoldersFilter: React.FunctionComponent<
IFoldersFilterProps
> = ({ }: React.PropsWithChildren<IFoldersFilterProps>) => {
const DEFAULT_TYPE = l10n.t(LocalizationKey.dashboardHeaderFoldersDefault);
const [crntFolder, setCrntFolder] = useRecoilState(FolderAtom);
const settings = useRecoilValue(SettingsSelector);
@@ -1,14 +1,12 @@
import * as React from 'react';
import { Sorting } from './Sorting';
import { Searchbox } from './Searchbox';
import { Filter } from './Filter';
import { Folders } from './Folders';
import { Settings, NavigationType } from '../../models';
import { DashboardMessage } from '../../DashboardMessage';
import { Grouping } from '.';
import { ViewSwitch } from './ViewSwitch';
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil';
import { CategoryAtom, GroupingSelector, SortingAtom, TagAtom } from '../../state';
import { useRecoilValue, useResetRecoilState } from 'recoil';
import { GroupingSelector, SortingAtom } from '../../state';
import { Messenger } from '@estruyf/vscode/dist/client';
import { ClearFilters } from './ClearFilters';
import { MediaHeaderTop } from '../Media/MediaHeaderTop';
@@ -16,7 +14,8 @@ import { ChoiceButton } from '../Common/ChoiceButton';
import { MediaHeaderBottom } from '../Media/MediaHeaderBottom';
import { Tabs } from './Tabs';
import { CustomScript } from '../../../models';
import { BoltIcon, PlusIcon } from '@heroicons/react/24/outline';
import { ArrowTopRightOnSquareIcon, BoltIcon, PlusIcon } from '@heroicons/react/24/outline';
import { HeartIcon } from '@heroicons/react/24/solid';
import { useLocation, useNavigate } from 'react-router-dom';
import { routePaths } from '../..';
import { useEffect, useMemo } from 'react';
@@ -30,6 +29,9 @@ import { ProjectSwitcher } from './ProjectSwitcher';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { SettingsLink } from '../SettingsView/SettingsLink';
import { Link } from '../Common/Link';
import { SPONSOR_LINK } from '../../../constants';
import { Filters } from './Filters';
export interface IHeaderProps {
header?: React.ReactNode;
@@ -47,8 +49,6 @@ export const Header: React.FunctionComponent<IHeaderProps> = ({
totalPages,
settings
}: React.PropsWithChildren<IHeaderProps>) => {
const [crntTag, setCrntTag] = useRecoilState(TagAtom);
const [crntCategory, setCrntCategory] = useRecoilState(CategoryAtom);
const grouping = useRecoilValue(GroupingSelector);
const resetSorting = useResetRecoilState(SortingAtom);
const location = useLocation();
@@ -120,35 +120,40 @@ export const Header: React.FunctionComponent<IHeaderProps> = ({
return [];
}, [settings?.dashboardState?.contents?.templatesEnabled]);
useEffect(() => {
if (location.search) {
const searchParams = new URLSearchParams(location.search);
const taxonomy = searchParams.get('taxonomy');
const value = searchParams.get('value');
if (taxonomy && value) {
if (taxonomy === 'tags') {
setCrntTag(value);
} else if (taxonomy === 'categories') {
setCrntCategory(value);
}
}
return;
}
setCrntTag('');
setCrntCategory('');
}, [location.search]);
return (
<div className={`w-full sticky top-0 z-20 bg-[var(--vscode-editor-background)] text-[var(--vscode-editor-foreground)]`}>
<div className={`mb-0 border-b flex justify-between bg-[var(--vscode-editor-background)] text-[var(--vscode-editor-foreground)] border-[var(--frontmatter-border)]`}>
<Tabs onNavigate={updateView} />
<div className='flex'>
<div className='flex items-center space-x-2 pr-4'>
<ProjectSwitcher />
{
settings?.websiteUrl && (
<Link
className='inline-flex items-center'
href={settings?.websiteUrl}
title={settings?.websiteUrl}>
<span>{settings?.websiteUrl}</span>
<ArrowTopRightOnSquareIcon className='w-4 h-4 ml-1' aria-hidden="true" />
</Link>
)
}
{
!settings?.isBacker && (
<Link
className='inline-flex items-center text-[var(--vscode-badge-background)]'
title={l10n.t(LocalizationKey.commonSupport)}
href={SPONSOR_LINK}
>
<span className='sr-only'>{l10n.t(LocalizationKey.commonSupport)}</span>
<HeartIcon className='w-4 h-4' aria-hidden="true" />
</Link>
)
}
<SettingsLink onNavigate={updateView} />
</div>
</div>
@@ -185,21 +190,7 @@ export const Header: React.FunctionComponent<IHeaderProps> = ({
>
<ClearFilters />
<Folders />
<Filter
label={`Tag`}
activeItem={crntTag}
items={settings?.tags || []}
onClick={(value) => setCrntTag(value)}
/>
<Filter
label={`Category`}
activeItem={crntCategory}
items={settings?.categories || []}
onClick={(value) => setCrntCategory(value)}
/>
<Filters />
<Grouping />
@@ -2,7 +2,6 @@ import * as React from 'react';
import { useCallback, useEffect, useMemo } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import usePagination from '../../hooks/usePagination';
import useThemeColors from '../../hooks/useThemeColors';
import { MediaTotalSelector, PageAtom, SettingsAtom } from '../../state';
import { PaginationButton } from './PaginationButton';
import * as l10n from '@vscode/l10n';
@@ -23,7 +22,6 @@ export const Pagination: React.FunctionComponent<IPaginationProps> = ({
totalPages,
totalMedia
);
const { getColors } = useThemeColors();
const getButtons = useCallback((): number[] => {
const maxButtons = 5;
@@ -77,12 +75,8 @@ export const Pagination: React.FunctionComponent<IPaginationProps> = ({
setPage(button);
}}
className={`max-h-8 rounded ${page === button
? `px-2 ${getColors('bg-gray-200 text-vulcan-500', 'bg-[var(--vscode-list-activeSelectionBackground)] text-[var(--vscode-list-activeSelectionForeground)]')}`
: getColors(
`text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500`,
`text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-list-activeSelectionForeground)]`
)
}`}
? `px-2 bg-[var(--vscode-list-activeSelectionBackground)] text-[var(--vscode-list-activeSelectionForeground)]`
: `text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-list-activeSelectionForeground)]`}`}
>
{button + 1}
</button>
@@ -1,5 +1,4 @@
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IPaginationButtonProps {
title: string;
@@ -12,18 +11,11 @@ export const PaginationButton: React.FunctionComponent<IPaginationButtonProps> =
disabled,
onClick
}: React.PropsWithChildren<IPaginationButtonProps>) => {
const { getColors } = useThemeColors();
return (
<button
disabled={disabled}
onClick={onClick}
className={`disabled:opacity-50 ${
getColors(
'text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500 disabled:hover:text-gray-500 dark:disabled:hover:text-whisper-900',
'text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-list-activeSelectionForeground)]'
)
}`}
className={`disabled:opacity-50 text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-list-activeSelectionForeground)]`}
>
{title}
</button>
@@ -2,7 +2,6 @@ import * as React from 'react';
import { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import usePagination from '../../hooks/usePagination';
import useThemeColors from '../../hooks/useThemeColors';
import { MediaTotalSelector, PageAtom, SettingsAtom } from '../../state';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -22,8 +21,6 @@ export const PaginationStatus: React.FunctionComponent<IPaginationStatusProps> =
totalPages || 0,
totalMedia
);
const { getColors } = useThemeColors();
const totelItemsOnPage = useMemo(() => {
const items = (page + 1) * pageSetNr;
if (totalItems < items) {
@@ -34,11 +31,7 @@ export const PaginationStatus: React.FunctionComponent<IPaginationStatusProps> =
return (
<div className="hidden sm:flex">
<p className={`text-sm ${getColors(
'text-gray-500 dark:text-whisper-900',
'text-[var(--vscode-tab-inactiveForeground)]'
)
}`}>
<p className={`text-sm text-[var(--vscode-tab-inactiveForeground)]`}>
{
l10n.t(LocalizationKey.dashboardHeaderPaginationStatusText,
(page * pageSetNr + 1),
@@ -4,7 +4,6 @@ import * as React from 'react';
import { useCallback } from 'react';
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil';
import { DashboardMessage } from '../../DashboardMessage';
import useThemeColors from '../../hooks/useThemeColors';
import { NavigationType } from '../../models';
import {
CategoryAtom,
@@ -37,7 +36,7 @@ export const RefreshDashboardData: React.FunctionComponent<IRefreshDashboardData
const selectedFolder = useRecoilValue(SelectedMediaFolderSelector);
const refreshPages = () => {
setLoading(true);
setLoading("initPages");
resetSearch();
resetSorting();
resetFolder();
@@ -47,7 +46,7 @@ export const RefreshDashboardData: React.FunctionComponent<IRefreshDashboardData
};
const refreshMedia = () => {
setLoading(true);
setLoading("initPages");
resetPage();
resetSearch();
Messenger.send(DashboardMessage.refreshMedia, { folder: selectedFolder });
@@ -2,11 +2,11 @@ import { MagnifyingGlassIcon, XCircleIcon } from '@heroicons/react/24/solid';
import * as React from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useDebounce } from '../../../hooks/useDebounce';
import useThemeColors from '../../hooks/useThemeColors';
import { SearchAtom, SearchReadyAtom } from '../../state';
import { RefreshDashboardData } from './RefreshDashboardData';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { TextField } from '../Common/TextField';
export interface ISearchboxProps {
placeholder?: string;
@@ -19,10 +19,9 @@ export const Searchbox: React.FunctionComponent<ISearchboxProps> = ({
const [debounceSearchValue, setDebounceValue] = useRecoilState(SearchAtom);
const searchReady = useRecoilValue(SearchReadyAtom);
const debounceSearch = useDebounce<string>(value, 500);
const { getColors } = useThemeColors();
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
const handleChange = (newValue: string) => {
setValue(newValue);
};
const reset = React.useCallback(() => {
@@ -46,31 +45,18 @@ export const Searchbox: React.FunctionComponent<ISearchboxProps> = ({
<label htmlFor="search" className="sr-only">
{l10n.t(LocalizationKey.commonSearch)}
</label>
<div className="relative flex justify-center">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<MagnifyingGlassIcon className={`h-5 w-5 ${getColors(`text-gray-400`, 'text-[var(--vscode-input-foreground)]')}`} aria-hidden="true" />
</div>
<input
type="text"
name="search"
className={`block w-full py-2 pl-10 pr-3 sm:text-sm appearance-none disabled:opacity-50 rounded ${getColors(
'bg-white dark:bg-vulcan-300 border border-gray-300 dark:border-vulcan-100 text-vulcan-500 dark:text-whisper-500 placeholder-gray-400 dark:placeholder-whisper-800 focus:outline-none',
'bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] border-[var(--vscode-input-border, --vscode-editorWidget-border)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent'
)
}`}
placeholder={placeholder || l10n.t(LocalizationKey.commonSearch)}
value={value}
onChange={handleChange}
disabled={!searchReady}
/>
{value && (
<button onClick={reset} className="absolute inset-y-0 right-0 pr-3 flex items-center">
<XCircleIcon className={`h-5 w-5 ${getColors(`text-gray-400`, 'text-[var(--vscode-input-foreground)]')}`} aria-hidden="true" />
</button>
<TextField
name='search'
icon={(
<MagnifyingGlassIcon className={`h-4 w-4 text-[var(--vscode-input-foreground)]`} aria-hidden="true" />
)}
</div>
value={value}
placeholder={placeholder || l10n.t(LocalizationKey.commonSearch)}
disabled={!searchReady}
onChange={handleChange}
onReset={reset}
/>
</div>
<RefreshDashboardData />
@@ -5,7 +5,6 @@ import * as React from 'react';
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { GeneralCommands } from '../../../constants';
import useThemeColors from '../../hooks/useThemeColors';
import { SettingsSelector } from '../../state';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -17,7 +16,6 @@ export const SyncButton: React.FunctionComponent<ISyncButtonProps> = (
) => {
const settings = useRecoilValue(SettingsSelector);
const [isSyncing, setIsSyncing] = useState(false);
const { getColors } = useThemeColors();
const pull = () => {
Messenger.send(GeneralCommands.toVSCode.gitSync);
@@ -49,11 +47,7 @@ export const SyncButton: React.FunctionComponent<ISyncButtonProps> = (
<div className="git_actions">
<button
type="button"
className={`inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium focus:outline-none rounded ${getColors(
`text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 disabled:bg-gray-500`,
`text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`
)
}`}
className={`inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium focus:outline-none rounded text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`}
onClick={pull}
disabled={isSyncing}
>
@@ -5,7 +5,6 @@ import { Bars4Icon, Squares2X2Icon } from '@heroicons/react/24/solid';
import { Messenger } from '@estruyf/vscode/dist/client';
import { DashboardMessage } from '../../DashboardMessage';
import { DashboardViewType } from '../../models';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -16,7 +15,6 @@ export const ViewSwitch: React.FunctionComponent<IViewSwitchProps> = (
) => {
const [view, setView] = useRecoilState(ViewAtom);
const settings = useRecoilValue(SettingsSelector);
const { getColors } = useThemeColors();
const toggleView = () => {
const newView =
@@ -32,9 +30,9 @@ export const ViewSwitch: React.FunctionComponent<IViewSwitchProps> = (
}, [settings?.pageViewType]);
return (
<div className={`flex rounded-sm lg:mb-1 ${getColors('bg-vulcan-50', 'bg-[var(--vscode-button-secondaryBackground)]')}`}>
<div className={`flex rounded-sm lg:mb-1 bg-[var(--vscode-button-secondaryBackground)]`}>
<button
className={`flex items-center px-2 py-1 rounded-l-sm ${view === DashboardViewType.Grid ? getColors('bg-teal-500 text-vulcan-500', 'bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)]') : 'text-[var(--vscode-button-secondaryForeground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)]'
className={`flex items-center px-2 py-1 rounded-l-sm ${view === DashboardViewType.Grid ? `bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)]` : 'text-[var(--vscode-button-secondaryForeground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)]'
}`}
title={l10n.t(LocalizationKey.dashboardHeaderViewSwitchToGrid)}
type={`button`}
@@ -46,7 +44,7 @@ export const ViewSwitch: React.FunctionComponent<IViewSwitchProps> = (
</span>
</button>
<button
className={`flex items-center px-2 py-1 rounded-r-sm ${view === DashboardViewType.List ? getColors('bg-teal-500 text-vulcan-500', 'bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)]') : 'text-[var(--vscode-button-secondaryForeground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)]'
className={`flex items-center px-2 py-1 rounded-r-sm ${view === DashboardViewType.List ? `bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)]` : 'text-[var(--vscode-button-secondaryForeground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)]'
}`}
title={l10n.t(LocalizationKey.dashboardHeaderViewSwitchToList)}
type={`button`}
@@ -1,5 +1,5 @@
export * from './Filter';
export * from './Folders';
export * from './FoldersFilter';
export * from './Grouping';
export * from './Header';
export * from './Searchbox';
@@ -1,5 +1,4 @@
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface INavigationBarProps {
title?: string;
@@ -11,28 +10,15 @@ export const NavigationBar: React.FunctionComponent<INavigationBarProps> = ({
bottom,
children
}: React.PropsWithChildren<INavigationBarProps>) => {
const { getColors } = useThemeColors();
return (
<aside
className={`w-2/12 px-4 py-6 h-full flex flex-col flex-grow border-r ${getColors(
'border-gray-200 dark:border-vulcan-300',
'border-[var(--frontmatter-border)]'
)}`}
className={`w-2/12 px-4 py-6 h-full flex flex-col flex-grow border-r border-[var(--frontmatter-border)]`}
>
{title && <h2 className={`text-lg ${getColors(
'text-gray-500 dark:text-whisper-900',
'text-[var(--vscode-tab-inactiveForeground)]'
)
}`}>{title}</h2>}
{title && <h2 className={`text-lg text-[var(--vscode-tab-inactiveForeground)]`}>{title}</h2>}
<nav className={`flex-1 py-4 -mx-4 h-full`}>
<div
className={`divide-y border-t border-b ${getColors(
'divide-gray-200 dark:divide-vulcan-300 border-gray-200 dark:border-vulcan-300',
'divide-[var(--frontmatter-border)] border-[var(--frontmatter-border)]'
)
}`}
className={`divide-y border-t border-b divide-[var(--frontmatter-border)] border-[var(--frontmatter-border)]`}
>
{children}
</div>
@@ -1,5 +1,4 @@
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface INavigationItemProps {
isSelected?: boolean;
@@ -11,23 +10,11 @@ export const NavigationItem: React.FunctionComponent<INavigationItemProps> = ({
onClick,
children
}: React.PropsWithChildren<INavigationItemProps>) => {
const { getColors } = useThemeColors();
return (
<button
type="button"
className={`navigationitem px-4 py-2 flex items-center text-sm font-medium w-full text-left cursor-pointer ${getColors(
'hover:bg-gray-200 dark:hover:bg-vulcan-400 hover:text-vulcan-500 dark:hover:text-whisper-500',
'hover:bg-[var(--frontmatter-list-hover-background)] hover:text-[var(--frontmatter-list-selected-text)]'
)
} ${isSelected
? getColors(
'bg-gray-300 dark:bg-vulcan-300 text-vulcan-500 dark:text-whisper-500',
'bg-[var(--frontmatter-list-selected-background)] text-[var(--frontmatter-list-selected-text)]'
) : getColors(
'text-gray-500 dark:text-whisper-900',
'text-[var(--frontmatter-list-text)]'
)
className={`navigationitem px-4 py-2 flex items-center text-sm font-medium w-full text-left cursor-pointer hover:bg-[var(--frontmatter-list-hover-background)] hover:text-[var(--frontmatter-list-selected-text)] ${isSelected
? `bg-[var(--frontmatter-list-selected-background)] text-[var(--frontmatter-list-selected-text)]` : `text-[var(--frontmatter-list-text)]`
}`}
onClick={onClick}
>
@@ -26,7 +26,7 @@ export const PageLayout: React.FunctionComponent<IPageLayoutProps> = ({
<div
className={
contentClass ||
'w-full flex justify-between flex-col flex-grow mx-auto pt-6 px-4 max-w-full xl:max-w-[90%]'
'w-full flex justify-between flex-col flex-grow mx-auto pt-6 px-4 max-w-full'
}
>
{children}
@@ -2,7 +2,6 @@ import { HeartIcon, StarIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import { REVIEW_LINK, SPONSOR_LINK } from '../../../constants';
import { VersionInfo } from '../../../models';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -18,15 +17,9 @@ interface ISponsorLinkProps {
}
const SponsorLink: React.FunctionComponent<ISponsorLinkProps> = ({ title, href, children }: React.PropsWithChildren<ISponsorLinkProps>) => {
const { getColors } = useThemeColors();
return (
<a
className={`group inline-flex justify-center items-center space-x-2 opacity-50 hover:opacity-100 ${getColors(
`text-vulcan-500 dark:text-whisper-500 hover:text-vulcan-600 dark:hover:text-whisper-300`,
`text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-textLink-foreground)]]`
)
}`}
className={`group inline-flex justify-center items-center space-x-2 opacity-50 hover:opacity-100 text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-textLink-foreground)]]`}
href={href}
title={title}
>
@@ -40,16 +33,10 @@ export const SponsorMsg: React.FunctionComponent<ISponsorMsgProps> = ({
isBacker,
version
}: React.PropsWithChildren<ISponsorMsgProps>) => {
const { getColors } = useThemeColors();
return (
<footer
className={`w-full px-4 py-2 text-center space-x-8 flex items-center border-t ${isBacker ? 'justify-center' : 'justify-between'
} ${getColors(
'bg-gray-100 dark:bg-vulcan-500 text-vulcan-50 dark:text-whisper-900 border-gray-200 dark:border-vulcan-300',
'bg-[var(--vscode-editor-background)] text-[var(--vscode-editor-foreground)] border-[var(--frontmatter-border)]'
)
}`}
} bg-[var(--vscode-editor-background)] text-[var(--vscode-editor-foreground)] border-[var(--frontmatter-border)]`}
>
{isBacker ? (
<span>
@@ -1,37 +1,28 @@
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import { TextField } from '../Common/TextField';
export interface IDetailsInputProps {
name: string;
value: string;
onChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
onChange: (value: string) => void;
isTextArea?: boolean;
}
export const DetailsInput: React.FunctionComponent<IDetailsInputProps> = ({ value, isTextArea, onChange }: React.PropsWithChildren<IDetailsInputProps>) => {
const { getColors } = useThemeColors();
export const DetailsInput: React.FunctionComponent<IDetailsInputProps> = ({ name, value, isTextArea, onChange }: React.PropsWithChildren<IDetailsInputProps>) => {
if (isTextArea) {
return (
<textarea
rows={3}
className={`py-1 px-2 sm:text-sm border w-full ${getColors(
'bg-white dark:bg-vulcan-300 border-gray-300 dark:border-vulcan-100 text-vulcan-500 dark:text-whisper-500 placeholder-gray-400 dark:placeholder-whisper-800 focus:outline-none',
'bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] border-[var(--vscode-input-border)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent'
)
}`}
<TextField
name={name}
value={value}
onChange={onChange}
multiline
/>
);
}
return (
<input
className={`py-1 px-2 sm:text-sm border w-full ${getColors(
'bg-white dark:bg-vulcan-300 border-gray-300 dark:border-vulcan-100 text-vulcan-500 dark:text-whisper-500 placeholder-gray-400 dark:placeholder-whisper-800 focus:outline-none',
'bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] border-[var(--vscode-input-border)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent'
)
}`}
<TextField
name={name}
value={value}
onChange={onChange}
/>
@@ -1,5 +1,4 @@
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IDetailsItemProps {
title: string;
@@ -7,13 +6,11 @@ export interface IDetailsItemProps {
}
export const DetailsItem: React.FunctionComponent<IDetailsItemProps> = ({ title, details }: React.PropsWithChildren<IDetailsItemProps>) => {
const { getColors } = useThemeColors();
return (
<>
<div className="py-3 flex justify-between text-sm font-medium">
<dt className={getColors('text-vulcan-100 dark:text-whisper-900', 'text-[var(--vscode-editor-foreground)]')}>{title}</dt>
<dd className={`text-right ${getColors('text-vulcan-300 dark:text-whisper-500', 'text-[var(--vscode-foreground)]')}`}>
<dt className={`text-[var(--vscode-editor-foreground)]`}>{title}</dt>
<dd className={`text-right text-[var(--vscode-foreground)]`}>
{details}
</dd>
</div>
@@ -206,7 +206,7 @@ export const DetailsSlideOver: React.FunctionComponent<IDetailsSlideOverProps> =
{l10n.t(LocalizationKey.dashboardMediaMetadataPanelFieldFileName)}
</label>
<div className="relative mt-1">
<DetailsInput value={name || ""} onChange={(e) => setFilename(`${e.target.value}.${extension}`)} />
<DetailsInput name={`filename`} value={name || ""} onChange={(e) => setFilename(`${e}.${extension}`)} />
<div className="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<span className={`sm:text-sm placeholder-[var(--vscode-input-placeholderForeground)]`}>.{extension}</span>
@@ -219,7 +219,7 @@ export const DetailsSlideOver: React.FunctionComponent<IDetailsSlideOverProps> =
{l10n.t(LocalizationKey.dashboardMediaCommonTitle)}
</label>
<div className="mt-1">
<DetailsInput value={title || ""} onChange={(e) => setTitle(e.target.value)} />
<DetailsInput name={`title`} value={title || ""} onChange={(e) => setTitle(e)} />
</div>
</div>
@@ -229,7 +229,7 @@ export const DetailsSlideOver: React.FunctionComponent<IDetailsSlideOverProps> =
{l10n.t(LocalizationKey.dashboardMediaCommonCaption)}
</label>
<div className="mt-1">
<DetailsInput value={caption || ""} onChange={(e) => setCaption(e.target.value)} isTextArea />
<DetailsInput name={`caption`} value={caption || ""} onChange={(e) => setCaption(e)} isTextArea />
</div>
</div>
)}
@@ -239,7 +239,7 @@ export const DetailsSlideOver: React.FunctionComponent<IDetailsSlideOverProps> =
{l10n.t(LocalizationKey.dashboardMediaCommonAlt)}
</label>
<div className="mt-1">
<DetailsInput value={alt || ""} onChange={(e) => setAlt(e.target.value)} isTextArea />
<DetailsInput name={`alt`} value={alt || ""} onChange={(e) => setAlt(e)} isTextArea />
</div>
</div>
)}
@@ -16,7 +16,6 @@ import { STATIC_FOLDER_PLACEHOLDER } from '../../../constants';
import { useCallback, useMemo } from 'react';
import { extname } from 'path';
import { parseWinPath } from '../../../helpers/parseWinPath';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -30,7 +29,6 @@ export const FolderCreation: React.FunctionComponent<IFolderCreationProps> = (
const allStaticFolders = useRecoilValue(AllStaticFoldersAtom);
const allContentFolders = useRecoilValue(AllContentFoldersAtom);
const viewData = useRecoilValue(ViewDataSelector);
const { getColors } = useThemeColors();
const hexoAssetFolderPath = useMemo(() => {
const path = viewData?.data?.filePath?.replace(extname(viewData.data.filePath), '');
@@ -78,11 +76,7 @@ export const FolderCreation: React.FunctionComponent<IFolderCreationProps> = (
if (isHexoPostAssetsEnabled) {
return (
<button
className={`mr-2 inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium focus:outline-none ${getColors(
`text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 disabled:bg-gray-500`,
`text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`
)
}`}
className={`mr-2 inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium focus:outline-none text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`}
title={l10n.t(LocalizationKey.dashboardMediaFolderCreationHexoCreate)}
onClick={onAssetFolderCreation}
>
@@ -116,11 +110,7 @@ export const FolderCreation: React.FunctionComponent<IFolderCreationProps> = (
<div className="flex flex-1 justify-end">
{renderPostAssetsButton}
<button
className={`inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium focus:outline-none rounded ${getColors(
`text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 disabled:bg-gray-500`,
`text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`
)
}`}
className={`inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium focus:outline-none rounded text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`}
title={l10n.t(LocalizationKey.dashboardMediaFolderCreationFolderCreate)}
onClick={onFolderCreation}
>
@@ -2,7 +2,6 @@ import { FolderIcon } from '@heroicons/react/24/solid';
import { basename, join } from 'path';
import * as React from 'react';
import { useRecoilState } from 'recoil';
import useThemeColors from '../../hooks/useThemeColors';
import { SelectedMediaFolderAtom } from '../../state';
export interface IFolderItemProps {
@@ -17,7 +16,6 @@ export const FolderItem: React.FunctionComponent<IFolderItemProps> = ({
staticFolder
}: React.PropsWithChildren<IFolderItemProps>) => {
const [, setSelectedFolder] = useRecoilState(SelectedMediaFolderAtom);
const { getColors } = useThemeColors();
const relFolderPath = wsFolder ? folder.replace(wsFolder, '') : folder;
@@ -28,25 +26,17 @@ export const FolderItem: React.FunctionComponent<IFolderItemProps> = ({
return (
<li
className={`group relative p-4 ${getColors(
'hover:bg-gray-200 dark:hover:bg-vulcan-100 text-gray-600 hover:text-gray-700 dark:text-whisper-900 dark:hover:text-whisper-800',
'hover:bg-[var(--vscode-list-hoverBackground)] text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-list-activeSelectionForeground)]'
)
}`}
className={`group relative hover:bg-[var(--vscode-list-hoverBackground)] text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-list-activeSelectionForeground)]`}
>
<button
title={isContentFolder ? 'Content directory folder' : 'Public directory folder'}
className={`w-full flex flex-row items-center h-full`}
className={`p-4 w-full flex flex-row items-center h-full`}
onClick={() => setSelectedFolder(folder)}
>
<div className="relative mr-4">
<FolderIcon className={`h-12 w-12`} />
{isContentFolder && (
<span className={`font-extrabold absolute bottom-3 left-1/2 transform -translate-x-1/2 ${getColors(
`text-whisper-800 dark:text-vulcan-500`,
`text-[var(--vscode-foreground)]`
)
}`}>
<span className={`font-extrabold absolute bottom-3 left-1/2 transform -translate-x-1/2 text-[var(--vscode-foreground)]`}>
C
</span>
)}
+11 -21
View File
@@ -37,7 +37,6 @@ import { InfoDialog } from '../Modals/InfoDialog';
import { DetailsSlideOver } from './DetailsSlideOver';
import { usePopper } from 'react-popper';
import { MediaSnippetForm } from './MediaSnippetForm';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -62,7 +61,6 @@ export const Item: React.FunctionComponent<IItemProps> = ({
const settings = useRecoilValue(SettingsSelector);
const selectedFolder = useRecoilValue(SelectedMediaFolderSelector);
const viewData = useRecoilValue(ViewDataSelector);
const { getColors } = useThemeColors();
const hasViewData = useMemo(() => {
return viewData?.data?.filePath !== undefined;
@@ -483,11 +481,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
</button>
<div className={`relative py-4 pl-4 pr-12`}>
<div className={`group/actions absolute top-4 right-4 flex flex-col space-y-4`}>
<div className={`flex items-center border border-transparent rounded-full p-2 -mr-2 -mt-2 ${getColors(
`group-hover/actions:bg-gray-200 dark:group-hover/actions:bg-vulcan-200 group-hover/actions:border-gray-100 dark:group-hover/actions:border-vulcan-50`,
`group-hover/actions:bg-[var(--vscode-sideBar-background)] group-hover/actions:border-[var(--frontmatter-border)]`
)
}`}>
<div className={`flex items-center border border-transparent rounded-full p-2 -mr-2 -mt-2 group-hover/actions:bg-[var(--vscode-sideBar-background)] group-hover/actions:border-[var(--frontmatter-border)]`}>
<Menu as="div" className="relative z-10 flex text-left">
<div className="hidden group-hover/actions:flex">
<QuickAction title="View media details" onClick={viewMediaDetails}>
@@ -626,39 +620,39 @@ export const Item: React.FunctionComponent<IItemProps> = ({
</Menu>
</div>
</div>
<p className={`text-sm font-bold pointer-events-none flex items-center break-all ${getColors(`dark:text-whisper-900`, `text-[var(--vscode-foreground)]`)}`}>
<p className={`text-sm font-bold pointer-events-none flex items-center break-all text-[var(--vscode-foreground)]}`}>
{basename(parseWinPath(media.fsPath) || '')}
</p>
{!isImageFile && media.title && (
<p className={`mt-2 text-xs font-medium pointer-events-none flex flex-col items-start ${getColors(`dark:text-whisper-900`, ``)}`}>
<p className={`mt-2 text-xs font-medium pointer-events-none flex flex-col items-start`}>
<b className={`mr-2`}>
{l10n.t(LocalizationKey.dashboardMediaCommonTitle)}:
</b>
<span className={`block mt-1 text-xs ${getColors(`dark:text-whisper-500`, `text-[var(--vscode-foreground)]`)}`}>{media.title}</span>
<span className={`block mt-1 text-xs text-[var(--vscode-foreground)]`}>{media.title}</span>
</p>
)}
{media.caption && (
<p className={`mt-2 text-xs font-medium pointer-events-none flex flex-col items-start ${getColors(`dark:text-whisper-900`, ``)}`}>
<p className={`mt-2 text-xs font-medium pointer-events-none flex flex-col items-start`}>
<b className={`mr-2`}>
{l10n.t(LocalizationKey.dashboardMediaCommonCaption)}:
</b>
<span className={`block mt-1 text-xs ${getColors(`dark:text-whisper-500`, `text-[var(--vscode-foreground)]`)}`}>{media.caption}</span>
<span className={`block mt-1 text-xs text-[var(--vscode-foreground)]`}>{media.caption}</span>
</p>
)}
{!media.caption && media.alt && (
<p className={`mt-2 text-xs font-medium pointer-events-none flex flex-col items-start ${getColors(`dark:text-whisper-900`, ``)}`}>
<p className={`mt-2 text-xs font-medium pointer-events-none flex flex-col items-start`}>
<b className={`mr-2`}>
{l10n.t(LocalizationKey.dashboardMediaCommonAlt)}:
</b>
<span className={`block mt-1 text-xs ${getColors(`dark:text-whisper-500`, `text-[var(--vscode-foreground)]`)}`}>{media.alt}</span>
<span className={`block mt-1 text-xs text-[var(--vscode-foreground)]`}>{media.alt}</span>
</p>
)}
{(media?.size || media?.dimensions) && (
<p className={`mt-2 text-xs font-medium pointer-events-none flex flex-col items-start ${getColors(`dark:text-whisper-900`, ``)}`}>
<p className={`mt-2 text-xs font-medium pointer-events-none flex flex-col items-start`}>
<b className={`mr-1`}>
{l10n.t(LocalizationKey.dashboardMediaCommonSize)}:
</b>
<span className={`block mt-1 text-xs ${getColors(`dark:text-whisper-500`, `text-[var(--vscode-foreground)]`)}`}>
<span className={`block mt-1 text-xs text-[var(--vscode-foreground)]`}>
{getMediaDetails()}
</span>
</p>
@@ -677,11 +671,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
{mediaSnippets.map((snippet, idx) => (
<li key={idx} className="inline-flex items-center pb-2 mr-2">
<button
className={`w-full inline-flex justify-center border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm disabled:opacity-30 ${getColors(
`bg-teal-600 text-white hover:bg-teal-700 dark:hover:bg-teal-900`,
`bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)] hover:bg-[var(--vscode-button-hoverBackground)]`
)
}`}
className={`w-full inline-flex justify-center border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:w-auto sm:text-sm disabled:opacity-30 bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)] hover:bg-[var(--vscode-button-hoverBackground)]`}
onClick={() => processSnippet(snippet)}
>
{snippet.title}
@@ -1,7 +1,6 @@
import { basename } from 'path';
import * as React from 'react';
import { useRecoilState } from 'recoil';
import useThemeColors from '../../hooks/useThemeColors';
import { LightboxAtom } from '../../state';
export interface ILightboxProps { }
@@ -10,7 +9,6 @@ export const Lightbox: React.FunctionComponent<ILightboxProps> = (
_: React.PropsWithChildren<ILightboxProps>
) => {
const [lightbox, setLightbox] = useRecoilState(LightboxAtom);
const { getColors } = useThemeColors();
if (!lightbox) {
return null;
@@ -23,11 +21,7 @@ export const Lightbox: React.FunctionComponent<ILightboxProps> = (
return (
<div
onClick={hideLightbox}
className={`fixed top-0 left-0 right-0 bottom-0 w-full h-full flex flex-wrap items-center justify-center z-50 ${getColors(
`bg-black bg-opacity-50`,
`bg-[var(--frontmatter-lightbox-background)]`
)
}`}
className={`fixed top-0 left-0 right-0 bottom-0 w-full h-full flex flex-wrap items-center justify-center z-50 bg-[var(--frontmatter-lightbox-background)]`}
>
<div className={`w-full h-full flex flex-wrap items-center justify-center`}>
<img
@@ -13,7 +13,7 @@ export const List: React.FunctionComponent<IListProps> = ({
return (
<ul
role="list"
className={`grid gap-4 ${gapClass} grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5`}
className={`grid gap-4 ${gapClass} grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 2xl:grid-cols-5`}
>
{children}
</ul>
@@ -25,10 +25,8 @@ import { PageLayout } from '../Layout/PageLayout';
import { parseWinPath } from '../../../helpers/parseWinPath';
import { basename, extname, join } from 'path';
import { MediaInfo } from '../../../models';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { NavigationType } from '../../models';
export interface IMediaProps { }
@@ -41,7 +39,6 @@ export const Media: React.FunctionComponent<IMediaProps> = (
const selectedFolder = useRecoilValue(SelectedMediaFolderAtom);
const folders = useRecoilValue(MediaFoldersAtom);
const loading = useRecoilValue(LoadingAtom);
const { getColors } = useThemeColors();
const currentStaticFolder = useMemo(() => {
if (settings?.staticFolder) {
@@ -177,11 +174,7 @@ export const Media: React.FunctionComponent<IMediaProps> = (
)}
{isDragActive && (
<div className={`absolute top-0 left-0 w-full h-full flex flex-col justify-center items-center z-50 ${getColors(
'text-whisper-500 bg-gray-900 bg-opacity-70',
'text-[var(--vscode-foreground)] bg-[var(--vscode-editor-background)] opacity-75'
)
}`}>
<div className={`absolute top-0 left-0 w-full h-full flex flex-col justify-center items-center z-50 text-[var(--vscode-foreground)] bg-[var(--vscode-editor-background)] opacity-75`}>
<ArrowUpTrayIcon className={`h-32`} />
<p className={`text-xl max-w-md text-center`}>
{selectedFolder
@@ -195,8 +188,7 @@ export const Media: React.FunctionComponent<IMediaProps> = (
<div className={`flex items-center justify-center h-full`}>
<div className={`max-w-xl text-center`}>
<FrontMatterIcon
className={`h-32 mx-auto opacity-90 mb-8 ${getColors('text-vulcan-300 dark:text-whisper-800', 'text-[var(--vscode-editor-foreground)]')
}`}
className={`h-32 mx-auto opacity-90 mb-8 text-[var(--vscode-editor-foreground)]`}
/>
<p className={`text-xl font-medium`}>
@@ -1,6 +1,5 @@
import * as React from 'react';
import { useRecoilValue } from 'recoil';
import useThemeColors from '../../hooks/useThemeColors';
import { NavigationType } from '../../models/NavigationType';
import { SettingsAtom } from '../../state';
import { Sorting } from '../Header';
@@ -13,7 +12,6 @@ export const MediaHeaderBottom: React.FunctionComponent<IMediaHeaderBottomProps>
_: React.PropsWithChildren<IMediaHeaderBottomProps>
) => {
const settings = useRecoilValue(SettingsAtom);
const { getColors } = useThemeColors();
if (!settings?.wsFolder) {
return null;
@@ -21,11 +19,7 @@ export const MediaHeaderBottom: React.FunctionComponent<IMediaHeaderBottomProps>
return (
<nav
className={`w-full flex justify-between py-2 border-b ${getColors(
'bg-gray-200 text-vulcan-300 dark:bg-vulcan-400 dark:text-whisper-600 border-gray-300 dark:border-vulcan-100',
'bg-[var(--vscode-sideBar-background)] text-[var(--vscode-sideBar-foreground)] border-[var(--frontmatter-border)]'
)
}`}
className={`w-full flex justify-between py-2 border-b bg-[var(--vscode-sideBar-background)] text-[var(--vscode-sideBar-foreground)] border-[var(--frontmatter-border)]`}
aria-label="Breadcrumb"
>
<Breadcrumb />
@@ -6,7 +6,6 @@ import { useDebounce } from '../../../hooks/useDebounce';
import { usePrevious } from '../../../panelWebView/hooks/usePrevious';
import { DashboardCommand } from '../../DashboardCommand';
import { DashboardMessage } from '../../DashboardMessage';
import useThemeColors from '../../hooks/useThemeColors';
import {
LoadingAtom,
PageAtom,
@@ -33,11 +32,10 @@ export const MediaHeaderTop: React.FunctionComponent<
const settings = useRecoilValue(SettingsSelector);
const debounceGetMedia = useDebounce<string | null>(lastUpdated, 200);
const prevSelectedFolder = usePrevious<string | null>(selectedFolder);
const { getColors } = useThemeColors();
const mediaUpdate = (message: MessageEvent<EventData<{ key: string; value: any }>>) => {
if (message.data.command === DashboardCommand.mediaUpdate) {
setLoading(true);
setLoading("loading");
Messenger.send(DashboardMessage.getMedia, {
page,
folder: selectedFolder || '',
@@ -51,7 +49,7 @@ export const MediaHeaderTop: React.FunctionComponent<
prevSelectedFolder !== null ||
settings?.dashboardState?.media.selectedFolder !== selectedFolder
) {
setLoading(true);
setLoading("loading");
setPage(0);
setLastUpdated(new Date().getTime().toString());
}
@@ -63,7 +61,7 @@ export const MediaHeaderTop: React.FunctionComponent<
React.useEffect(() => {
if (debounceGetMedia) {
setLoading(true);
setLoading("loading");
Messenger.send(DashboardMessage.getMedia, {
page,
@@ -83,11 +81,7 @@ export const MediaHeaderTop: React.FunctionComponent<
return (
<nav
className={`py-3 px-4 flex items-center justify-between border-b ${getColors(
'border-gray-300 dark:border-vulcan-100',
'border-[var(--frontmatter-border)]'
)
}`}
className={`py-3 px-4 flex items-center justify-between border-b border-[var(--frontmatter-border)]`}
aria-label="Pagination"
>
<Searchbox placeholder={l10n.t(LocalizationKey.dashboardMediaMediaHeaderTopSearchboxPlaceholder)} />
@@ -1,7 +1,6 @@
import { Menu } from '@headlessui/react';
import { EllipsisVerticalIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IActionMenuButtonProps {
title: string;
@@ -14,18 +13,12 @@ export const ActionMenuButton: React.FunctionComponent<IActionMenuButtonProps> =
disabled,
ref
}: React.PropsWithChildren<IActionMenuButtonProps>) => {
const { getColors } = useThemeColors();
return (
<Menu.Button
ref={ref || null}
onClick={(e: React.MouseEvent<HTMLButtonElement>) => e.stopPropagation()}
disabled={disabled}
className={`group inline-flex justify-center text-sm font-medium ${getColors(
'text-vulcan-400 hover:text-vulcan-600 dark:text-gray-400 dark:hover:text-whisper-600',
'text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)]'
)
} ${disabled ? 'opacity-50' : ''
className={`group inline-flex justify-center text-sm font-medium text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)] ${disabled ? 'opacity-50' : ''
}`}
>
<span className="sr-only">{title}</span>
@@ -1,7 +1,6 @@
import { Menu } from '@headlessui/react';
import { ChevronDownIcon } from '@heroicons/react/24/solid';
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IMenuButtonProps {
label: string | JSX.Element;
@@ -14,11 +13,9 @@ export const MenuButton: React.FunctionComponent<IMenuButtonProps> = ({
title,
disabled
}: React.PropsWithChildren<IMenuButtonProps>) => {
const { getColors } = useThemeColors();
return (
<div className={`group flex items-center ${disabled ? 'opacity-50' : ''}`}>
<div className={`mr-2 font-medium flex items-center ${getColors('text-gray-500 dark:text-whisper-700', 'text-[var(--vscode-tab-inactiveForeground)]')}`}>{label}:</div>
<div className={`mr-2 font-medium flex items-center text-[var(--vscode-tab-inactiveForeground)]`}>{label}:</div>
<Menu.Button
disabled={disabled}
@@ -1,6 +1,5 @@
import { Menu } from '@headlessui/react';
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IMenuItemProps {
title: JSX.Element | string;
@@ -17,21 +16,13 @@ export const MenuItem: React.FunctionComponent<IMenuItemProps> = ({
disabled,
onClick
}: React.PropsWithChildren<IMenuItemProps>) => {
const { getColors } = useThemeColors();
return (
<Menu.Item>
<button
disabled={disabled}
onClick={(e) => onClick(value, e)}
className={`${
!isCurrent ? `font-normal` : `font-bold`
} block px-4 py-2 text-sm w-full text-left disabled:opacity-50 ${
getColors(
'text-gray-500 dark:text-whisper-900 hover:bg-gray-100 hover:text-gray-700 dark:hover:text-whisper-600 dark:hover:bg-vulcan-100',
'text-[var(--vscode-editor-foreground)] hover:bg-[var(--vscode-list-hoverBackground)] '
)
}`}
className={`${!isCurrent ? `font-normal` : `font-bold`
} block px-4 py-2 text-sm w-full text-left disabled:opacity-50 text-[var(--vscode-editor-foreground)] hover:bg-[var(--vscode-list-hoverBackground)]`}
>
{title}
</button>
@@ -1,7 +1,6 @@
import { Menu, Transition } from '@headlessui/react';
import * as React from 'react';
import { Fragment } from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IMenuItemsProps {
widthClass?: string;
@@ -17,8 +16,6 @@ export const MenuItems: React.FunctionComponent<IMenuItemsProps> = ({
updatePopper,
disablePopper
}: React.PropsWithChildren<IMenuItemsProps>) => {
const { getColors } = useThemeColors();
return (
<Transition
as={Fragment}
@@ -32,11 +29,7 @@ export const MenuItems: React.FunctionComponent<IMenuItemsProps> = ({
>
<Menu.Items
className={`${widthClass || ''} ${marginTopClass || 'mt-2'} ${disablePopper ? 'origin-top-right absolute right-0 z-20' : ''
} rounded shadow-2xl ring-1 ring-opacity-5 focus:outline-none text-sm max-h-96 overflow-auto ${getColors(
'bg-white dark:bg-vulcan-500 ring-vulcan-400 dark:ring-white',
'bg-[var(--vscode-sideBar-background)] ring-[var(--frontmatter-border)]'
)
}`}
} rounded shadow-2xl ring-1 ring-opacity-5 focus:outline-none text-sm max-h-96 overflow-auto bg-[var(--vscode-sideBar-background)] ring-[var(--frontmatter-border)]`}
>
<div className="py-1">{children}</div>
</Menu.Items>
@@ -1,5 +1,4 @@
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IQuickActionProps {
title: string;
@@ -11,18 +10,12 @@ export const QuickAction: React.FunctionComponent<IQuickActionProps> = ({
onClick,
children
}: React.PropsWithChildren<IQuickActionProps>) => {
const { getColors } = useThemeColors();
return (
<button
type="button"
title={title}
onClick={onClick}
className={`px-2 group inline-flex justify-center text-sm font-medium ${getColors(
'text-vulcan-400 hover:text-vulcan-600 dark:text-gray-400 dark:hover:text-whisper-600',
'text-[var(--vscode-foreground)] hover:text-[var(--frontmatter-button-hoverBackground)]'
)
}`}
className={`px-2 group inline-flex justify-center text-sm font-medium text-[var(--vscode-foreground)] hover:text-[var(--frontmatter-button-hoverBackground)]`}
>
{children}
<span className="sr-only">{title}</span>
@@ -2,7 +2,6 @@ import { Dialog, Transition } from '@headlessui/react';
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import { Fragment, useRef } from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IAlertProps {
title: string;
@@ -23,7 +22,6 @@ export const Alert: React.FunctionComponent<IAlertProps> = ({
trigger
}: React.PropsWithChildren<IAlertProps>) => {
const cancelButtonRef = useRef(null);
const { getColors } = useThemeColors();
return (
<Transition.Root show={true} as={Fragment}>
@@ -42,11 +40,7 @@ export const Alert: React.FunctionComponent<IAlertProps> = ({
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className={`fixed inset-0 transition-opacity ${getColors(
`bg-vulcan-500 bg-opacity-75`,
`bg-[var(--vscode-editor-background)] opacity-75`
)
}`} />
<Dialog.Overlay className={`fixed inset-0 transition-opacity bg-[var(--vscode-editor-background)] opacity-75`} />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
@@ -63,54 +57,37 @@ export const Alert: React.FunctionComponent<IAlertProps> = ({
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div className={`inline-block align-bottom rounded px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6 border-2 ${getColors(
'bg-white dark:bg-vulcan-500 border-whisper-900',
'bg-[var(--vscode-editor-background)] border-[var(--frontmatter-border)]'
)
}`}>
<div className={`inline-block align-bottom rounded px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6 border-2 bg-[var(--vscode-editor-background)] border-[var(--frontmatter-border)]`}>
<div className="sm:flex sm:items-start">
<div className={`mt-3 mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full sm:mx-0 sm:h-10 sm:w-10 ${getColors(
'bg-gray-50 dark:bg-vulcan-400',
'bg-[var(--vscode-sidebar-background)]'
)
}`}>
<div className={`mt-3 mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full sm:mx-0 sm:h-10 sm:w-10 bg-[var(--vscode-sidebar-background)]`}>
<ExclamationTriangleIcon
className={`h-6 w-6 ${getColors(`text-red-500 dark:text-red-50`, `text-[var(--vscode-errorForeground)]`)}`}
className={`h-6 w-6 text-[var(--vscode-errorForeground)]`}
aria-hidden="true"
/>
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<Dialog.Title
as="h3"
className={`text-lg leading-6 font-medium ${getColors(`text-vulcan-300 dark:text-whisper-900`, `text-[var(--vscode-editor-foreground)]`)
}`}
className={`text-lg leading-6 font-medium text-[var(--vscode-editor-foreground)]`}
>
{title}
</Dialog.Title>
<div className="mt-2">
<p className={`text-sm ${getColors(`text-vulcan-500 dark:text-whisper-500`, `text-[var(--vscode-editor-foreground)]`)}`}>{description}</p>
<p className={`text-sm text-[var(--vscode-editor-foreground)]`}>{description}</p>
</div>
</div>
</div>
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<button
type="button"
className={`w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 sm:ml-3 sm:w-auto sm:text-sm ${getColors(
'text-white bg-red-600 hover:bg-red-700 dark:hover:bg-red-900 focus:ring-red-500',
'text-[var(--vscode-statusBarItem-errorForeground)] bg-[var(--vscode-statusBarItem-errorBackground)]'
)
}`}
className={`w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 text-base font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 sm:ml-3 sm:w-auto sm:text-sm text-[var(--vscode-statusBarItem-errorForeground)] bg-[var(--vscode-statusBarItem-errorBackground)]`}
onClick={() => trigger()}
>
{okBtnText}
</button>
<button
type="button"
className={`mt-3 w-full inline-flex justify-center rounded-md border shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:mt-0 sm:w-auto sm:text-sm ${getColors(
'bg-white border-gray-300 text-gray-700 hover:bg-gray-50 dark:hover:bg-gray-200',
'bg-[var(--vscode-button-secondaryBackground)] border-[var(--frontmatter-border)] text-[var(--vscode-button-secondaryForeground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)]'
)
}`}
className={`mt-3 w-full inline-flex justify-center rounded-md border shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:mt-0 sm:w-auto sm:text-sm bg-[var(--vscode-button-secondaryBackground)] border-[var(--frontmatter-border)] text-[var(--vscode-button-secondaryForeground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)]`}
onClick={() => dismiss()}
ref={cancelButtonRef}
>
@@ -1,7 +1,6 @@
import { Dialog, Transition } from '@headlessui/react';
import * as React from 'react';
import { Fragment, useRef } from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IFormDialogProps {
title: string;
@@ -25,7 +24,6 @@ export const FormDialog: React.FunctionComponent<IFormDialogProps> = ({
children
}: React.PropsWithChildren<IFormDialogProps>) => {
const cancelButtonRef = useRef(null);
const { getColors } = useThemeColors();
return (
<Transition.Root show={true} as={Fragment}>
@@ -44,11 +42,7 @@ export const FormDialog: React.FunctionComponent<IFormDialogProps> = ({
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className={`fixed inset-0 transition-opacity ${getColors(
`bg-vulcan-500 bg-opacity-75`,
`bg-[var(--vscode-editor-background)] opacity-75`
)
}`} />
<Dialog.Overlay className={`fixed inset-0 transition-opacity bg-[var(--vscode-editor-background)] opacity-75`} />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
@@ -65,16 +59,11 @@ export const FormDialog: React.FunctionComponent<IFormDialogProps> = ({
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div className={`inline-block align-bottom rounded-lg px-4 pt-5 pb-4 text-left overflow-auto shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6 border-2 ${getColors(
'bg-white dark:bg-vulcan-500 border-whisper-900',
'bg-[var(--vscode-sideBar-background)] border-[var(--frontmatter-border)]'
)
}`}>
<div className={`inline-block align-bottom rounded-lg px-4 pt-5 pb-4 text-left overflow-auto shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6 border-2 bg-[var(--vscode-sideBar-background)] border-[var(--frontmatter-border)]`}>
<div>
<Dialog.Title
as="h3"
className={`text-lg leading-6 font-medium ${getColors(`text-vulcan-300 dark:text-whisper-900`, `text-[var(--vscode-editor-foreground)]`)
}`}
className={`text-lg leading-6 font-medium text-[var(--vscode-editor-foreground)]`}
>
{title}
</Dialog.Title>
@@ -88,11 +77,7 @@ export const FormDialog: React.FunctionComponent<IFormDialogProps> = ({
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
<button
type="button"
className={`w-full inline-flex justify-center rounded shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:mt-0 sm:w-auto sm:text-sm sm:ml-3 ${getColors(
'bg-teal-600 focus:ring-teal-500 text-white hover:bg-teal-700 dark:hover:bg-teal-900 ',
'bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)] hover:bg-[var(--vscode-button-hoverBackground)]'
)
}`}
className={`w-full inline-flex justify-center rounded shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:mt-0 sm:w-auto sm:text-sm sm:ml-3 bg-[var(--frontmatter-button-background)] text-[var(--vscode-button-foreground)] hover:bg-[var(--vscode-button-hoverBackground)]`}
onClick={() => trigger()}
disabled={isSaveDisabled}
>
@@ -101,11 +86,7 @@ export const FormDialog: React.FunctionComponent<IFormDialogProps> = ({
<button
type="button"
className={`mt-3 w-full inline-flex justify-center rounded shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:mt-0 sm:w-auto sm:text-sm ${getColors(
'bg-white border-gray-300 text-gray-700 hover:bg-gray-50 dark:hover:bg-gray-200',
'bg-[var(--vscode-button-secondaryBackground)] text-[var(--vscode-button-secondaryForeground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)]'
)
}`}
className={`mt-3 w-full inline-flex justify-center rounded shadow-sm px-4 py-2 text-base font-medium focus:outline-none sm:mt-0 sm:w-auto sm:text-sm bg-[var(--vscode-button-secondaryBackground)] text-[var(--vscode-button-secondaryForeground)] hover:bg-[var(--vscode-button-secondaryHoverBackground)]`}
onClick={() => dismiss()}
ref={cancelButtonRef}
>
@@ -3,7 +3,6 @@ import { ArrowRightIcon, ArrowTopRightOnSquareIcon, ArrowPathIcon } from '@heroi
import * as React from 'react';
import { useEffect, useRef, useState } from 'react';
import { GeneralCommands, PreviewCommands } from '../../../constants';
import useThemeColors from '../../hooks/useThemeColors';
import { EventData } from '@estruyf/vscode/dist/models';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -17,7 +16,6 @@ export const Preview: React.FunctionComponent<IPreviewProps> = ({
}: React.PropsWithChildren<IPreviewProps>) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
const [crntUrl, setCrntUrl] = useState<string | null>(null);
const { getColors } = useThemeColors();
const [localeReady, setLocaleReady] = useState<boolean>(false);
const onRefresh = () => {
@@ -87,27 +85,26 @@ export const Preview: React.FunctionComponent<IPreviewProps> = ({
{
localeReady && (
<div
className={`actions flex items-center space-x-2 px-2 ${getColors('text-vulcan-500 dark:text-whisper-100', 'text-[var(--vscode-list-activeSelectionForeground)]')
}`}
className={`actions flex items-center space-x-2 px-2 text-[var(--vscode-list-activeSelectionForeground)]`}
>
<button
title={l10n.t(LocalizationKey.dashboardPreviewButtonOpenTitle)}
onClick={navigateToUrl}
className={getColors(`hover:text-vulcan-500 dark:hover:text-whisper-100`, `hover:text-[var(--vscode-textLink-activeForeground)]`)}>
className={`hover:text-[var(--vscode-textLink-activeForeground)]`}>
<ArrowRightIcon className="w-4 h-4" aria-hidden="true" />
</button>
<button
title={l10n.t(LocalizationKey.dashboardPreviewButtonRefreshTitle)}
onClick={onRefresh}
className={`mr-2 ${getColors(`hover:text-vulcan-500 dark:hover:text-whisper-100`, `hover:text-[var(--vscode-textLink-activeForeground)]`)}`}>
className={`mr-2 hover:text-[var(--vscode-textLink-activeForeground)]`}>
<ArrowPathIcon className="w-4 h-4" aria-hidden="true" />
</button>
<button
title={l10n.t(LocalizationKey.dashboardPreviewButtonOpenTitle)}
onClick={openInBrowser}
className={`mr-2 ${getColors(`hover:text-vulcan-500 dark:hover:text-whisper-100`, `hover:text-[var(--vscode-textLink-activeForeground)]`)}`}>
className={`mr-2 hover:text-[var(--vscode-textLink-activeForeground)]`}>
<ArrowTopRightOnSquareIcon className="w-4 h-4" aria-hidden="true" />
</button>
</div>
@@ -6,15 +6,17 @@ import { useRecoilValue } from 'recoil';
import { SettingsSelector } from '../../state';
import { SettingsInput } from './SettingsInput';
import { VSCodeButton } from '@vscode/webview-ui-toolkit/react';
import { FrameworkDetectors, SETTING_FRAMEWORK_START, SETTING_PREVIEW_HOST, SETTING_WEBSITE_URL } from '../../../constants';
import { DOCS_SUBMODULES, FrameworkDetectors, GIT_CONFIG, SETTING_FRAMEWORK_START, SETTING_GIT_COMMIT_MSG, SETTING_GIT_ENABLED, SETTING_PREVIEW_HOST, SETTING_WEBSITE_URL } from '../../../constants';
import { messageHandler } from '@estruyf/vscode/dist/client';
import { DashboardMessage } from '../../DashboardMessage';
import { SettingsCheckbox } from './SettingsCheckbox';
import { ChevronRightIcon } from '@heroicons/react/24/outline';
export interface ICommonSettingsProps { }
interface Config {
name: string;
value: string;
value: string | boolean;
}
export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (props: React.PropsWithChildren<ICommonSettingsProps>) => {
@@ -22,7 +24,7 @@ export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (pr
const [config, setConfig] = React.useState<Config[]>([]);
const [updated, setUpdated] = React.useState<boolean>(false);
const onSettingChange = React.useCallback((name: string, value: string) => {
const onSettingChange = React.useCallback((name: string, value: string | boolean) => {
setConfig((prev) => {
const setting = prev.find((c) => c.name === name);
if (setting) {
@@ -39,7 +41,13 @@ export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (pr
}, [config]);
const retrieveSettings = () => {
messageHandler.request<Config[]>(DashboardMessage.getSettings, [SETTING_PREVIEW_HOST, SETTING_WEBSITE_URL, SETTING_FRAMEWORK_START]).then((config) => {
messageHandler.request<Config[]>(DashboardMessage.getSettings, [
SETTING_PREVIEW_HOST,
SETTING_WEBSITE_URL,
SETTING_FRAMEWORK_START,
SETTING_GIT_ENABLED,
SETTING_GIT_COMMIT_MSG,
]).then((config) => {
setConfig(config);
setUpdated(false);
});
@@ -65,6 +73,42 @@ export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (pr
<Startup settings={settings} />
</div>
<div className='py-4'>
<h2 className='text-xl mb-2'>{l10n.t(LocalizationKey.settingsGit)}</h2>
<div className='space-y-2'>
<SettingsCheckbox
label={l10n.t(LocalizationKey.settingsGitEnabled)}
name={SETTING_GIT_ENABLED}
value={(config.find((c) => c.name === SETTING_GIT_ENABLED)?.value || false) as boolean}
onChange={onSettingChange}
/>
<SettingsInput
label={l10n.t(LocalizationKey.settingsGitCommitMessage)}
name={SETTING_GIT_COMMIT_MSG}
value={(config.find((c) => c.name === SETTING_GIT_COMMIT_MSG)?.value || "") as string}
placeholder={GIT_CONFIG.defaultCommitMessage}
onChange={onSettingChange}
/>
<p className={`text-[var(--frontmatter-secondary-text)] flex items-center`}>
<ChevronRightIcon className='h-4 w-4 inline' />
<span>
{l10n.t(LocalizationKey.settingsGitSubmoduleInfo)}&nbsp;
</span>
<a
href={DOCS_SUBMODULES}
title={l10n.t(LocalizationKey.settingsGitSubmoduleLink)}
className='text-[var(--vscode-textLink-foreground)] hover:text-[var(--vscode-textLink-activeForeground)]'>
{l10n.t(LocalizationKey.settingsGitSubmoduleLink)}
</a>
</p>
</div>
</div>
<div className='py-4'>
<h2 className='text-xl mb-2'>{l10n.t(LocalizationKey.settingsCommonSettingsWebsiteTitle)}</h2>
@@ -72,21 +116,21 @@ export const CommonSettings: React.FunctionComponent<ICommonSettingsProps> = (pr
<SettingsInput
label={l10n.t(LocalizationKey.settingsCommonSettingsPreviewUrl)}
name={SETTING_PREVIEW_HOST}
value={config.find((c) => c.name === SETTING_PREVIEW_HOST)?.value || ""}
value={(config.find((c) => c.name === SETTING_PREVIEW_HOST)?.value || "") as string}
onChange={onSettingChange}
/>
<SettingsInput
label={l10n.t(LocalizationKey.settingsCommonSettingsWebsiteUrl)}
name={SETTING_WEBSITE_URL}
value={config.find((c) => c.name === SETTING_WEBSITE_URL)?.value || ""}
value={(config.find((c) => c.name === SETTING_WEBSITE_URL)?.value || "") as string}
onChange={onSettingChange}
/>
<SettingsInput
label={l10n.t(LocalizationKey.settingsCommonSettingsStartCommand)}
name={SETTING_FRAMEWORK_START}
value={config.find((c) => c.name === SETTING_FRAMEWORK_START)?.value || ""}
value={(config.find((c) => c.name === SETTING_FRAMEWORK_START)?.value || "") as string}
onChange={onSettingChange}
fallback={FrameworkDetectors.find((f) => f.framework.name === settings?.crntFramework)?.commands.start || ""}
/>
@@ -0,0 +1,35 @@
import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';
import * as React from 'react';
export interface ISettingsCheckboxProps {
label: string;
name: string;
value: boolean;
onChange: (key: string, value: boolean) => void;
}
export const SettingsCheckbox: React.FunctionComponent<ISettingsCheckboxProps> = ({
label,
name,
value,
onChange
}: React.PropsWithChildren<ISettingsCheckboxProps>) => {
const [isEnabled, setIsEnabled] = React.useState(false);
const updateValue = (value: boolean) => {
setIsEnabled(value);
onChange(name, value);
}
React.useEffect(() => {
setIsEnabled(value);
}, [value]);
return (
<VSCodeCheckbox
onChange={(e: React.ChangeEvent<HTMLInputElement>) => updateValue(e.target.checked)}
checked={isEnabled}>
{label}
</VSCodeCheckbox>
);
};
@@ -5,6 +5,7 @@ export interface ISettingsInputProps {
label: string;
name: string;
value: string;
placeholder?: string;
onChange: (key: string, value: string) => void;
fallback?: string;
}
@@ -13,6 +14,7 @@ export const SettingsInput: React.FunctionComponent<ISettingsInputProps> = ({
label,
name,
value,
placeholder,
onChange,
fallback
}: React.PropsWithChildren<ISettingsInputProps>) => {
@@ -24,6 +26,7 @@ export const SettingsInput: React.FunctionComponent<ISettingsInputProps> = ({
boxShadow: 'none'
}}
value={value || fallback || ""}
placeholder={placeholder}
onInput={(e: React.ChangeEvent<HTMLInputElement>) => onChange(name, e.target.value)}>
{label}
</VSCodeTextField>
@@ -17,7 +17,6 @@ import { FEATURE_FLAG } from '../../../constants';
import { SnippetParser } from '../../../helpers/SnippetParser';
import { Snippet, Snippets } from '../../../models';
import { DashboardMessage } from '../../DashboardMessage';
import useThemeColors from '../../hooks/useThemeColors';
import { ModeAtom, SettingsSelector, ViewDataSelector } from '../../state';
import { QuickAction } from '../Menu';
import { Alert } from '../Modals/Alert';
@@ -42,7 +41,6 @@ export const Item: React.FunctionComponent<IItemProps> = ({
const [showInsertDialog, setShowInsertDialog] = useState(false);
const [showEditDialog, setShowEditDialog] = useState(false);
const [showAlert, setShowAlert] = React.useState(false);
const { getColors } = useThemeColors();
const [snippetTitle, setSnippetTitle] = useState<string>('');
const [snippetDescription, setSnippetDescription] = useState<string>('');
@@ -163,17 +161,9 @@ export const Item: React.FunctionComponent<IItemProps> = ({
return (
<>
<li className={`group relative overflow-hidden shadow-md hover:shadow-xl dark:shadow-none border p-4 space-y-2 rounded ${getColors(
'bg-gray-50 dark:bg-vulcan-200 dark:hover:bg-vulcan-100 border-gray-200 dark:border-vulcan-50',
'bg-[var(--vscode-sideBar-background)] hover:bg-[var(--vscode-list-hoverBackground)] border-[var(--frontmatter-border)]'
)
}`}>
<li className={`group relative overflow-hidden shadow-md hover:shadow-xl dark:shadow-none border p-4 space-y-2 rounded bg-[var(--vscode-sideBar-background)] hover:bg-[var(--vscode-list-hoverBackground)] border-[var(--frontmatter-border)]`}>
<div className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2">
<CodeBracketIcon className={`w-64 h-64 opacity-5 ${getColors(
'text-vulcan-200 dark:text-gray-400',
'text-[var(--vscode-foreground)]'
)
}`} />
<CodeBracketIcon className={`w-64 h-64 opacity-5 text-[var(--vscode-foreground)]`} />
</div>
<h2
@@ -195,11 +185,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
alternative={
insertToContent ? (
<div className={`absolute top-4 right-4 flex flex-col space-y-4`}>
<div className={`flex items-center border border-transparent rounded-full p-2 -mr-2 -mt-2 ${getColors(
'group-hover:bg-gray-200 dark:group-hover:bg-vulcan-200 group-hover:border-gray-100 dark:group-hover:border-vulcan-50',
'group-hover:bg-[var(--vscode-sideBar-background)] group-hover:border-[var(--frontmatter-border)]'
)
}`}>
<div className={`flex items-center border border-transparent rounded-full p-2 -mr-2 -mt-2 group-hover:bg-[var(--vscode-sideBar-background)] group-hover:border-[var(--frontmatter-border)]`}>
<div className="group-hover:hidden">
<EllipsisHorizontalIcon className="w-4 h-4" />
</div>
@@ -217,11 +203,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
}
>
<div className={`absolute top-4 right-4 flex flex-col space-y-4`}>
<div className={`flex items-center border border-transparent rounded-full p-2 -mr-2 -mt-2 ${getColors(
'group-hover:bg-gray-200 dark:group-hover:bg-vulcan-200 group-hover:border-gray-100 dark:group-hover:border-vulcan-50',
'group-hover:bg-[var(--vscode-sideBar-background)] group-hover:border-[var(--frontmatter-border)]'
)
}`}>
<div className={`flex items-center border border-transparent rounded-full p-2 -mr-2 -mt-2 group-hover:bg-[var(--vscode-sideBar-background)] group-hover:border-[var(--frontmatter-border)]`}>
<div className="group-hover:hidden">
<EllipsisHorizontalIcon className="w-4 h-4" />
</div>
@@ -261,11 +243,7 @@ export const Item: React.FunctionComponent<IItemProps> = ({
</div>
</FeatureFlag>
<p className={`text-xs ${getColors(
'text-vulcan-200 dark:text-whisper-800',
'text-[var(--vscode-foreground)]'
)
}`}>{snippet.description}</p>
<p className={`text-xs text-[var(--vscode-foreground)]`}>{snippet.description}</p>
</li>
{showInsertDialog && (
@@ -1,7 +1,6 @@
import { Messenger } from '@estruyf/vscode/dist/client';
import * as React from 'react';
import { GeneralCommands } from '../../../constants';
import useThemeColors from '../../hooks/useThemeColors';
import { SnippetInput } from './SnippetInput';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -28,8 +27,6 @@ export const NewForm: React.FunctionComponent<INewFormProps> = ({
onDescriptionUpdate,
onBodyUpdate
}: React.PropsWithChildren<INewFormProps>) => {
const { getColors } = useThemeColors();
const openLink = () => {
Messenger.send(
GeneralCommands.toVSCode.openLink,
@@ -43,7 +40,7 @@ export const NewForm: React.FunctionComponent<INewFormProps> = ({
<label htmlFor={`title`} className="block text-sm font-medium capitalize">
{l10n.t(LocalizationKey.commonTitle)}
{' '}
<span className={getColors(`text-red-400`, `text-[var(--vscode-notificationsErrorIcon-foreground)]`)} title="Required field">
<span className={`text-[var(--vscode-editorError-foreground)]`} title="Required field">
*
</span>
</label>
@@ -52,7 +49,7 @@ export const NewForm: React.FunctionComponent<INewFormProps> = ({
name='title'
value={title}
placeholder={l10n.t(LocalizationKey.dashboardSnippetsViewNewFormSnippetInputTitlePlaceholder)}
onChange={(e) => onTitleUpdate(e.currentTarget.value)}
onChange={(e) => onTitleUpdate(e)}
/>
</div>
</div>
@@ -66,7 +63,7 @@ export const NewForm: React.FunctionComponent<INewFormProps> = ({
name='description'
value={description}
placeholder={l10n.t(LocalizationKey.dashboardSnippetsViewNewFormSnippetInputDescriptionPlaceholder)}
onChange={(e) => onDescriptionUpdate(e.currentTarget.value)}
onChange={(e) => onDescriptionUpdate(e)}
/>
</div>
</div>
@@ -75,7 +72,7 @@ export const NewForm: React.FunctionComponent<INewFormProps> = ({
<label htmlFor={`snippet`} className="block text-sm font-medium capitalize">
{l10n.t(LocalizationKey.dashboardSnippetsViewNewFormSnippetInputSnippetLabel)}
{' '}
<span className="text-red-400" title="Required field">
<span className="text-[var(--vscode-editorError-foreground)]" title="Required field">
*
</span>
</label>
@@ -84,7 +81,7 @@ export const NewForm: React.FunctionComponent<INewFormProps> = ({
name='snippet'
value={body}
placeholder={l10n.t(LocalizationKey.dashboardSnippetsViewNewFormSnippetInputSnippetPlaceholder)}
onChange={(e) => onBodyUpdate(e.currentTarget.value)}
onChange={(e) => onBodyUpdate(e)}
isTextArea
/>
</div>
@@ -103,18 +100,13 @@ export const NewForm: React.FunctionComponent<INewFormProps> = ({
type="checkbox"
checked={isMediaSnippet}
onChange={(e) => onMediaSnippetUpdate(e.currentTarget.checked)}
className={`h-4 w-4 rounded ${getColors(
`focus:ring-teal-500 text-teal-600 border-gray-300 dark:border-vulcan-50`,
`focus:ring-[var(--frontmatter-button-background)] text-[var(--frontmatter-button-background)] border-[var(--frontmatter-border)]`
)
}`}
className={`h-4 w-4 rounded focus:ring-[var(--frontmatter-button-background)] text-[var(--frontmatter-button-background)] border-[var(--frontmatter-border)]`}
/>
</div>
<div className="ml-3 text-sm">
<label
htmlFor="isMediaSnippet"
className={`font-medium ${getColors(`text-vulcan-100 dark:text-whisper-900`, `text-[var(--vscode-editor-foreground)]`)
}`}
className={`font-medium text-[var(--vscode-editor-foreground)]`}
>
{l10n.t(LocalizationKey.dashboardSnippetsViewNewFormSnippetInputIsMediaSnippetCheckboxLabel)}
</label>
@@ -6,7 +6,6 @@ import { processKnownPlaceholders } from '../../../helpers/PlaceholderHelper';
import { SnippetParser } from '../../../helpers/SnippetParser';
import { Snippet, SnippetField, SnippetInfoField, SnippetSpecialPlaceholders } from '../../../models';
import { DashboardMessage } from '../../DashboardMessage';
import useThemeColors from '../../hooks/useThemeColors';
import { SettingsAtom, ViewDataSelector } from '../../state';
import { SnippetInputField } from './SnippetInputField';
import { SNIPPET } from '../../../constants/Snippet';
@@ -31,7 +30,6 @@ const SnippetForm: React.ForwardRefRenderFunction<SnippetFormHandle, ISnippetFor
const viewData = useRecoilValue(ViewDataSelector);
const [fields, setFields] = useState<SnippetField[]>([]);
const settings = useRecoilValue(SettingsAtom);
const { getColors } = useThemeColors();
const onTextChange = useCallback(
(field: SnippetField, value: string) => {
@@ -169,11 +167,7 @@ ${snippetBody}
return (
<div>
<pre className={`border p-2 whitespace-pre-wrap break-words max-h-64 overflow-auto rounded ${getColors(
'border-opacity-40',
'border-[var(--frontmatter-border)] bg-[var(--vscode-editor-background)] text-[var(--vscode-editor-foreground)]',
)
}`}>
<pre className={`border p-2 whitespace-pre-wrap break-words max-h-64 overflow-auto rounded border-[var(--frontmatter-border)] bg-[var(--vscode-editor-background)] text-[var(--vscode-editor-foreground)]`}>
{snippetBody}
</pre>
@@ -1,48 +1,33 @@
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import { TextField } from '../Common/TextField';
export interface ISnippetInputProps {
name: string;
value?: string;
placeholder?: string;
onChange?: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void;
onChange?: (value: string) => void;
isTextArea?: boolean;
}
export const SnippetInput: React.FunctionComponent<ISnippetInputProps> = ({ name, value, placeholder, isTextArea, onChange }: React.PropsWithChildren<ISnippetInputProps>) => {
const { getColors } = useThemeColors();
if (isTextArea) {
return (
<textarea
<TextField
name={name}
value={value || ''}
placeholder={placeholder}
rows={5}
className={`block w-full sm:text-sm ${
getColors(
'focus:outline-none border-gray-300 text-vulcan-500',
'border-transparent bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent'
)
}`}
onChange={onChange}
multiline
/>
)
}
return (
<input
type="text"
<TextField
name={name}
value={value || ''}
placeholder={placeholder}
className={`block w-full sm:text-sm ${
getColors(
'focus:outline-none border-gray-300 text-vulcan-500',
'border-transparent bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent'
)
}`}
onChange={onChange}
/>
onChange={onChange} />
);
};
@@ -1,8 +1,8 @@
import * as React from 'react';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
import { Choice, SnippetField, SnippetInfoField } from '../../../models';
import useThemeColors from '../../hooks/useThemeColors';
import { useEffect } from 'react';
import { TextField } from '../Common/TextField';
export interface ISnippetInputFieldProps {
field: SnippetField;
@@ -15,7 +15,6 @@ export const SnippetInputField: React.FunctionComponent<ISnippetInputFieldProps>
fieldInfo,
onValueChange
}: React.PropsWithChildren<ISnippetInputFieldProps>) => {
const { getColors } = useThemeColors();
useEffect(() => {
if (fieldInfo) {
@@ -32,11 +31,10 @@ export const SnippetInputField: React.FunctionComponent<ISnippetInputFieldProps>
<select
name={field.name}
value={field.value || ''}
className={`block w-full sm:text-sm ${getColors(
'focus:outline-none border-gray-300 text-vulcan-500',
'border-transparent bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent'
)
}`}
className={`block w-full sm:text-sm pr-2 appearance-none disabled:opacity-50 rounded bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] border-[var(--frontmatter-border)] focus:border-[var(--vscode-focusBorder)] focus:outline-0`}
style={{
boxShadow: "none"
}}
onChange={(e) => onValueChange(field, e.target.value)}
>
{(field.choices || [])?.map((option: string | Choice, index: number) =>
@@ -59,31 +57,21 @@ export const SnippetInputField: React.FunctionComponent<ISnippetInputFieldProps>
if (field.type === 'string' && !field.single) {
return (
<textarea
<TextField
name={field.name}
value={field.value || ''}
className={`block w-full sm:text-sm h-auto ${getColors(
'focus:outline-none border-gray-300 text-vulcan-500',
'border-transparent bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent'
)
}`}
onChange={(e) => onValueChange(field, e.currentTarget.value)}
onChange={(e) => onValueChange(field, e)}
rows={4}
multiline
/>
);
}
return (
<input
type="text"
<TextField
name={field.name}
value={field.value || ''}
className={`block w-full sm:text-sm ${getColors(
'focus:outline-none border-gray-300 text-vulcan-500',
'border-transparent bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent'
)
}`}
onChange={(e) => onValueChange(field, e.currentTarget.value)}
onChange={(e) => onValueChange(field, e)}
/>
);
};
@@ -8,7 +8,6 @@ import { FEATURE_FLAG } from '../../../constants';
import { TelemetryEvent } from '../../../constants/TelemetryEvent';
import { SnippetParser } from '../../../helpers/SnippetParser';
import { DashboardMessage } from '../../DashboardMessage';
import useThemeColors from '../../hooks/useThemeColors';
import { ModeAtom, SettingsSelector, ViewDataSelector } from '../../state';
import { FilterInput } from '../Header/FilterInput';
import { PageLayout } from '../Layout/PageLayout';
@@ -33,7 +32,6 @@ export const Snippets: React.FunctionComponent<ISnippetsProps> = (
const [showCreateDialog, setShowCreateDialog] = useState(false);
const [mediaSnippet, setMediaSnippet] = useState(false);
const [snippetFilter, setSnippetFilter] = useState<string>('');
const { getColors } = useThemeColors();
const snippets = settings?.snippets || {};
const snippetKeys = useMemo(() => {
@@ -92,8 +90,7 @@ export const Snippets: React.FunctionComponent<ISnippetsProps> = (
header={
<FeatureFlag features={mode?.features || []} flag={FEATURE_FLAG.dashboard.snippets.manage}>
<div
className={`py-3 px-4 flex items-center justify-between border-b ${getColors(`border-gray-300 dark:border-vulcan-100`, `border-[var(--frontmatter-border)]`)
}`}
className={`py-3 px-4 flex items-center justify-between border-b border-[var(--frontmatter-border)]`}
aria-label={l10n.t(LocalizationKey.dashboardSnippetsViewSnippetsAriaLabel)}
>
<FilterInput
@@ -107,11 +104,7 @@ export const Snippets: React.FunctionComponent<ISnippetsProps> = (
<div className="flex flex-1 justify-end">
<button
className={`inline-flex items-center px-3 py-1 rounded text-xs leading-4 font-medium focus:outline-none ${getColors(
`text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 disabled:bg-gray-500`,
`text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`
)
}`}
className={`inline-flex items-center px-3 py-1 rounded text-xs leading-4 font-medium focus:outline-none text-[var(--vscode-button-foreground)] bg-[var(--frontmatter-button-background)] hover:bg-[var(--vscode-button-hoverBackground)] disabled:opacity-50`}
title={l10n.t(LocalizationKey.dashboardSnippetsViewSnippetsButtonCreate)}
onClick={() => setShowCreateDialog(true)}
>
@@ -145,15 +138,14 @@ export const Snippets: React.FunctionComponent<ISnippetsProps> = (
</ul>
) : (
<div className="w-full h-full flex items-center justify-center text-white">
<div className={`flex flex-col items-center ${getColors('text-gray-500 dark:text-whisper-900', 'text-[var(--frontmatter-text)]')
}`}>
<div className={`flex flex-col items-center text-[var(--frontmatter-text)]`}>
<CodeBracketIcon className="w-32 h-32" />
<p className="text-3xl mt-2">
{l10n.t(LocalizationKey.dashboardSnippetsViewSnippetsEmptyMessage)}
</p>
<p className="text-xl mt-4">
<a
className={getColors(`text-teal-700 hover:text-teal-900`, `text-[var(--frontmatter-link)] hover:text-[var(--frontmatter-link-hover)]`)}
className={`text-[var(--frontmatter-link)] hover:text-[var(--frontmatter-link-hover)]`}
href={`https://frontmatter.codes/docs/snippets`}
title={l10n.t(LocalizationKey.dashboardSnippetsViewSnippetsReadMore)}
>
@@ -10,15 +10,15 @@ import { MenuItem } from '../Menu';
import { Framework, StaticFolder, Template } from '../../../models';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
import { FrameworkDetectors } from '../../../constants/FrameworkDetectors';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { SelectItem } from './SelectItem';
import { Templates } from '../../../constants';
import { GeneralCommands, SETTING_GIT_ENABLED, Templates } from '../../../constants';
import { TemplateItem } from './TemplateItem';
import { Spinner } from '../Common/Spinner';
import { AstroContentTypes } from '../Configuration/Astro/AstroContentTypes';
import { ContentFolders } from '../Configuration/Common/ContentFolders';
import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';
export interface IStepsToGetStartedProps {
settings: Settings;
@@ -30,9 +30,10 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
const [loading, setLoading] = useState<boolean>(false);
const [framework, setFramework] = useState<string | null>(null);
const [taxImported, setTaxImported] = useState<boolean>(false);
const [isGitEnabled, setIsGitEnabled] = useState<boolean>(false);
const [isGitRepo, setIsGitRepo] = useState<boolean>(false);
const [templates, setTemplates] = useState<Template[]>([]);
const [astroCollectionsStatus, setAstroCollectionsStatus] = useState<Status>(Status.Optional)
const { getColors } = useThemeColors();
const [astroCollectionsStatus, setAstroCollectionsStatus] = useState<Status>(Status.Optional);
const frameworks: Framework[] = FrameworkDetectors.map((detector: any) => detector.framework);
@@ -75,6 +76,15 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
setTaxImported(true);
};
const updateSetting = (name: string, value: any) => {
setIsGitEnabled(value);
Messenger.send(DashboardMessage.updateSetting, {
name,
value,
global: true
});
}
const crntTemplates = useMemo(() => {
if (!templates || templates.length === 0 || !settings.crntFramework) {
return [];
@@ -108,29 +118,17 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
<Menu as="div" className="relative inline-block text-left mt-4">
<div>
<Menu.Button className={`group flex justify-center p-2 rounded-md border ${getColors(
'text-vulcan-500 hover:text-vulcan-600 dark:text-whisper-500 dark:hover:text-whisper-600 border-vulcan-400 dark:border-white',
'text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)]'
)
}`}>
<Menu.Button className={`group flex justify-center p-2 rounded-md border text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)]`}>
{framework ? framework : l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedFrameworkSelect)}
<ChevronDownIcon
className={`flex-shrink-0 -mr-1 ml-1 h-5 w-5 ${getColors(
'text-gray-400 group-hover:text-gray-500 dark:text-whisper-600 dark:group-hover:text-whisper-700',
''
)
}`}
className={`flex-shrink-0 -mr-1 ml-1 h-5 w-5`}
aria-hidden="true"
/>
</Menu.Button>
</div>
<Menu.Items
className={`w-40 origin-top-left absolute left-0 z-10 mt-2 rounded-md shadow-2xl ring-1 ring-opacity-5 focus:outline-none text-sm max-h-96 overflow-auto ${getColors(
'bg-white dark:bg-vulcan-500 ring-vulcan-400 dark:ring-white',
'bg-[var(--vscode-sideBar-background)] ring-[var(--frontmatter-border)]'
)
}`}
className={`w-40 origin-top-left absolute left-0 z-10 mt-2 rounded-md shadow-2xl ring-1 ring-opacity-5 focus:outline-none text-sm max-h-96 overflow-auto bg-[var(--vscode-sideBar-background)] ring-[var(--frontmatter-border)]`}
>
<div className="py-1">
<MenuItem
@@ -244,6 +242,21 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
show: settings.crntFramework === 'astro' || framework === 'astro',
status: settings.initialized && settings.staticFolder && settings.staticFolder !== "/" ? Status.Completed : Status.NotStarted,
},
{
id: `welcome-git`,
name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedGitName),
description: (
<div className='mt-1'>
<VSCodeCheckbox
onChange={(e: React.ChangeEvent<HTMLInputElement>) => updateSetting(SETTING_GIT_ENABLED, e.target.checked)}
checked={isGitEnabled}>
{l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedGitDescription)}
</VSCodeCheckbox>
</div>
),
show: isGitRepo,
status: settings.git.actions ? Status.Completed : Status.NotStarted
},
{
id: `welcome-import`,
name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedTagsName),
@@ -271,7 +284,7 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
: undefined
}
]
), [settings, framework, taxImported, templates, astroCollectionsStatus]);
), [settings, framework, taxImported, templates, astroCollectionsStatus, isGitRepo]);
React.useEffect(() => {
if (settings.crntFramework || settings.framework?.name) {
@@ -279,6 +292,14 @@ export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps>
}
}, [settings.crntFramework, settings.framework]);
React.useEffect(() => {
messageHandler.request<boolean>(GeneralCommands.toVSCode.gitIsRepo).then((result) => {
setIsGitRepo(result);
});
setIsGitEnabled(settings.git.actions);
}, [settings.git.actions]);
React.useEffect(() => {
const fetchTemplates = async () => {
try {
@@ -1,5 +1,6 @@
import { FunnelIcon, XCircleIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import { TextField } from '../Common/TextField';
export interface IFilterInputProps {
label?: string;
@@ -29,27 +30,17 @@ export const FilterInput: React.FunctionComponent<IFilterInputProps> = ({
)
}
<div className="relative flex justify-center">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<TextField
name='filter'
icon={(
<FunnelIcon className={`h-4 w-4 text-[var(--vscode-input-foreground)]`} aria-hidden="true" />
</div>
<input
type="text"
name="filter"
className={`block w-full py-2 pl-10 pr-3 sm:text-sm appearance-none disabled:opacity-50 rounded bg-[var(--vscode-input-background)] text-[var(--vscode-input-foreground)] border-[var(--vscode-input-border)] placeholder-[var(--vscode-input-placeholderForeground)] focus:outline-[var(--vscode-focusBorder)] focus:outline-1 focus:outline-offset-0 focus:shadow-none focus:border-transparent`}
placeholder={placeholder || ""}
value={value}
onChange={(e) => onChange && onChange(e.target.value)}
disabled={disabled}
/>
{value && (
<button onClick={onReset} className="absolute inset-y-0 right-0 pr-3 flex items-center">
<XCircleIcon className={`h-5 w-5 text-[var(--vscode-input-foreground)]`} aria-hidden="true" />
</button>
)}
</div>
value={value}
placeholder={placeholder || ""}
disabled={disabled}
onChange={onChange}
onReset={onReset}
/>
</div>
</div>
);
@@ -2,10 +2,11 @@ import { Messenger } from '@estruyf/vscode/dist/client';
import {
ArrowUpCircleIcon,
PencilIcon,
PlusCircleIcon,
PlusIcon,
TagIcon,
TrashIcon,
} from '@heroicons/react/24/outline';
} from '@heroicons/react/24/solid';
import * as React from 'react';
import { useCallback } from 'react';
import { MergeIcon } from '../../../components/icons/MergeIcon';
@@ -68,7 +69,7 @@ export const TaxonomyActions: React.FunctionComponent<ITaxonomyActionsProps> = (
return (
<>
<div className={`space-x-2`}>
<div className={`space-x-2 text-[var(--frontmatter-text)]`}>
{unmapped && (
<LinkButton
title={l10n.t(LocalizationKey.dashboardTaxonomyViewButtonAddTitle, value)}
@@ -83,7 +84,10 @@ export const TaxonomyActions: React.FunctionComponent<ITaxonomyActionsProps> = (
<LinkButton
title={`Tag content`}
onClick={onTagging}>
<TagIcon className={`w-4 h-4`} aria-hidden={true} />
<div className='relative'>
<TagIcon className={`w-4 h-4`} aria-hidden={true} />
<PlusCircleIcon className={`w-3 h-3 absolute left-[-3px] bottom-[-4px] border-1 bg-[var(--vscode-editor-background)] rounded-full`} aria-hidden={true} />
</div>
<span className="sr-only">{l10n.t(LocalizationKey.commonEdit)}</span>
</LinkButton>
@@ -6,7 +6,6 @@ import { useRecoilValue } from 'recoil';
import { getTaxonomyField } from '../../../helpers/getTaxonomyField';
import { useNavigate } from 'react-router-dom';
import { routePaths } from '../..';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -23,7 +22,6 @@ export const TaxonomyLookup: React.FunctionComponent<ITaxonomyLookupProps> = ({
}: React.PropsWithChildren<ITaxonomyLookupProps>) => {
const settings = useRecoilValue(SettingsSelector);
const navigate = useNavigate();
const { getColors } = useThemeColors();
const total: number | undefined = useMemo(() => {
if (!taxonomy || !value || !pages || !settings?.contentTypes) {
@@ -58,7 +56,7 @@ export const TaxonomyLookup: React.FunctionComponent<ITaxonomyLookupProps> = ({
if (taxonomy === 'tags' || taxonomy === 'categories') {
return (
<button
className={total ? `font-bold ${getColors(`text-teal-900 hover:text-teal-600 `, `text-[var(--frontmatter-link)] hover:text-[var(--frontmatter-link-hover)]`)}` : ``}
className={total ? `font-bold text-[var(--frontmatter-link)] hover:text-[var(--frontmatter-link-hover)]` : ``}
title={total ? l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyLookupButtonTitle, value, taxonomy) : ``}
onClick={onNavigate}
>
@@ -174,7 +174,7 @@ export const TaxonomyManager: React.FunctionComponent<ITaxonomyManagerProps> = (
<tr>
<th
scope="col"
className={`px-6 py-3 text-left text-xs font-medium uppercase text-[var(--frontmatter-secondary-text)]'`}
className={`px-6 py-3 text-left text-xs font-medium uppercase text-[var(--frontmatter-secondary-text)]`}
>
{l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyManagerTableHeadingName)}
</th>
@@ -1,10 +1,10 @@
import * as React from 'react';
import { Page, PageMappings, SortingOption } from '../../models';
import { useRecoilValue } from 'recoil';
import { SettingsSelector, SortingAtom } from '../../state';
import { SettingsSelector } from '../../state';
import { getTaxonomyField } from '../../../helpers/getTaxonomyField';
import { Sorting } from '../../../helpers/Sorting';
import { ArrowLeftIcon } from '@heroicons/react/24/outline';
import { ArrowLeftIcon, EyeIcon } from '@heroicons/react/24/outline';
import { Button } from '../Common/Button';
import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';
import { FilterInput } from './FilterInput';
@@ -12,9 +12,10 @@ import { useDebounce } from '../../../hooks/useDebounce';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { sortPages } from '../../../utils/sortPages';
import { messageHandler } from '@estruyf/vscode/dist/client';
import { Messenger, messageHandler } from '@estruyf/vscode/dist/client';
import { DashboardMessage } from '../../DashboardMessage';
import { ExtensionState } from '../../../constants';
import { LinkButton } from '../Common/LinkButton';
export interface ITaxonomyTaggingProps {
taxonomy: string | null;
@@ -123,6 +124,10 @@ export const TaxonomyTagging: React.FunctionComponent<ITaxonomyTaggingProps> = (
return (!untaggedPages.find((p: Page) => p.fmFilePath === page.fmFilePath) && !pageMappings.untagged.find((p: Page) => p.fmFilePath === page.fmFilePath)) || pageMappings.tagged.find((p: Page) => p.fmFilePath === page.fmFilePath);
}, [untaggedPages, pageMappings.tagged]);
const onFileView = (filePath: string) => {
Messenger.send(DashboardMessage.openFile, filePath);
}
React.useEffect(() => {
messageHandler.request<{ key: string; value: SortingOption; }>(DashboardMessage.getState, {
key: ExtensionState.Dashboard.Contents.Sorting
@@ -173,12 +178,18 @@ export const TaxonomyTagging: React.FunctionComponent<ITaxonomyTaggingProps> = (
>
{l10n.t(LocalizationKey.commonTitle)}
</th>
<th
scope="col"
className={``}
>
</th>
</tr>
</thead>
<tbody className={`divide-y divide-[var(--frontmatter-border)]`}>
{untaggedPages && sortedPages && sortedPages.map((page) => (
<tr key={page.fmFilePath} className='py-2'>
<td className={`pl-6 w-[25px]`}>
<tr key={page.fmFilePath}>
<td className={`pl-6 py-2 w-[25px]`}>
<VSCodeCheckbox
title={l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyTaggingCheckbox, value)}
onClick={() => onCheckboxClick(page)}
@@ -188,14 +199,24 @@ export const TaxonomyTagging: React.FunctionComponent<ITaxonomyTaggingProps> = (
</span>
</VSCodeCheckbox>
</td>
<td className={`pr-6 whitespace-nowrap text-sm font-medium text-[var(--frontmatter-text)]`}>
<td className={`py-2 text-sm font-medium text-[var(--frontmatter-text)]`}>
<button
title={l10n.t(LocalizationKey.dashboardTaxonomyViewTaxonomyTaggingCheckbox, value)}
className='hover:text-[var(--vscode-textLink-activeForeground)]'
className='hover:text-[var(--vscode-textLink-activeForeground)] text-left'
onClick={() => onCheckboxClick(page)}>
{page.title}
</button>
</td>
<td className={`py-2 pr-6`}>
<LinkButton
title={l10n.t(LocalizationKey.dashboardContentsContentActionsMenuItemView)}
onClick={() => onFileView(page.fmFilePath)}>
<EyeIcon className={`w-4 h-4`} aria-hidden={true} />
<span className='sr-only'>
{l10n.t(LocalizationKey.dashboardContentsContentActionsMenuItemView)}
</span>
</LinkButton>
</td>
</tr>
))}
</tbody>
@@ -1,6 +1,5 @@
import { StopIcon } from '@heroicons/react/24/outline';
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
@@ -9,11 +8,9 @@ export interface IUnknownViewProps { }
export const UnknownView: React.FunctionComponent<IUnknownViewProps> = (
_: React.PropsWithChildren<IUnknownViewProps>
) => {
const { getColors } = useThemeColors();
return (
<div className={`w-full h-full flex items-center justify-center`}>
<div className={`flex flex-col items-center ${getColors(`text-gray-500 dark:text-whisper-900`, `text-[var(--frontmatter-text)]`)}`}>
<div className={`flex flex-col items-center text-[var(--frontmatter-text)]`}>
<StopIcon className="w-32 h-32" />
<p className="text-3xl mt-2">
{l10n.t(LocalizationKey.dashboardUnkownViewTitle)}
@@ -1,5 +1,4 @@
import * as React from 'react';
import useThemeColors from '../../hooks/useThemeColors';
export interface IWelcomeLinkProps {
href: string;
@@ -7,17 +6,11 @@ export interface IWelcomeLinkProps {
}
export const WelcomeLink: React.FunctionComponent<IWelcomeLinkProps> = ({ href, title, children }: React.PropsWithChildren<IWelcomeLinkProps>) => {
const { getColors } = useThemeColors();
return (
<a
href={href}
title={title}
className={`flex items-center px-1 ${getColors(
'text-vulcan-300 hover:text-vulcan-500 dark:text-whisper-500 dark:hover:text-teal-500',
'text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-textLink-activeForeground)]'
)
}`}
className={`flex items-center px-1 text-[var(--vscode-editor-foreground)] hover:text-[var(--vscode-textLink-activeForeground)]`}
>
{children}
</a>
-1
View File
@@ -4,4 +4,3 @@ export * from './useMedia';
export * from './useMessages';
export * from './usePages';
export * from './usePagination';
export * from './useThemeColors';

Some files were not shown because too many files have changed in this diff Show More