mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-05-01 02:52:29 +02:00
Merge branch 'dev' into issue/747
This commit is contained in:
@@ -6,12 +6,15 @@
|
||||
|
||||
- [#731](https://github.com/estruyf/vscode-front-matter/issues/731): Added the ability to map/unmap taxonomy to multiple pages at once
|
||||
- [#746](https://github.com/estruyf/vscode-front-matter/issues/746): Placeholder support added to to the `slug` field
|
||||
- [#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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 +0,0 @@
|
||||
export * from './sleep';
|
||||
@@ -1,3 +0,0 @@
|
||||
export async function sleep(time: number) {
|
||||
await new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
@@ -50,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",
|
||||
@@ -278,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",
|
||||
|
||||
17415
package-lock.json
generated
17415
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
38
package.json
38
package.json
@@ -484,6 +484,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": [],
|
||||
@@ -2521,9 +2546,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",
|
||||
@@ -2543,7 +2565,6 @@
|
||||
"@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": "^4.0.9",
|
||||
@@ -2552,17 +2573,14 @@
|
||||
"@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",
|
||||
@@ -2570,7 +2588,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",
|
||||
@@ -2593,9 +2610,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",
|
||||
@@ -2627,7 +2642,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",
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -374,7 +374,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,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';
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
@@ -199,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();
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -8,6 +8,7 @@ export const GeneralCommands = {
|
||||
toVSCode: {
|
||||
openLink: 'openLink',
|
||||
gitSync: 'gitSync',
|
||||
gitIsRepo: 'gitIsRepo',
|
||||
getLocalization: 'getLocalization',
|
||||
openOnWebsite: 'openOnWebsite'
|
||||
}
|
||||
|
||||
3
src/constants/Git.ts
Normal file
3
src/constants/Git.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const GIT_CONFIG = {
|
||||
defaultCommitMessage: 'Synced by Front Matter'
|
||||
};
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -61,6 +61,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,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>
|
||||
|
||||
@@ -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,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,7 +11,6 @@ export const List: React.FunctionComponent<IListProps> = ({
|
||||
children
|
||||
}: React.PropsWithChildren<IListProps>) => {
|
||||
const view = useRecoilValue(ViewSelector);
|
||||
const { getColors } = useThemeColors();
|
||||
|
||||
let className = '';
|
||||
if (view === DashboardViewType.Grid) {
|
||||
@@ -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>
|
||||
|
||||
@@ -10,7 +10,6 @@ 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';
|
||||
@@ -34,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(() => {
|
||||
@@ -121,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>
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
@@ -2,9 +2,8 @@ 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,10 +84,7 @@ 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)]`}
|
||||
>
|
||||
<HomeIcon className="flex-shrink-0 h-5 w-5" aria-hidden="true" />
|
||||
<span className="sr-only">{l10n.t(LocalizationKey.dashboardHeaderBreadcrumbHome)}</span>
|
||||
@@ -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)}
|
||||
>
|
||||
|
||||
108
src/dashboardWebView/components/Header/Filters.tsx
Normal file
108
src/dashboardWebView/components/Header/Filters.tsx
Normal file
@@ -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';
|
||||
@@ -33,6 +31,7 @@ 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;
|
||||
@@ -50,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();
|
||||
@@ -123,27 +120,6 @@ 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)]`}>
|
||||
@@ -214,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,
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,7 +32,6 @@ 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) {
|
||||
@@ -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)}
|
||||
</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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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';
|
||||
|
||||
@@ -16,7 +15,6 @@ export const SnippetInputField: React.FunctionComponent<ISnippetInputFieldProps>
|
||||
fieldInfo,
|
||||
onValueChange
|
||||
}: React.PropsWithChildren<ISnippetInputFieldProps>) => {
|
||||
const { getColors } = useThemeColors();
|
||||
|
||||
useEffect(() => {
|
||||
if (fieldInfo) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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}
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -4,4 +4,3 @@ export * from './useMedia';
|
||||
export * from './useMessages';
|
||||
export * from './usePages';
|
||||
export * from './usePagination';
|
||||
export * from './useThemeColors';
|
||||
|
||||
@@ -75,7 +75,7 @@ export default function useMedia() {
|
||||
const messageListener = useCallback((message: MessageEvent<EventData<MediaPaths | { key: string; value: any }>>) => {
|
||||
if (message.data.command === DashboardCommand.media) {
|
||||
const payload: MediaPaths = message.data.payload as MediaPaths;
|
||||
setLoading("loading");
|
||||
setLoading(undefined);
|
||||
setMedia(payload.media);
|
||||
setTotal(payload.total);
|
||||
setFolders(payload.folders);
|
||||
|
||||
@@ -5,6 +5,8 @@ import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import {
|
||||
AllPagesAtom,
|
||||
CategorySelector,
|
||||
FilterValuesAtom,
|
||||
FiltersAtom,
|
||||
FolderSelector,
|
||||
SearchSelector,
|
||||
SettingsSelector,
|
||||
@@ -26,12 +28,14 @@ export default function usePages(pages: Page[]) {
|
||||
const [sortedPages, setSortedPages] = useState<Page[]>([]);
|
||||
const [sorting, setSorting] = useRecoilState(SortingAtom);
|
||||
const [tabInfo, setTabInfo] = useRecoilState(TabInfoAtom);
|
||||
const [, setFilterValues] = useRecoilState(FilterValuesAtom);
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const tab = useRecoilValue(TabSelector);
|
||||
const folder = useRecoilValue(FolderSelector);
|
||||
const search = useRecoilValue(SearchSelector);
|
||||
const tag = useRecoilValue(TagSelector);
|
||||
const category = useRecoilValue(CategorySelector);
|
||||
const filters = useRecoilValue(FiltersAtom);
|
||||
|
||||
/**
|
||||
* Process all the pages by applying the sorting, filtering and searching.
|
||||
@@ -86,9 +90,19 @@ export default function usePages(pages: Page[]) {
|
||||
);
|
||||
}
|
||||
|
||||
const filterNames = Object.keys(filters);
|
||||
if (filterNames.length > 0) {
|
||||
for (const filter of filterNames) {
|
||||
const filterValue = filters[filter];
|
||||
if (filterValue) {
|
||||
pagesSorted = pagesSorted.filter((page) => page[filter] === filterValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSortedPages(pagesSorted);
|
||||
},
|
||||
[settings, tab, folder, search, tag, category, sorting, tabInfo]
|
||||
[settings, tab, folder, search, tag, category, sorting, tabInfo, filters]
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -159,10 +173,27 @@ export default function usePages(pages: Page[]) {
|
||||
// Set the tab information
|
||||
setTabInfo(draftTypes);
|
||||
|
||||
if (Object.keys(filters).length === 0) {
|
||||
const availableFilters = (settings?.filters || []).filter((f) => f !== 'pageFolders' && f !== 'tags' && f !== 'categories');
|
||||
if (availableFilters.length > 0) {
|
||||
const allFilters: { [filter: string]: string[]; } = {};
|
||||
for (const filter of availableFilters) {
|
||||
if (filter) {
|
||||
const filterName = typeof filter === 'string' ? filter : filter.name;
|
||||
const values = crntPages.map((page) => page[filterName]).filter((value) => value);
|
||||
allFilters[filterName] = [...new Set(values)];
|
||||
}
|
||||
}
|
||||
setFilterValues(allFilters);
|
||||
} else {
|
||||
setFilterValues({});
|
||||
}
|
||||
}
|
||||
|
||||
// Set the pages
|
||||
setPageItems(crntPages);
|
||||
},
|
||||
[tab, tabInfo, settings]
|
||||
[tab, tabInfo, settings, filters]
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -204,7 +235,7 @@ export default function usePages(pages: Page[]) {
|
||||
} else {
|
||||
startPageProcessing();
|
||||
}
|
||||
}, [settings?.draftField, pages, sorting, search, tag, category, folder]);
|
||||
}, [settings?.draftField, pages, sorting, search, tag, category, filters, folder]);
|
||||
|
||||
useEffect(() => {
|
||||
processByTab(sortedPages);
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
|
||||
|
||||
import { useCallback } from 'react';
|
||||
import { useSettingsContext } from '../providers/SettingsProvider';
|
||||
|
||||
export default function useThemeColors() {
|
||||
const { experimental } = useSettingsContext();
|
||||
|
||||
const getColors = useCallback((defaultColors: string, themeColors: string) => {
|
||||
// The feature is now enabled by default
|
||||
return themeColors;
|
||||
}, [experimental]);
|
||||
|
||||
return {
|
||||
getColors
|
||||
};
|
||||
}
|
||||
@@ -37,6 +37,7 @@ export interface Settings {
|
||||
framework: Framework | null | undefined;
|
||||
draftField: DraftField | null | undefined;
|
||||
customSorting: SortingSetting[] | undefined;
|
||||
filters: (string | { title: string; name: string })[] | undefined;
|
||||
dashboardState: DashboardState;
|
||||
scripts: CustomScript[];
|
||||
dataFiles: DataFile[] | undefined;
|
||||
|
||||
6
src/dashboardWebView/state/atom/FilterValuesAtom.ts
Normal file
6
src/dashboardWebView/state/atom/FilterValuesAtom.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const FilterValuesAtom = atom<{ [filter: string]: string[] }>({
|
||||
key: 'FilterValuesAtom',
|
||||
default: {}
|
||||
});
|
||||
6
src/dashboardWebView/state/atom/FiltersAtom.ts
Normal file
6
src/dashboardWebView/state/atom/FiltersAtom.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const FiltersAtom = atom<{ [filter: string]: string }>({
|
||||
key: 'FiltersAtom',
|
||||
default: {}
|
||||
});
|
||||
@@ -3,6 +3,8 @@ export * from './AllPagesAtom';
|
||||
export * from './AllStaticFoldersAtom';
|
||||
export * from './CategoryAtom';
|
||||
export * from './DashboardViewAtom';
|
||||
export * from './FilterValuesAtom';
|
||||
export * from './FiltersAtom';
|
||||
export * from './FolderAtom';
|
||||
export * from './GroupingAtom';
|
||||
export * from './LightboxAtom';
|
||||
@@ -11,6 +13,7 @@ export * from './MediaFoldersAtom';
|
||||
export * from './MediaTotalAtom';
|
||||
export * from './ModeAtom';
|
||||
export * from './PageAtom';
|
||||
export * from './PinnedItems';
|
||||
export * from './SearchAtom';
|
||||
export * from './SearchReadyAtom';
|
||||
export * from './SelectedMediaFolderAtom';
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
label {
|
||||
&::after {
|
||||
content: ' *';
|
||||
@apply text-red-400;
|
||||
@apply text-[var(--vscode-editorError-foreground)];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +97,7 @@
|
||||
}
|
||||
|
||||
.ant-form-item-has-error .ant-form-item-children-icon {
|
||||
@apply absolute right-1 top-1 text-red-400;
|
||||
@apply absolute right-1 top-1 text-[var(--vscode-editorError-foreground)];
|
||||
|
||||
svg {
|
||||
@apply h-4 w-4;
|
||||
|
||||
@@ -279,8 +279,8 @@ export class ContentType {
|
||||
const configPath = await Settings.projectConfigPath();
|
||||
const notificationAction = await Notifications.info(
|
||||
overrideBool
|
||||
? l10n.t(LocalizationKey.helpersContentTypeGenerateUpdatedSuccess)
|
||||
: l10n.t(LocalizationKey.helpersContentTypeGenerateGeneratedSuccess),
|
||||
? l10n.t(LocalizationKey.helpersContentTypeGenerateUpdatedSuccess, contentTypeName)
|
||||
: l10n.t(LocalizationKey.helpersContentTypeGenerateGeneratedSuccess, contentTypeName),
|
||||
configPath && (await existsAsync(configPath))
|
||||
? l10n.t(LocalizationKey.commonOpenSettings)
|
||||
: undefined
|
||||
|
||||
@@ -397,12 +397,21 @@ export class CustomScript {
|
||||
|
||||
for (const question of data.questions) {
|
||||
if (question.name && question.message) {
|
||||
const answer = await window.showInputBox({
|
||||
prompt: question.message,
|
||||
value: question.default || '',
|
||||
ignoreFocusOut: true,
|
||||
title: question.message
|
||||
});
|
||||
let answer;
|
||||
if (question.options) {
|
||||
answer = await window.showQuickPick(question.options, {
|
||||
title: question.message,
|
||||
ignoreFocusOut: true,
|
||||
canPickMany: false
|
||||
});
|
||||
} else {
|
||||
answer = await window.showInputBox({
|
||||
prompt: question.message,
|
||||
value: question.default || '',
|
||||
ignoreFocusOut: true,
|
||||
title: question.message
|
||||
});
|
||||
}
|
||||
|
||||
if (answer) {
|
||||
answers.push(`${question.name}="${answer}"`);
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
CONTEXT,
|
||||
ExtensionState,
|
||||
SETTING_CONTENT_DRAFT_FIELD,
|
||||
SETTING_CONTENT_FILTERS,
|
||||
SETTING_CONTENT_SORTING,
|
||||
SETTING_CONTENT_SORTING_DEFAULT,
|
||||
SETTING_DASHBOARD_OPENONSTART,
|
||||
@@ -16,7 +17,6 @@ import {
|
||||
SETTING_FRAMEWORK_ID,
|
||||
SETTING_MEDIA_SORTING_DEFAULT,
|
||||
SETTING_CUSTOM_SCRIPTS,
|
||||
SETTING_TAXONOMY_CONTENT_TYPES,
|
||||
SETTING_CONTENT_SNIPPETS,
|
||||
SETTING_DATE_FORMAT,
|
||||
SETTING_DASHBOARD_CONTENT_TAGS,
|
||||
@@ -106,6 +106,7 @@ export class DashboardSettings {
|
||||
draftField: Settings.get<DraftField>(SETTING_CONTENT_DRAFT_FIELD),
|
||||
customSorting: Settings.get<SortingSetting[]>(SETTING_CONTENT_SORTING),
|
||||
contentFolders: Folders.get(),
|
||||
filters: Settings.get<string[]>(SETTING_CONTENT_FILTERS),
|
||||
crntFramework: Settings.get<string>(SETTING_FRAMEWORK_ID),
|
||||
framework: !isInitialized && wsFolder ? await FrameworkDetector.get(wsFolder.fsPath) : null,
|
||||
scripts: Settings.get<CustomScript[]>(SETTING_CUSTOM_SCRIPTS) || [],
|
||||
|
||||
@@ -67,7 +67,7 @@ export class MediaHelpers {
|
||||
)
|
||||
: sort;
|
||||
|
||||
// If the static folder is not set, retreive the last opened location
|
||||
// If the static folder is not set, retrieve the last opened location
|
||||
if (!selectedFolder) {
|
||||
const stateValue = await ext.getState<string | undefined>(
|
||||
ExtensionState.SelectedFolder,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Extension, Settings } from '.';
|
||||
import { EXTENSION_BETA_ID, EXTENSION_ID, SETTING_TELEMETRY_DISABLE } from '../constants';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const METRICS_URL = 'https://frontmatter.codes/api/metrics';
|
||||
|
||||
|
||||
@@ -127,9 +127,9 @@ export class SettingsListener extends BaseListener {
|
||||
* Update a setting from the dashboard
|
||||
* @param data
|
||||
*/
|
||||
private static async update(data: { name: string; value: any }) {
|
||||
private static async update(data: { name: string; value: any; global?: boolean }) {
|
||||
if (data.name) {
|
||||
await Settings.update(data.name, data.value);
|
||||
await Settings.update(data.name, data.value, data.global);
|
||||
this.getSettings(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import {
|
||||
COMMAND_NAME,
|
||||
CONTEXT,
|
||||
GIT_CONFIG,
|
||||
SETTING_DATE_FORMAT,
|
||||
SETTING_GIT_COMMIT_MSG,
|
||||
SETTING_GIT_ENABLED,
|
||||
SETTING_GIT_SUBMODULE_BRANCH,
|
||||
SETTING_GIT_SUBMODULE_FOLDER,
|
||||
SETTING_GIT_SUBMODULE_PULL,
|
||||
SETTING_GIT_SUBMODULE_PUSH
|
||||
} from './../../constants/settings';
|
||||
SETTING_GIT_SUBMODULE_PUSH,
|
||||
TelemetryEvent
|
||||
} from './../../constants';
|
||||
import { Settings } from './../../helpers/SettingsHelper';
|
||||
import { Dashboard } from '../../commands/Dashboard';
|
||||
import { PanelProvider } from '../../panelWebView/PanelProvider';
|
||||
@@ -17,14 +24,6 @@ import {
|
||||
} from '../../helpers';
|
||||
import { GeneralCommands } from './../../constants/GeneralCommands';
|
||||
import simpleGit, { SimpleGit } from 'simple-git';
|
||||
import {
|
||||
COMMAND_NAME,
|
||||
CONTEXT,
|
||||
SETTING_DATE_FORMAT,
|
||||
SETTING_GIT_COMMIT_MSG,
|
||||
SETTING_GIT_ENABLED,
|
||||
TelemetryEvent
|
||||
} from '../../constants';
|
||||
import { Folders } from '../../commands/Folders';
|
||||
import { commands } from 'vscode';
|
||||
import { PostMessageData } from '../../models';
|
||||
@@ -65,12 +64,24 @@ export class GitListener {
|
||||
*/
|
||||
public static process(msg: PostMessageData) {
|
||||
switch (msg.command) {
|
||||
case GeneralCommands.toVSCode.gitIsRepo:
|
||||
this.checkIsGitRepo(msg.command, msg.requestId);
|
||||
break;
|
||||
case GeneralCommands.toVSCode.gitSync:
|
||||
this.sync();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static async checkIsGitRepo(command: string, requestId?: string) {
|
||||
if (!command || !requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isRepo = await GitListener.isGitRepository();
|
||||
Dashboard.postWebviewMessage({ command: command as any, payload: isRepo, requestId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the sync
|
||||
*/
|
||||
@@ -175,7 +186,7 @@ export class GitListener {
|
||||
// Check if anything changed
|
||||
if (status.files.length > 0) {
|
||||
await subGit.raw(['add', '.', '-A']);
|
||||
await subGit.commit(commitMsg || 'Synced by Front Matter');
|
||||
await subGit.commit(commitMsg || GIT_CONFIG.defaultCommitMessage);
|
||||
}
|
||||
await subGit.push();
|
||||
} catch (e) {
|
||||
@@ -202,7 +213,7 @@ export class GitListener {
|
||||
'git',
|
||||
'commit',
|
||||
'-m',
|
||||
commitMsg || 'Synced by Front Matter'
|
||||
commitMsg || GIT_CONFIG.defaultCommitMessage
|
||||
]);
|
||||
await git.subModule(['foreach', 'git', 'push']);
|
||||
}
|
||||
@@ -222,7 +233,7 @@ export class GitListener {
|
||||
|
||||
if (status.files.length > 0) {
|
||||
await git.raw(['add', '.', '-A']);
|
||||
await git.commit(commitMsg || 'Synced by Front Matter');
|
||||
await git.commit(commitMsg || GIT_CONFIG.defaultCommitMessage);
|
||||
}
|
||||
|
||||
await git.push();
|
||||
|
||||
@@ -191,6 +191,26 @@ export enum LocalizationKey {
|
||||
* Run full diagnostics
|
||||
*/
|
||||
settingsDiagnosticLink = 'settings.diagnostic.link',
|
||||
/**
|
||||
* Git synchronization
|
||||
*/
|
||||
settingsGit = 'settings.git',
|
||||
/**
|
||||
* Enable Git synchronization to easily sync your changes with your repository.
|
||||
*/
|
||||
settingsGitEnabled = 'settings.git.enabled',
|
||||
/**
|
||||
* Commit message
|
||||
*/
|
||||
settingsGitCommitMessage = 'settings.git.commitMessage',
|
||||
/**
|
||||
* When working with Git submodules, you can refer to the submodule settings in the documentation.
|
||||
*/
|
||||
settingsGitSubmoduleInfo = 'settings.git.submoduleInfo',
|
||||
/**
|
||||
* Read more about Git submodules
|
||||
*/
|
||||
settingsGitSubmoduleLink = 'settings.git.submoduleLink',
|
||||
/**
|
||||
* Website and SSG settings
|
||||
*/
|
||||
@@ -919,6 +939,14 @@ export enum LocalizationKey {
|
||||
* Now that Front Matter knows all the content folders. Would you like to import all tags and categories from the available content?
|
||||
*/
|
||||
dashboardStepsStepsToGetStartedTagsDescription = 'dashboard.steps.stepsToGetStarted.tags.description',
|
||||
/**
|
||||
* Do you want to enable Git synchronization?
|
||||
*/
|
||||
dashboardStepsStepsToGetStartedGitName = 'dashboard.steps.stepsToGetStarted.git.name',
|
||||
/**
|
||||
* Enable Git synchronization to eaily sync your changes with your repository.
|
||||
*/
|
||||
dashboardStepsStepsToGetStartedGitDescription = 'dashboard.steps.stepsToGetStarted.git.description',
|
||||
/**
|
||||
* Show the dashboard
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_TITLE_LENGTH } from '../constants';
|
||||
import { Logger, Notifications, Settings, TaxonomyHelper } from '../helpers';
|
||||
import fetch from 'node-fetch';
|
||||
import { TagType } from '../panelWebView/TagType';
|
||||
import { TaxonomyType } from '../models';
|
||||
import * as l10n from '@vscode/l10n';
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
export const fetchWithTimeout = async (url: string, options: any, timeout = 5000) => {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"outDir": "e2e/out",
|
||||
"lib": [
|
||||
"es6",
|
||||
"dom"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"strict": false,
|
||||
"noUnusedLocals": true,
|
||||
"experimentalDecorators": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"e2e/src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"src"
|
||||
]
|
||||
}
|
||||
@@ -19,7 +19,6 @@
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
".vscode-test",
|
||||
"docs",
|
||||
"e2e"
|
||||
"docs"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user