mirror of
https://github.com/estruyf/vscode-front-matter.git
synced 2026-08-07 01:13:08 +02:00
#430 - support for post_asset_folder folder
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
|
||||
- [#406](https://github.com/estruyf/vscode-front-matter/issues/406): Added support for single data entries in the data dashboard
|
||||
- [#428](https://github.com/estruyf/vscode-front-matter/issues/428): Improved UX for inserting images to your content
|
||||
- [#430](https://github.com/estruyf/vscode-front-matter/issues/430): Support for HEXO its `post_asset_folder` setting (image location)
|
||||
- [#434](https://github.com/estruyf/vscode-front-matter/issues/434): Webview errors are logged in the extension output
|
||||
|
||||
### ⚡️ Optimizations
|
||||
|
||||
+11
-11
@@ -1,3 +1,4 @@
|
||||
import { STATIC_FOLDER_PLACEHOLDER } from './../constants/StaticFolderPlaceholder';
|
||||
import { Questions } from './../helpers/Questions';
|
||||
import { SETTING_CONTENT_PAGE_FOLDERS, SETTING_CONTENT_STATIC_FOLDER, SETTING_CONTENT_SUPPORTED_FILETYPES, TelemetryEvent } from './../constants';
|
||||
import { commands, Uri, workspace, window } from "vscode";
|
||||
@@ -43,6 +44,10 @@ export class Folders {
|
||||
startPath += "/";
|
||||
}
|
||||
|
||||
if (startPath.includes(STATIC_FOLDER_PLACEHOLDER.hexo.placeholder)) {
|
||||
startPath = startPath.replace(STATIC_FOLDER_PLACEHOLDER.hexo.placeholder, STATIC_FOLDER_PLACEHOLDER.hexo.postsFolder);
|
||||
}
|
||||
|
||||
const folderName = await window.showInputBox({
|
||||
title: `Add media folder`,
|
||||
prompt: `Which name would you like to give to your folder (use "/" to create multi-level folders)?`,
|
||||
@@ -56,22 +61,17 @@ export class Folders {
|
||||
return;
|
||||
}
|
||||
|
||||
const folders = folderName.split("/").filter(f => f);
|
||||
let parentFolders: string[] = [];
|
||||
await Folders.createFolder(join(parseWinPath(wsFolder?.fsPath || ""), folderName));
|
||||
}
|
||||
|
||||
for (const folder of folders) {
|
||||
const folderPath = join(parseWinPath(wsFolder?.fsPath || ""), parentFolders.join("/"), folder);
|
||||
|
||||
parentFolders.push(folder);
|
||||
|
||||
if (!(await existsAsync(folderPath))) {
|
||||
await mkdirAsync(folderPath);
|
||||
}
|
||||
public static async createFolder(folderPath: string) {
|
||||
if (!(await existsAsync(folderPath))) {
|
||||
await mkdirAsync(folderPath, { recursive: true });
|
||||
}
|
||||
|
||||
if (Dashboard.isOpen) {
|
||||
MediaHelpers.resetMedia();
|
||||
MediaListener.sendMediaFiles(0, folderName);
|
||||
MediaListener.sendMediaFiles(0, folderPath);
|
||||
}
|
||||
|
||||
Telemetry.send(TelemetryEvent.addMediaFolder);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
|
||||
export const STATIC_FOLDER_PLACEHOLDER = {
|
||||
hexo: {
|
||||
postsFolder: "source/_posts",
|
||||
placeholder: "hexo:post_asset_folder",
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ export * from './LocalStore';
|
||||
export * from './Navigation';
|
||||
export * from './NotificationType';
|
||||
export * from './PreviewCommands';
|
||||
export * from './StaticFolderPlaceholder';
|
||||
export * from './TelemetryEvent';
|
||||
export * from './charCode';
|
||||
export * from './charMap';
|
||||
|
||||
@@ -31,6 +31,7 @@ export enum DashboardMessage {
|
||||
updateMediaMetadata = 'updateMediaMetadata',
|
||||
createMediaFolder = 'createMediaFolder',
|
||||
insertFile = 'insertFile',
|
||||
createHexoAssetFolder = 'createHexoAssetFolder',
|
||||
|
||||
// Data dashboard
|
||||
getDataEntries = 'getDataEntries',
|
||||
|
||||
@@ -65,6 +65,8 @@ export const Item: React.FunctionComponent<IItemProps> = ({ fmFilePath, date, ti
|
||||
return [];
|
||||
}, [settings, pageData]);
|
||||
|
||||
console.log(pageData[PREVIEW_IMAGE_FIELD])
|
||||
|
||||
if (view === DashboardViewType.Grid) {
|
||||
return (
|
||||
<li className="relative">
|
||||
|
||||
@@ -2,16 +2,34 @@ import * as React from 'react';
|
||||
import {FolderAddIcon, LightningBoltIcon} from '@heroicons/react/outline';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { SelectedMediaFolderAtom, SettingsSelector } from '../../state';
|
||||
import { AllContentFoldersAtom, AllStaticFoldersAtom, SelectedMediaFolderAtom, SettingsSelector, ViewDataSelector } from '../../state';
|
||||
import { Messenger } from '@estruyf/vscode/dist/client';
|
||||
import { ChoiceButton } from '../ChoiceButton';
|
||||
import { CustomScript, ScriptType } from '../../../models';
|
||||
import { STATIC_FOLDER_PLACEHOLDER } from '../../../constants';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { extname } from 'path';
|
||||
import { parseWinPath } from '../../../helpers/parseWinPath';
|
||||
|
||||
export interface IFolderCreationProps {}
|
||||
|
||||
export const FolderCreation: React.FunctionComponent<IFolderCreationProps> = (props: React.PropsWithChildren<IFolderCreationProps>) => {
|
||||
const selectedFolder = useRecoilValue(SelectedMediaFolderAtom);
|
||||
const settings = useRecoilValue(SettingsSelector);
|
||||
const allStaticFolders = useRecoilValue(AllStaticFoldersAtom);
|
||||
const allContentFolders = useRecoilValue(AllContentFoldersAtom);
|
||||
const viewData = useRecoilValue(ViewDataSelector);
|
||||
|
||||
const hexoAssetFolderPath = useMemo(() => {
|
||||
const path = viewData?.data?.filePath?.replace(extname(viewData.data.filePath), '');
|
||||
return parseWinPath(path);
|
||||
}, [viewData?.data?.filePath]);
|
||||
|
||||
const onAssetFolderCreation = useCallback(() => {
|
||||
Messenger.send(DashboardMessage.createHexoAssetFolder, {
|
||||
hexoAssetFolderPath
|
||||
});
|
||||
}, [hexoAssetFolderPath]);
|
||||
|
||||
const onFolderCreation = () => {
|
||||
Messenger.send(DashboardMessage.createMediaFolder, {
|
||||
@@ -23,11 +41,34 @@ export const FolderCreation: React.FunctionComponent<IFolderCreationProps> = (pr
|
||||
Messenger.send(DashboardMessage.runCustomScript, {script, path: selectedFolder});
|
||||
};
|
||||
|
||||
const isHexoPostAssetsEnabled = useMemo(() => {
|
||||
if (allStaticFolders && allContentFolders && settings?.staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder && hexoAssetFolderPath) {
|
||||
return ![...allStaticFolders, ...allContentFolders].some(f => f.startsWith(hexoAssetFolderPath));
|
||||
}
|
||||
return false;
|
||||
}, [settings?.staticFolder, allStaticFolders, allContentFolders, hexoAssetFolderPath]);
|
||||
|
||||
const scripts = (settings?.scripts || []).filter(script => script.type === ScriptType.MediaFolder && !script.hidden);
|
||||
|
||||
const renderPostAssetsButton = useMemo(() => {
|
||||
if (isHexoPostAssetsEnabled) {
|
||||
return (
|
||||
<button
|
||||
className={`mr-2 inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 focus:outline-none disabled:bg-gray-500`}
|
||||
title={`Create post asset folder`}
|
||||
onClick={onAssetFolderCreation}>
|
||||
<FolderAddIcon className={`mr-2 h-6 w-6`} />
|
||||
<span className={``}>Create post asset folder</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}, [isHexoPostAssetsEnabled]);
|
||||
|
||||
if (scripts.length > 0) {
|
||||
return (
|
||||
<div className="flex flex-1 justify-end">
|
||||
{ renderPostAssetsButton }
|
||||
<ChoiceButton
|
||||
title={`Create new folder`}
|
||||
choices={scripts.map(s => ({
|
||||
@@ -43,6 +84,7 @@ export const FolderCreation: React.FunctionComponent<IFolderCreationProps> = (pr
|
||||
|
||||
return (
|
||||
<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 text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 focus:outline-none disabled:bg-gray-500`}
|
||||
title={`Create new folder`}
|
||||
|
||||
@@ -9,15 +9,16 @@ import { Item } from './Item';
|
||||
import { Lightbox } from './Lightbox';
|
||||
import { List } from './List';
|
||||
import { useDropzone } from 'react-dropzone'
|
||||
import { useCallback, useEffect } from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { DashboardMessage } from '../../DashboardMessage';
|
||||
import { FrontMatterIcon } from '../../../panelWebView/components/Icons/FrontMatterIcon';
|
||||
import { FolderItem } from './FolderItem';
|
||||
import useMedia from '../../hooks/useMedia';
|
||||
import { TelemetryEvent } from '../../../constants';
|
||||
import { STATIC_FOLDER_PLACEHOLDER, TelemetryEvent } from '../../../constants';
|
||||
import { PageLayout } from '../Layout/PageLayout';
|
||||
import { parseWinPath } from '../../../helpers/parseWinPath';
|
||||
import { basename, extname, join } from 'path';
|
||||
import { MediaInfo } from '../../../models';
|
||||
|
||||
export interface IMediaProps {}
|
||||
|
||||
@@ -29,9 +30,20 @@ export const Media: React.FunctionComponent<IMediaProps> = (props: React.PropsWi
|
||||
const folders = useRecoilValue(MediaFoldersAtom);
|
||||
const loading = useRecoilValue(LoadingAtom);
|
||||
|
||||
const contentFolders = React.useMemo(() => {
|
||||
// Check if content allows page bundle
|
||||
if (viewData && viewData.data && typeof viewData.data.pageBundle !== "undefined" && !viewData.data.pageBundle) {
|
||||
const currentStaticFolder = useMemo(() => {
|
||||
if (settings?.staticFolder) {
|
||||
let staticFolderPath = join('/', settings?.staticFolder || '', '/');
|
||||
if (settings?.staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
staticFolderPath = join('/', STATIC_FOLDER_PLACEHOLDER.hexo.postsFolder, '/');
|
||||
}
|
||||
return staticFolderPath;
|
||||
}
|
||||
return;
|
||||
}, [settings?.staticFolder])
|
||||
|
||||
const contentFolders = useMemo(() => {
|
||||
// Check if content allows page bundle or if Hexo post assets are enabled
|
||||
if (viewData && viewData.data && typeof viewData.data.pageBundle !== "undefined" && !viewData.data.pageBundle && settings?.staticFolder !== STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -46,17 +58,26 @@ export const Media: React.FunctionComponent<IMediaProps> = (props: React.PropsWi
|
||||
}
|
||||
|
||||
return groupedFolders;
|
||||
}, [folders, viewData, settings?.contentFolders]);
|
||||
}, [folders, viewData, settings?.contentFolders, settings?.staticFolder]);
|
||||
|
||||
const publicFolders = React.useMemo(() => {
|
||||
return folders.filter(f => parseWinPath(f).includes(join('/', settings?.staticFolder || '', '/')));
|
||||
}, [folders, viewData, settings?.staticFolder]);
|
||||
const publicFolders = useMemo(() => {
|
||||
if (currentStaticFolder && settings?.staticFolder !== STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
return folders.filter(f => parseWinPath(f).includes(currentStaticFolder));
|
||||
}
|
||||
|
||||
const allMedia = React.useMemo(() => {
|
||||
let mediaFiles = media;
|
||||
return undefined;
|
||||
}, [folders, viewData, currentStaticFolder, settings?.staticFolder]);
|
||||
|
||||
const allMedia = useMemo(() => {
|
||||
let mediaFiles: MediaInfo[] = Object.assign([], media);
|
||||
// Check if content allows page bundle
|
||||
if (viewData && viewData.data && typeof viewData.data.pageBundle !== "undefined" && !viewData.data.pageBundle) {
|
||||
mediaFiles = media.filter(m => parseWinPath(m.fsPath).includes(join('/', settings?.staticFolder || '', '/')));
|
||||
if (currentStaticFolder && viewData && viewData.data && typeof viewData.data.pageBundle !== "undefined" && !viewData.data.pageBundle) {
|
||||
mediaFiles = media.filter(m => parseWinPath(m.fsPath).includes(currentStaticFolder));
|
||||
}
|
||||
|
||||
// Filter if Hexo post folder
|
||||
if (currentStaticFolder && settings?.staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
mediaFiles = mediaFiles.filter(m => parseWinPath(m.fsPath).includes(currentStaticFolder));
|
||||
}
|
||||
|
||||
if (viewData && viewData.data && viewData.data.type === "file" && viewData.data.fileExtensions && viewData.data.fileExtensions.length > 0) {
|
||||
@@ -70,7 +91,7 @@ export const Media: React.FunctionComponent<IMediaProps> = (props: React.PropsWi
|
||||
}
|
||||
|
||||
return mediaFiles;
|
||||
}, [media, viewData, settings?.staticFolder]);
|
||||
}, [media, viewData, currentStaticFolder, settings?.staticFolder]);
|
||||
|
||||
const onDrop = useCallback((acceptedFiles: File[]) => {
|
||||
acceptedFiles.forEach((file) => {
|
||||
@@ -120,7 +141,7 @@ export const Media: React.FunctionComponent<IMediaProps> = (props: React.PropsWi
|
||||
<div className="absolute top-0 left-0 w-full h-full text-whisper-500 bg-gray-900 bg-opacity-70 flex flex-col justify-center items-center z-50">
|
||||
<UploadIcon className={`h-32`} />
|
||||
<p className={`text-xl max-w-md text-center`}>
|
||||
{selectedFolder ? `Upload to ${selectedFolder}` : `No folder selected, files you drop will be added to the ${settings?.staticFolder || "public"} folder.`}
|
||||
{selectedFolder ? `Upload to ${selectedFolder}` : `No folder selected, files you drop will be added to the ${currentStaticFolder || "public"} folder.`}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
@@ -132,7 +153,7 @@ export const Media: React.FunctionComponent<IMediaProps> = (props: React.PropsWi
|
||||
<div className={`max-w-xl text-center`}>
|
||||
<FrontMatterIcon className={`text-vulcan-300 dark:text-whisper-800 h-32 mx-auto opacity-90 mb-8`} />
|
||||
|
||||
<p className={`text-xl font-medium`}>No media files to show. You can drag & drop new files.</p>
|
||||
<p className={`text-xl font-medium`}>No media files to show. You can drag & drop new files by holding your [shift] key.</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -147,7 +168,7 @@ export const Media: React.FunctionComponent<IMediaProps> = (props: React.PropsWi
|
||||
<List gap={0}>
|
||||
{
|
||||
group.folders.map((folder) => (
|
||||
<FolderItem key={folder} folder={folder} staticFolder={settings?.staticFolder} wsFolder={settings?.wsFolder} />
|
||||
<FolderItem key={folder} folder={folder} staticFolder={currentStaticFolder} wsFolder={settings?.wsFolder} />
|
||||
))
|
||||
}
|
||||
</List>
|
||||
@@ -160,13 +181,13 @@ export const Media: React.FunctionComponent<IMediaProps> = (props: React.PropsWi
|
||||
publicFolders && publicFolders.length > 0 && (
|
||||
<div className={`mb-8`}>
|
||||
{
|
||||
contentFolders && contentFolders.length > 0 && (<h2 className='text-lg mb-8'>Public folder{settings?.staticFolder && (<span>: <b>{settings?.staticFolder}</b></span>)}</h2>)
|
||||
contentFolders && contentFolders.length > 0 && (<h2 className='text-lg mb-8'>Public folder{currentStaticFolder && (<span>: <b>{currentStaticFolder}</b></span>)}</h2>)
|
||||
}
|
||||
|
||||
<List gap={0}>
|
||||
{
|
||||
publicFolders.map((folder) => (
|
||||
<FolderItem key={folder} folder={folder} staticFolder={settings?.staticFolder} wsFolder={settings?.wsFolder} />
|
||||
<FolderItem key={folder} folder={folder} staticFolder={currentStaticFolder} wsFolder={settings?.wsFolder} />
|
||||
))
|
||||
}
|
||||
</List>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useState, useEffect, useCallback } from 'react';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { MediaInfo, MediaPaths } from '../../models';
|
||||
import { DashboardCommand } from '../DashboardCommand';
|
||||
import { LoadingAtom, MediaFoldersAtom, MediaTotalAtom, PageAtom, SearchAtom, SelectedMediaFolderAtom, SettingsAtom } from '../state';
|
||||
import { AllContentFoldersAtom, AllStaticFoldersAtom, LoadingAtom, MediaFoldersAtom, MediaTotalAtom, PageAtom, SearchAtom, SelectedMediaFolderAtom, SettingsAtom } from '../state';
|
||||
import Fuse from 'fuse.js';
|
||||
import usePagination from './usePagination';
|
||||
|
||||
@@ -26,6 +26,8 @@ export default function useMedia() {
|
||||
const [ , setSelectedFolder ] = useRecoilState(SelectedMediaFolderAtom);
|
||||
const [ , setTotal ] = useRecoilState(MediaTotalAtom);
|
||||
const [ , setFolders ] = useRecoilState(MediaFoldersAtom);
|
||||
const [ , setAllContentFolders ] = useRecoilState(AllContentFoldersAtom);
|
||||
const [ , setAllStaticFolders ] = useRecoilState(AllStaticFoldersAtom);
|
||||
const [ , setLoading ] = useRecoilState(LoadingAtom);
|
||||
const search = useRecoilValue(SearchAtom);
|
||||
const settings = useRecoilValue(SettingsAtom);
|
||||
@@ -44,6 +46,8 @@ export default function useMedia() {
|
||||
setFolders(data.folders);
|
||||
setSelectedFolder(data.selectedFolder);
|
||||
setSearchedMedia(data.media);
|
||||
setAllContentFolders(data.allContentFolders);
|
||||
setAllStaticFolders(data.allStaticfolders);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const AllContentFoldersAtom = atom<string[] | undefined>({
|
||||
key: 'AllContentFoldersAtom',
|
||||
default: undefined
|
||||
});
|
||||
@@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const AllStaticFoldersAtom = atom<string[] | undefined>({
|
||||
key: 'AllStaticFoldersAtom',
|
||||
default: undefined
|
||||
});
|
||||
@@ -1,3 +1,5 @@
|
||||
export * from './AllContentFoldersAtom';
|
||||
export * from './AllStaticFoldersAtom';
|
||||
export * from './CategoryAtom';
|
||||
export * from './DashboardViewAtom';
|
||||
export * from './FolderAtom';
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { parseWinPath } from './parseWinPath';
|
||||
import * as jsoncParser from 'jsonc-parser';
|
||||
import jsyaml = require("js-yaml");
|
||||
import { join, resolve } from "path";
|
||||
import { commands, Uri } from "vscode";
|
||||
import { Folders } from "../commands/Folders";
|
||||
import { COMMAND_NAME } from "../constants";
|
||||
import { COMMAND_NAME, SETTING_CONTENT_STATIC_FOLDER, SETTING_FRAMEWORK_ID, STATIC_FOLDER_PLACEHOLDER } from "../constants";
|
||||
import { FrameworkDetectors } from "../constants/FrameworkDetectors";
|
||||
import { Framework } from "../models";
|
||||
import { Logger } from "./Logger";
|
||||
import { existsAsync, readFileAsync } from '../utils';
|
||||
import { Settings } from '.';
|
||||
import { parse } from 'path';
|
||||
|
||||
export class FrameworkDetector {
|
||||
|
||||
@@ -84,10 +87,76 @@ export class FrameworkDetector {
|
||||
public static async checkDefaultSettings(framework: Framework) {
|
||||
if (framework.name.toLowerCase() === "jekyll") {
|
||||
await FrameworkDetector.jekyll();
|
||||
} else if (framework.name.toLowerCase() === "hexo") {
|
||||
await FrameworkDetector.hexo();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are any changes for the current framework that need to be applied
|
||||
* @param relAssetPath
|
||||
* @param filePath
|
||||
*/
|
||||
public static relAssetPathUpdate(relAssetPath: string, filePath: string): string {
|
||||
const staticFolder = Folders.getStaticFolderRelativePath();
|
||||
const frameworkId = Settings.get(SETTING_FRAMEWORK_ID);
|
||||
|
||||
// Support for HEXO post asset folders
|
||||
if (staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
relAssetPath = relAssetPath.replace(STATIC_FOLDER_PLACEHOLDER.hexo.postsFolder, "");
|
||||
|
||||
// Filename without the extension
|
||||
const fileParsing = parse(filePath);
|
||||
const name = fileParsing.name;
|
||||
relAssetPath = relAssetPath.replace(name, "");
|
||||
relAssetPath = join(relAssetPath);
|
||||
|
||||
// Remove remove the slash at the beginning
|
||||
relAssetPath = parseWinPath(relAssetPath);
|
||||
if (relAssetPath.startsWith("/")) {
|
||||
relAssetPath = relAssetPath.substring(1);
|
||||
}
|
||||
}
|
||||
// Support for HEXO image folder
|
||||
else if (frameworkId === "hexo") {
|
||||
relAssetPath = parseWinPath(relAssetPath);
|
||||
if (relAssetPath.startsWith("/")) {
|
||||
relAssetPath = relAssetPath.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
return parseWinPath(relAssetPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the default settings for Hexo
|
||||
*/
|
||||
private static async hexo() {
|
||||
try {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const hexoConfig = join(wsFolder?.fsPath || "", '_config.yml');
|
||||
let assetFoler = "source/images";
|
||||
|
||||
if (await existsAsync(hexoConfig)) {
|
||||
const content = await readFileAsync(hexoConfig, "utf8");
|
||||
// Convert YAML to JSON
|
||||
const config = jsyaml.safeLoad(content);
|
||||
|
||||
// Check if post assets are used: https://hexo.io/docs/asset-folders.html#Post-Asset-Folder
|
||||
if (config.post_asset_folder) {
|
||||
assetFoler = STATIC_FOLDER_PLACEHOLDER.hexo.placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
await Settings.update(SETTING_CONTENT_STATIC_FOLDER, assetFoler, true);
|
||||
} catch (e) {
|
||||
Logger.error(`Something failed while processing your Hexo configuration. ${(e as Error).message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the default settings for Jekyll
|
||||
*/
|
||||
private static async jekyll() {
|
||||
try {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { STATIC_FOLDER_PLACEHOLDER } from './../constants/StaticFolderPlaceholder';
|
||||
import { ExplorerView } from './../explorerView/ExplorerView';
|
||||
import { Uri, window } from 'vscode';
|
||||
import { dirname, join } from "path";
|
||||
import { dirname, extname, join } from "path";
|
||||
import { Field } from '../models';
|
||||
import { existsSync } from 'fs';
|
||||
import { Folders } from '../commands/Folders';
|
||||
@@ -49,7 +50,21 @@ export class ImageHelper {
|
||||
*/
|
||||
public static relToAbs(filePath: string, value: string) {
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const staticFolder = Folders.getStaticFolderRelativePath();
|
||||
let staticFolder = Folders.getStaticFolderRelativePath();
|
||||
|
||||
if (staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
const editor = window.activeTextEditor;
|
||||
if (editor) {
|
||||
const document = editor.document;
|
||||
const filePath = parseWinPath(document.fileName);
|
||||
const pathWithoutExtension = filePath.replace(extname(filePath), '');
|
||||
const assetFilePath = join(pathWithoutExtension, value);
|
||||
|
||||
if (existsSync(assetFilePath)) {
|
||||
return Uri.file(assetFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const staticPath = join(parseWinPath(wsFolder?.fsPath || ""), staticFolder || "", value);
|
||||
const contentFolderPath = filePath ? join(dirname(filePath), value) : null;
|
||||
|
||||
+43
-21
@@ -1,4 +1,5 @@
|
||||
import { decodeBase64, Extension, MediaLibrary, Notifications, parseWinPath, Settings, Sorting } from ".";
|
||||
import { STATIC_FOLDER_PLACEHOLDER } from './../constants/StaticFolderPlaceholder';
|
||||
import { decodeBase64, Extension, FrameworkDetector, MediaLibrary, Notifications, parseWinPath, Settings, Sorting } from ".";
|
||||
import { Dashboard } from "../commands/Dashboard";
|
||||
import { Folders } from "../commands/Folders";
|
||||
import { DEFAULT_CONTENT_TYPE, ExtensionState, HOME_PAGE_NAVIGATION_ID, SETTING_MEDIA_SUPPORTED_MIMETYPES } from "../constants";
|
||||
@@ -78,11 +79,17 @@ export class MediaHelpers {
|
||||
|
||||
allMedia = [...media];
|
||||
} else {
|
||||
if (staticFolder) {
|
||||
if (staticFolder && staticFolder !== STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
const folderSearch = join(staticFolder || "", '/*');
|
||||
const files = await workspace.findFiles(folderSearch);
|
||||
const media = await MediaHelpers.updateMediaData(MediaHelpers.filterMedia(files));
|
||||
|
||||
allMedia = [...media];
|
||||
} else if (staticFolder && staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
const folderSearch = join(STATIC_FOLDER_PLACEHOLDER.hexo.postsFolder, '/*');
|
||||
const files = await workspace.findFiles(folderSearch);
|
||||
const media = await MediaHelpers.updateMediaData(MediaHelpers.filterMedia(files));
|
||||
|
||||
allMedia = [...media];
|
||||
}
|
||||
|
||||
@@ -150,31 +157,40 @@ export class MediaHelpers {
|
||||
let allContentFolders: string[] = [];
|
||||
let allFolders: string[] = [];
|
||||
|
||||
let foldersFromSelection: string[] = [];
|
||||
|
||||
if (selectedFolder) {
|
||||
if (await existsAsync(selectedFolder)) {
|
||||
allFolders = (await readdirAsync(selectedFolder, { withFileTypes: true })).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(selectedFolder, dir.name)));
|
||||
foldersFromSelection = (await readdirAsync(selectedFolder, { withFileTypes: true })).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(selectedFolder, dir.name)));
|
||||
}
|
||||
} else {
|
||||
if (pageBundleContentTypes.length > 0) {
|
||||
for (const contentFolder of contentFolders) {
|
||||
const contentPath = contentFolder.path;
|
||||
if (contentPath && await existsAsync(contentPath)) {
|
||||
const subFolders = (await readdirAsync(contentPath, { withFileTypes: true })).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(contentPath, dir.name)));
|
||||
allContentFolders = [...allContentFolders, ...subFolders];
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve all the content folders
|
||||
if (pageBundleContentTypes.length > 0) {
|
||||
for (const contentFolder of contentFolders) {
|
||||
const contentPath = contentFolder.path;
|
||||
if (contentPath && await existsAsync(contentPath)) {
|
||||
const subFolders = (await readdirAsync(contentPath, { withFileTypes: true })).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(contentPath, dir.name)));
|
||||
allContentFolders = [...allContentFolders, ...subFolders];
|
||||
}
|
||||
}
|
||||
|
||||
const staticPath = join(parseWinPath(wsFolder?.fsPath || ""), staticFolder || "");
|
||||
if (staticPath && await existsAsync(staticPath)) {
|
||||
allFolders = (await readdirAsync(staticPath, { withFileTypes: true })).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(staticPath, dir.name)));
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve all the static folders
|
||||
let staticPath = join(parseWinPath(wsFolder?.fsPath || ""), staticFolder || "");
|
||||
if (staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
staticPath = join(parseWinPath(wsFolder?.fsPath || ""), STATIC_FOLDER_PLACEHOLDER.hexo.postsFolder);
|
||||
}
|
||||
|
||||
if (staticPath && await existsAsync(staticPath)) {
|
||||
allFolders = (await readdirAsync(staticPath, { withFileTypes: true })).filter(dir => dir.isDirectory()).map(dir => parseWinPath(join(staticPath, dir.name)));
|
||||
}
|
||||
|
||||
// Store the last opened folder
|
||||
await Extension.getInstance().setState(ExtensionState.SelectedFolder, requestedFolder === HOME_PAGE_NAVIGATION_ID ? HOME_PAGE_NAVIGATION_ID : selectedFolder, "workspace");
|
||||
|
||||
let sortedFolders = [...allContentFolders, ...allFolders];
|
||||
let sortedFolders = selectedFolder ? foldersFromSelection : [...allContentFolders, ...allFolders];
|
||||
|
||||
sortedFolders = sortedFolders.sort((a, b) => {
|
||||
if (a.toLowerCase() < b.toLowerCase()) {
|
||||
return -1;
|
||||
@@ -193,7 +209,9 @@ export class MediaHelpers {
|
||||
media: files,
|
||||
total: total,
|
||||
folders: sortedFolders,
|
||||
selectedFolder
|
||||
selectedFolder,
|
||||
allContentFolders,
|
||||
allStaticfolders: allFolders,
|
||||
} as MediaPaths
|
||||
}
|
||||
|
||||
@@ -276,6 +294,10 @@ export class MediaHelpers {
|
||||
Dashboard.resetViewData();
|
||||
|
||||
const editor = window.activeTextEditor;
|
||||
if (!editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
const wsFolder = Folders.getWorkspaceFolder();
|
||||
const filePath = data.file;
|
||||
let relPath = data.relPath;
|
||||
@@ -304,7 +326,7 @@ export class MediaHelpers {
|
||||
|
||||
// Snippets are already parsed, so update the URL of the image
|
||||
if (data.snippet) {
|
||||
data.snippet = data.snippet.replace(data.relPath, relPath);
|
||||
data.snippet = data.snippet.replace(data.relPath, FrameworkDetector.relAssetPathUpdate(relPath, editor.document.fileName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,7 +347,7 @@ export class MediaHelpers {
|
||||
|
||||
const caption = isFile ? `${data.title || ""}` : `${data.alt || data.caption || ""}`;
|
||||
|
||||
const snippet = data.snippet || `${isFile ? "" : "!"}[${caption}](${relPath.replace(/ /g, "%20")})`;
|
||||
const snippet = data.snippet || `${isFile ? "" : "!"}[${caption}](${FrameworkDetector.relAssetPathUpdate(relPath, editor.document.fileName).replace(/ /g, "%20")})`;
|
||||
if (selection !== undefined) {
|
||||
builder.replace(selection, snippet);
|
||||
} else {
|
||||
@@ -339,7 +361,7 @@ export class MediaHelpers {
|
||||
|
||||
DataListener.updateMetadata({
|
||||
field: data.fieldName,
|
||||
value: relPath,
|
||||
value: FrameworkDetector.relAssetPathUpdate(relPath, editor.document.fileName),
|
||||
parents: data.parents,
|
||||
blockData: data.blockData
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import { SortingOption } from '../../dashboardWebView/models';
|
||||
import { commands, env, Uri } from 'vscode';
|
||||
import { COMMAND_NAME, TelemetryEvent } from '../../constants';
|
||||
import * as os from 'os';
|
||||
import { Folders } from '../../commands';
|
||||
|
||||
|
||||
export class MediaListener extends BaseListener {
|
||||
@@ -51,6 +52,11 @@ export class MediaListener extends BaseListener {
|
||||
case DashboardMessage.createMediaFolder:
|
||||
await commands.executeCommand(COMMAND_NAME.createFolder, msg?.data);
|
||||
break;
|
||||
case DashboardMessage.createHexoAssetFolder:
|
||||
if (msg?.data.hexoAssetFolderPath) {
|
||||
Folders.createFolder(msg?.data.hexoAssetFolderPath);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,9 @@ export class SettingsListener extends BaseListener {
|
||||
const allFrameworks = FrameworkDetector.getAll();
|
||||
const framework = allFrameworks.find((f: Framework) => f.name === frameworkId);
|
||||
if (framework) {
|
||||
await Settings.update(SETTING_CONTENT_STATIC_FOLDER, framework.static, true);
|
||||
if (framework.static) {
|
||||
await Settings.update(SETTING_CONTENT_STATIC_FOLDER, framework.static, true);
|
||||
}
|
||||
|
||||
await FrameworkDetector.checkDefaultSettings(framework);
|
||||
} else {
|
||||
|
||||
@@ -4,6 +4,8 @@ export interface MediaPaths {
|
||||
media: MediaInfo[];
|
||||
total: number;
|
||||
folders: string[];
|
||||
allContentFolders: string[];
|
||||
allStaticfolders: string[];
|
||||
selectedFolder: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { STATIC_FOLDER_PLACEHOLDER } from './../constants/StaticFolderPlaceholder';
|
||||
import { parseWinPath } from './../helpers/parseWinPath';
|
||||
import { dirname, join } from "path";
|
||||
import { dirname, extname, join } from "path";
|
||||
import { StatusBarAlignment, Uri, window } from "vscode";
|
||||
import { Dashboard } from "../commands/Dashboard";
|
||||
import { Folders } from "../commands/Folders";
|
||||
@@ -236,7 +237,14 @@ export class PagesParser {
|
||||
|
||||
// Revalidate as the array could have been empty
|
||||
if (fieldValue) {
|
||||
const staticPath = join(wsFolder.fsPath, staticFolder || "", fieldValue);
|
||||
let staticPath = join(wsFolder.fsPath, staticFolder || "", fieldValue);
|
||||
|
||||
if (staticFolder === STATIC_FOLDER_PLACEHOLDER.hexo.placeholder) {
|
||||
const crntFilePath = parseWinPath(filePath)
|
||||
const pathWithoutExtension = crntFilePath.replace(extname(crntFilePath), '');
|
||||
staticPath = join(pathWithoutExtension, fieldValue);
|
||||
}
|
||||
|
||||
const contentFolderPath = join(dirname(filePath), fieldValue);
|
||||
|
||||
let previewUri = null;
|
||||
|
||||
Reference in New Issue
Block a user