mirror of
https://github.com/eatcodeplay/obsidian-simple-banner.git
synced 2026-07-22 05:48:13 +00:00
initial code commit
This commit is contained in:
parent
3bc549e519
commit
e8e21ddee8
18 changed files with 4365 additions and 0 deletions
10
.editorconfig
Normal file
10
.editorconfig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
tab_width = 2
|
||||
1
.env.dist
Normal file
1
.env.dist
Normal file
|
|
@ -0,0 +1 @@
|
|||
VAULT_PLUGIN_PATH=/path/to/your/.obsidian/plugins/your-plugin
|
||||
3
.eslintignore
Normal file
3
.eslintignore
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
node_modules/
|
||||
|
||||
main.js
|
||||
23
.eslintrc
Normal file
23
.eslintrc
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": { "node": true },
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off"
|
||||
}
|
||||
}
|
||||
34
.github/workflows/release.yml
vendored
Normal file
34
.github/workflows/release.yml
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
name: Release Obsidian plugin
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "20.x"
|
||||
|
||||
- name: Build plugin
|
||||
run: |
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
- name: Create release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
tag="${GITHUB_REF#refs/tags/}"
|
||||
|
||||
gh release create "$tag" \
|
||||
--title="$tag" \
|
||||
dist/main.js manifest.json dist/styles.css
|
||||
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
.vscode
|
||||
.idea
|
||||
.DS_Store
|
||||
.env
|
||||
*.iml
|
||||
*.map
|
||||
node_modules
|
||||
dist
|
||||
data.json
|
||||
1
.npmrc
Normal file
1
.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
|||
tag-version-prefix=""
|
||||
30
assets/snippet.css
Normal file
30
assets/snippet.css
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* -------------------------------
|
||||
Source / Live View Styles
|
||||
------------------------------- */
|
||||
|
||||
/* Styles the cells of a table with calculated values */
|
||||
div.markdown-rendered table.table-editor tr > td.stm-cell.stm-value,
|
||||
div.markdown-rendered table.table-editor tr > td.stm-cell > .stm-value {
|
||||
padding: var(--size-2-2) var(--size-4-2); /* must be the same as the original .table-cell-wrapper */
|
||||
font-weight: calc(var(--font-weight) + var(--bold-modifier));
|
||||
}
|
||||
|
||||
/* Styles the last row of a table with calculated values */
|
||||
div.markdown-rendered table.table-editor tr.stm-row:last-of-type:not(.off) {
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
|
||||
/* -------------------------------
|
||||
Reading View Styles
|
||||
------------------------------- */
|
||||
|
||||
/* Styles the cells of a table with calculated values */
|
||||
div.el-table > table tr.stm-row > td.stm-cell.stm-value,
|
||||
div.el-table > table tr.stm-row > td.stm-cell > .stm-value {
|
||||
font-weight: calc(var(--font-weight) + var(--bold-modifier));
|
||||
}
|
||||
|
||||
/* Styles the last row of a table with calculated values */
|
||||
div.el-table > table tr.stm-row:last-of-type:not(.off) {
|
||||
background-color: var(--background-secondary);
|
||||
}
|
||||
72
esbuild.config.mjs
Normal file
72
esbuild.config.mjs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import esbuild from 'esbuild';
|
||||
import process from 'process';
|
||||
import builtins from 'builtin-modules';
|
||||
import { sassPlugin } from 'esbuild-sass-plugin';
|
||||
import { cp } from 'node:fs/promises';
|
||||
import 'dotenv/config';
|
||||
|
||||
const banner =
|
||||
`/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
`;
|
||||
|
||||
const prod = (process.argv[2] === 'production');
|
||||
const vaultCopy = {
|
||||
name: 'vault-copy',
|
||||
setup(build) {
|
||||
build.onEnd(async () => {
|
||||
const vaultPluginPath = process.env.VAULT_PLUGIN_PATH;
|
||||
if (vaultPluginPath) {
|
||||
try {
|
||||
await Promise.all([
|
||||
cp('dist/main.js', `${vaultPluginPath}/main.js`, { overwrite: true }),
|
||||
cp('manifest.json', `${vaultPluginPath}/manifest.json`, { overwrite: true }),
|
||||
cp('dist/styles.css', `${vaultPluginPath}/styles.css`, { overwrite: true }),
|
||||
]);
|
||||
} catch (copyError) {
|
||||
console.error('Error copying files:', copyError);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const context = await esbuild.context({
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
entryPoints: ['src/main.ts', 'src/styles.scss'],
|
||||
bundle: true,
|
||||
external: [
|
||||
'obsidian',
|
||||
'electron',
|
||||
'@codemirror/autocomplete',
|
||||
'@codemirror/collab',
|
||||
'@codemirror/commands',
|
||||
'@codemirror/language',
|
||||
'@codemirror/lint',
|
||||
'@codemirror/search',
|
||||
'@codemirror/state',
|
||||
'@codemirror/view',
|
||||
'@lezer/common',
|
||||
'@lezer/highlight',
|
||||
'@lezer/lr',
|
||||
...builtins],
|
||||
format: 'cjs',
|
||||
target: 'es2018',
|
||||
logLevel: 'info',
|
||||
sourcemap: prod ? false : 'inline',
|
||||
treeShaking: true,
|
||||
outdir: 'dist',
|
||||
plugins: [sassPlugin(), vaultCopy],
|
||||
minify: prod,
|
||||
});
|
||||
|
||||
if (prod) {
|
||||
await context.rebuild();
|
||||
process.exit(0);
|
||||
} else {
|
||||
await context.watch();
|
||||
}
|
||||
10
manifest.json
Normal file
10
manifest.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"id": "simple-banner",
|
||||
"name": "Simple Banner",
|
||||
"version": "0.1.0",
|
||||
"minAppVersion": "1.8.9",
|
||||
"description": "Simply add a banner image.",
|
||||
"author": "Sandro Ducceschi",
|
||||
"authorUrl": "https://eatcodeplay.dev",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
3104
package-lock.json
generated
Normal file
3104
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
33
package.json
Normal file
33
package.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "simple-banner",
|
||||
"version": "0.1.0",
|
||||
"description": "Simply add a banner image",
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
"test": "tsc -noEmit -skipLibCheck",
|
||||
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
|
||||
"version": "node version-bump.mjs && git add manifest.json versions.json"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.x"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "Sandro Ducceschi",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"dotenv": "^16.5.0",
|
||||
"esbuild": "0.17.3",
|
||||
"esbuild-sass-plugin": "2.4.5",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
||||
7
src/ContainerComponent.ts
Normal file
7
src/ContainerComponent.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import {BaseComponent} from "obsidian";
|
||||
|
||||
export class ContainerComponent extends BaseComponent {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
676
src/main.ts
Normal file
676
src/main.ts
Normal file
|
|
@ -0,0 +1,676 @@
|
|||
import {
|
||||
App,
|
||||
debounce,
|
||||
MarkdownView,
|
||||
Platform,
|
||||
Plugin,
|
||||
PluginSettingTab,
|
||||
Setting,
|
||||
TFile,
|
||||
Workspace,
|
||||
WorkspaceLeaf,
|
||||
} from 'obsidian';
|
||||
|
||||
//----------------------------------
|
||||
// Interfaces
|
||||
//----------------------------------
|
||||
interface SimpleBannerSettings {
|
||||
offset: number;
|
||||
radius: Array<number>;
|
||||
padding: number;
|
||||
fade: boolean;
|
||||
desktopHeight: number;
|
||||
tabletHeight: number;
|
||||
mobileHeight: number;
|
||||
propertyName: string;
|
||||
}
|
||||
|
||||
const DEFAULT_SETTINGS: SimpleBannerSettings = {
|
||||
offset: -32,
|
||||
radius: [8, 8, 8, 8],
|
||||
padding: 8,
|
||||
fade: true,
|
||||
desktopHeight: 240,
|
||||
mobileHeight: 160,
|
||||
tabletHeight: 190,
|
||||
propertyName: 'banner',
|
||||
}
|
||||
|
||||
interface BannerData {
|
||||
path: string | null;
|
||||
value: string | null;
|
||||
isNewValue: boolean;
|
||||
isUpdate: boolean;
|
||||
viewMode: ViewMode | null;
|
||||
lastViewMode: ViewMode | null;
|
||||
container: HTMLElement | null;
|
||||
}
|
||||
|
||||
interface BannerOptions {
|
||||
x: number;
|
||||
y: number;
|
||||
repeatable: boolean;
|
||||
}
|
||||
|
||||
enum ViewMode {
|
||||
Source = 'source',
|
||||
Reading = 'preview',
|
||||
}
|
||||
|
||||
export default class SimpleBanner extends Plugin {
|
||||
//---------------------------------------------------
|
||||
//
|
||||
// Variables
|
||||
//
|
||||
//---------------------------------------------------
|
||||
workspace: Workspace;
|
||||
settings: SimpleBannerSettings;
|
||||
boundProcess: () => void;
|
||||
|
||||
//---------------------------------------------------
|
||||
//
|
||||
// Plugin Lifecycle
|
||||
//
|
||||
//---------------------------------------------------
|
||||
async onload() {
|
||||
this.workspace = this.app.workspace;
|
||||
|
||||
await this.loadSettings();
|
||||
this.addSettingTab(new SettingTab(this.app, this));
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
this.applySettings();
|
||||
this.boundProcess = debounce(this.process.bind(this), 50);
|
||||
this.registerEvent(this.workspace.on('layout-change', this.boundProcess));
|
||||
this.registerEvent(this.workspace.on('file-open', this.handleFileEvents.bind(this)));
|
||||
this.registerEvent(this.app.metadataCache.on('changed', this.handleMetaEvents.bind(this)));
|
||||
this.processAll();
|
||||
});
|
||||
}
|
||||
|
||||
onunload() {
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
//---------------------------------------------------
|
||||
|
||||
processAll() {
|
||||
this.app.workspace.iterateRootLeaves((leaf: WorkspaceLeaf) => {
|
||||
const view = leaf.view as MarkdownView;
|
||||
if (view) {
|
||||
const file = view.file as TFile || null;
|
||||
const options = this.computeBannerData(file, view);
|
||||
this.process(options || null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
process(options?: BannerData | null) {
|
||||
const opts = options || this.computeBannerData();
|
||||
if (!opts) {
|
||||
return;
|
||||
}
|
||||
if (!opts.value) {
|
||||
this.removeBanner();
|
||||
return;
|
||||
}
|
||||
this.updateBanner(opts);
|
||||
}
|
||||
|
||||
updateBanner(options: BannerData) {
|
||||
const propsContainer = document.querySelector('.metadata-container');
|
||||
if (propsContainer) {
|
||||
const parent = propsContainer.parentNode;
|
||||
if (parent && parent.firstChild !== propsContainer) {
|
||||
parent.prepend(propsContainer);
|
||||
}
|
||||
}
|
||||
|
||||
const { value, isNewValue, isUpdate, viewMode, lastViewMode, container } = options;
|
||||
if (lastViewMode !== viewMode || isNewValue) {
|
||||
if (container && isNewValue) {
|
||||
const view = this.getActiveView();
|
||||
const containers = container.querySelectorAll('.markdown-preview-view, .cm-scroller');
|
||||
containers.forEach((c) => {
|
||||
let element = (c.querySelector('.simple-banner') || document.createElement('div')) as HTMLElement;
|
||||
element.classList.add('simple-banner');
|
||||
|
||||
if (isNewValue) {
|
||||
const { url, repeatable, x, y } = this.parseLinkString(value || '', view);
|
||||
|
||||
element.classList.remove('static');
|
||||
this.setCSSVariable('--smpbn-url', `url(${url}`, container);
|
||||
this.setCSSVariable('--smpbn-img-x', `${x}px`, container);
|
||||
this.setCSSVariable('--smpbn-img-y', `${y}px`, container);
|
||||
this.setCSSVariable('--smpbn-size', repeatable ? 'auto' : 'cover', container);
|
||||
this.setCSSVariable('--smpbn-repeat', repeatable ? 'repeat' : 'no-repeat', container);
|
||||
|
||||
if (isUpdate) {
|
||||
element.classList.add('static');
|
||||
} else {
|
||||
c.prepend(element);
|
||||
element.onanimationend = () => {
|
||||
const banners = document.querySelectorAll('.simple-banner');
|
||||
banners.forEach(b => b.classList.add('static'));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
options.isNewValue = false;
|
||||
options.lastViewMode = viewMode;
|
||||
container.dataset.sb = JSON.stringify(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeBanner() {
|
||||
const options = this.computeBannerData();
|
||||
const container = options?.container;
|
||||
if (options && container) {
|
||||
const targets = container.querySelectorAll('.simple-banner');
|
||||
targets.forEach((t) => { t.remove() });
|
||||
options.lastViewMode = null;
|
||||
options.value = null;
|
||||
delete container.dataset.sb;
|
||||
}
|
||||
}
|
||||
|
||||
computeBannerData(newfile?: TFile, targetView?: MarkdownView): BannerData | null {
|
||||
const view = targetView || this.getActiveView();
|
||||
if (view instanceof MarkdownView) {
|
||||
const viewMode = view.getMode() || null;
|
||||
const defaultOptions = this.createDefaultBannerData();
|
||||
let oldopt: BannerData | null = defaultOptions;
|
||||
const container = view.containerEl;
|
||||
if (container?.dataset.sb) {
|
||||
oldopt = JSON.parse(container.dataset.sb) as BannerData || defaultOptions;
|
||||
}
|
||||
if (newfile && newfile.path !== view?.file?.path) {
|
||||
oldopt = defaultOptions;
|
||||
}
|
||||
|
||||
const opt = {
|
||||
path: null,
|
||||
value: null,
|
||||
isNewValue: false,
|
||||
isUpdate: false,
|
||||
viewMode: (viewMode === ViewMode.Reading) ? ViewMode.Reading : ViewMode.Source,
|
||||
lastViewMode: oldopt.viewMode,
|
||||
container: view.containerEl,
|
||||
} as BannerData;
|
||||
|
||||
const file = view?.file || null;
|
||||
if (file) {
|
||||
const cachedMetadata = this.app.metadataCache.getFileCache(file);
|
||||
const propName = this.settings.propertyName;
|
||||
const frontmatter = cachedMetadata?.frontmatter;
|
||||
if (frontmatter && frontmatter[propName]) {
|
||||
opt.value = frontmatter[propName];
|
||||
opt.path = file.path;
|
||||
if (oldopt.value !== opt.value) {
|
||||
opt.isNewValue = true;
|
||||
if (this.isOptionsUpdate(oldopt.value, opt.value, view)) {
|
||||
opt.isUpdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// Settings Methods
|
||||
//----------------------------------
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
this.applySettings();
|
||||
}
|
||||
|
||||
applySettings() {
|
||||
let height = this.settings.desktopHeight;
|
||||
if (Platform.isTablet) {
|
||||
height = this.settings.tabletHeight;
|
||||
} else if (Platform.isMobile) {
|
||||
height = this.settings.mobileHeight;
|
||||
}
|
||||
|
||||
const offset = this.settings.offset;
|
||||
const radius = this.settings.radius;
|
||||
const padding = this.settings.padding;
|
||||
const fade = this.settings.fade;
|
||||
|
||||
this.setCSSVariable('--smpbn-height', `${height}px`);
|
||||
this.setCSSVariable('--smpbn-note-offset', `${offset}px`);
|
||||
this.setCSSVariable('--smpbn-radius', `${radius[0]}px ${radius[1]}px ${radius[2]}px ${radius[3]}px`);
|
||||
this.setCSSVariable('--smpbn-padding', `${padding}px`);
|
||||
this.setCSSVariable('--smpbn-fade', 'none');
|
||||
if (fade) {
|
||||
this.setCSSVariable(
|
||||
'--smpbn-fade',
|
||||
`linear-gradient(to bottom, black calc(100% + -75%), transparent)`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// Event Handlers
|
||||
//----------------------------------
|
||||
handleFileEvents(file: TFile) {
|
||||
const options = this.computeBannerData(file);
|
||||
const container = options?.container;
|
||||
if (options && container && file.path !== options.path) {
|
||||
options.lastViewMode = null;
|
||||
delete container.dataset.sb;
|
||||
this.boundProcess();
|
||||
}
|
||||
}
|
||||
|
||||
async handleMetaEvents(file: TFile) {
|
||||
this.app.workspace.iterateRootLeaves((leaf: WorkspaceLeaf) => {
|
||||
const view = leaf.view as MarkdownView;
|
||||
if (view.file === file) {
|
||||
const options = this.computeBannerData(file, view);
|
||||
this.process(options || null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// Helper Methods
|
||||
//----------------------------------
|
||||
getActiveView(): MarkdownView | null {
|
||||
return this.workspace.getActiveViewOfType(MarkdownView) || null;
|
||||
}
|
||||
|
||||
parseLinkString(str: string, view?: MarkdownView | null) {
|
||||
let url: string | null = null;
|
||||
let displayText: string | null = null;
|
||||
let external: boolean = false;
|
||||
let obsidianUrl: boolean = false;
|
||||
let options = { x: 0, y: 0, repeatable: false };
|
||||
|
||||
const wikilinkRegex = /^!?\[\[([^\]]+?)(\|([^\]]+?))?\]\]$/;
|
||||
const wikilinkMatch = str.match(wikilinkRegex);
|
||||
if (wikilinkMatch) {
|
||||
url = wikilinkMatch[1].trim();
|
||||
displayText = wikilinkMatch[3] ? wikilinkMatch[3].trim() : null;
|
||||
}
|
||||
|
||||
const markdownLinkRegex = /^!?\[([^\]]*)\]\(([^)]+?)\)$/;
|
||||
const markdownBareLinkRegex = /^!?<([^>]+)>$/;
|
||||
const markdownMatch = str.match(markdownLinkRegex);
|
||||
const markdownBareMatch = str.match(markdownBareLinkRegex);
|
||||
if (markdownMatch) {
|
||||
displayText = markdownMatch[1].trim();
|
||||
url = markdownMatch[2].trim();
|
||||
} else if (markdownBareMatch) {
|
||||
url = markdownBareMatch[1].trim();
|
||||
displayText = null;
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
url = str;
|
||||
displayText = null;
|
||||
}
|
||||
|
||||
external = /^https?:\/\//i.test(url);
|
||||
|
||||
if (url.startsWith('obsidian://open')) {
|
||||
const str = url.replace('obsidian://open', '');
|
||||
const params = new URLSearchParams(str);
|
||||
let file = params.get('file');
|
||||
if (file) {
|
||||
url = file;
|
||||
obsidianUrl = true;
|
||||
external = false;
|
||||
displayText = null;
|
||||
}
|
||||
}
|
||||
|
||||
const hashIndex = url.indexOf('#');
|
||||
if ((external || obsidianUrl) && hashIndex !== -1) {
|
||||
options = this.parseBannerOptions(url.substring(hashIndex + 1));
|
||||
url = url.replace(/#.*/, '').trim();
|
||||
}
|
||||
|
||||
if (displayText) {
|
||||
options = this.parseBannerOptions(displayText);
|
||||
}
|
||||
|
||||
if (!external) {
|
||||
const vault = this.app.vault;
|
||||
const files = vault.getFiles().filter(f => f.path === url || f.name === url);
|
||||
let file = files.find(f => f.path === url);
|
||||
if (file) {
|
||||
url = vault.getResourcePath(file);
|
||||
}
|
||||
if (!file) {
|
||||
file = files.find(f => f.name === url);
|
||||
if (file) {
|
||||
url = vault.getResourcePath(file);
|
||||
}
|
||||
}
|
||||
|
||||
if (obsidianUrl && file && view) {
|
||||
const activeFile = this.workspace.getActiveFile();
|
||||
if (activeFile) {
|
||||
this.app.fileManager.processFrontMatter(activeFile, (frontmatter) => {
|
||||
const propName = this.settings.propertyName;
|
||||
frontmatter[propName] = `[[${file?.path}]]`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
url: url.trim(),
|
||||
external,
|
||||
...options,
|
||||
};
|
||||
}
|
||||
|
||||
parseBannerOptions(str: string): BannerOptions {
|
||||
let repeatable: boolean;
|
||||
let x = 0;
|
||||
let y = 0;
|
||||
|
||||
const values = str.toLowerCase();
|
||||
repeatable = values.includes('repeat');
|
||||
|
||||
const sizes = str.split(/x|,/);
|
||||
const numbers = sizes.filter(v => !isNaN(parseInt(v.trim(), 10)));
|
||||
|
||||
if (numbers.length === 2) {
|
||||
x = parseInt(numbers[0].trim(), 10);
|
||||
y = parseInt(numbers[1].trim(), 10);
|
||||
} else if (numbers.length === 1) {
|
||||
y = parseInt(numbers[0].trim(), 10);
|
||||
}
|
||||
return { x, y, repeatable };
|
||||
}
|
||||
|
||||
isOptionsUpdate(oldstr?: string | null, newstr?: string | null, view?: MarkdownView | null): boolean {
|
||||
if (!oldstr || !newstr) {
|
||||
return false;
|
||||
}
|
||||
const oldopt = this.parseLinkString(oldstr, view);
|
||||
const newopt = this.parseLinkString(newstr, view);
|
||||
return oldopt.url === newopt.url;
|
||||
}
|
||||
|
||||
setCSSVariable(name: string, value: string, target: HTMLElement = document.documentElement) {
|
||||
target.style.setProperty(name, value);
|
||||
}
|
||||
|
||||
createDefaultBannerData(): BannerData {
|
||||
return {
|
||||
path: null,
|
||||
value: null,
|
||||
isNewValue: false,
|
||||
isUpdate: false,
|
||||
viewMode: null,
|
||||
lastViewMode: null,
|
||||
container: null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the settings tab for configuring the SimpleBanner plugin.
|
||||
*
|
||||
*/
|
||||
class SettingTab extends PluginSettingTab {
|
||||
plugin: SimpleBanner;
|
||||
|
||||
constructor(app: App, plugin: SimpleBanner) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
const {containerEl} = this;
|
||||
containerEl.empty();
|
||||
|
||||
// GLOBALS
|
||||
new Setting(containerEl)
|
||||
.setHeading()
|
||||
.setName('Global Settings');
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Note Offset')
|
||||
.setDesc('Move the position of the notes content in pixels.')
|
||||
.addExtraButton(button => button
|
||||
.setIcon('rotate-ccw')
|
||||
.setTooltip('Restore default')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.offset = DEFAULT_SETTINGS.offset;
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
})
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter a number')
|
||||
.setValue(this.plugin.settings.offset.toString())
|
||||
.onChange(async (value) => {
|
||||
let num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
num = DEFAULT_SETTINGS.offset;
|
||||
}
|
||||
this.plugin.settings.offset = num;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Border Radius')
|
||||
.setDesc('Size of the border radius in pixels.')
|
||||
.addExtraButton(button => button
|
||||
.setIcon('rotate-ccw')
|
||||
.setTooltip('Restore default')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.radius = DEFAULT_SETTINGS.radius;
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
})
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('8')
|
||||
.setValue(this.plugin.settings.radius[0].toString())
|
||||
.onChange(async (value) => {
|
||||
let num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
num = DEFAULT_SETTINGS.radius[0];
|
||||
}
|
||||
this.plugin.settings.radius[0] = num;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('8')
|
||||
.setValue(this.plugin.settings.radius[1].toString())
|
||||
.onChange(async (value) => {
|
||||
let num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
num = DEFAULT_SETTINGS.radius[1];
|
||||
}
|
||||
this.plugin.settings.radius[1] = num;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('8')
|
||||
.setValue(this.plugin.settings.radius[2].toString())
|
||||
.onChange(async (value) => {
|
||||
let num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
num = DEFAULT_SETTINGS.radius[2];
|
||||
}
|
||||
this.plugin.settings.radius[2] = num;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
)
|
||||
.addText((text) => {
|
||||
text.setPlaceholder('8')
|
||||
.setValue(this.plugin.settings.radius[3].toString())
|
||||
.onChange(async (value) => {
|
||||
let num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
num = DEFAULT_SETTINGS.radius[3];
|
||||
}
|
||||
this.plugin.settings.radius[3] = num;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
text?.inputEl?.parentElement?.classList.add('smpbn-radii');
|
||||
return text;
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Padding')
|
||||
.setDesc('Padding of the image from the edges of the note in pixels.')
|
||||
.addExtraButton(button => button
|
||||
.setIcon('rotate-ccw')
|
||||
.setTooltip('Restore default')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.padding = DEFAULT_SETTINGS.padding;
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
})
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter a number')
|
||||
.setValue(this.plugin.settings.padding.toString())
|
||||
.onChange(async (value) => {
|
||||
let num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
num = DEFAULT_SETTINGS.padding;
|
||||
}
|
||||
this.plugin.settings.padding = num;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Fade')
|
||||
.setDesc('Fade the image out towards the content.')
|
||||
.addToggle(component => component
|
||||
.setValue(this.plugin.settings.fade)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.fade = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setHeading()
|
||||
.setName('Height Settings');
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Desktop')
|
||||
.setDesc('Height of the Banner on desktop devices (in pixels).')
|
||||
.addExtraButton(button => button
|
||||
.setIcon('rotate-ccw')
|
||||
.setTooltip('Restore default')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.desktopHeight = DEFAULT_SETTINGS.desktopHeight;
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
})
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter a number')
|
||||
.setValue(this.plugin.settings.desktopHeight.toString())
|
||||
.onChange(async (value) => {
|
||||
let num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
num = DEFAULT_SETTINGS.desktopHeight;
|
||||
}
|
||||
this.plugin.settings.desktopHeight = num;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Tablet')
|
||||
.setDesc('Height of the Banner on tablet devices (in pixels).')
|
||||
.addExtraButton(button => button
|
||||
.setIcon('rotate-ccw')
|
||||
.setTooltip('Restore default')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.tabletHeight = DEFAULT_SETTINGS.tabletHeight;
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
})
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter a number')
|
||||
.setValue(this.plugin.settings.tabletHeight.toString())
|
||||
.onChange(async (value) => {
|
||||
let num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
num = DEFAULT_SETTINGS.tabletHeight;
|
||||
}
|
||||
this.plugin.settings.tabletHeight = num;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Mobile')
|
||||
.setDesc('Height of the Banner on mobile devices (in pixels).')
|
||||
.addExtraButton(button => button
|
||||
.setIcon('rotate-ccw')
|
||||
.setTooltip('Restore default')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.mobileHeight = DEFAULT_SETTINGS.mobileHeight;
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
})
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('Enter a number')
|
||||
.setValue(this.plugin.settings.mobileHeight.toString())
|
||||
.onChange(async (value) => {
|
||||
let num = parseInt(value, 10);
|
||||
if (isNaN(num)) {
|
||||
num = DEFAULT_SETTINGS.mobileHeight;
|
||||
}
|
||||
this.plugin.settings.mobileHeight = num;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setHeading()
|
||||
.setName('Frontmatter Settings');
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Property Name')
|
||||
.setDesc('Name of the property this plugin should look for in the frontmatter.')
|
||||
.addExtraButton(button => button
|
||||
.setIcon('rotate-ccw')
|
||||
.setTooltip('Restore default')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.propertyName = DEFAULT_SETTINGS.propertyName;
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
})
|
||||
)
|
||||
.addText(text => text
|
||||
.setPlaceholder('Default: banner')
|
||||
.setValue(this.plugin.settings.propertyName.toString())
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.propertyName = (value !== '') ? value : DEFAULT_SETTINGS.propertyName;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
307
src/styles.scss
Normal file
307
src/styles.scss
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
@keyframes fade {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
@keyframes move {
|
||||
from {
|
||||
background-position-y: calc(50% + (var(--smpbn-img-y, 0) - 10px));
|
||||
}
|
||||
to {
|
||||
background-position-y: calc(50% + var(--smpbn-img-y, 0));
|
||||
}
|
||||
}
|
||||
|
||||
.view-content {
|
||||
.cm-scroller, .markdown-preview-view {
|
||||
padding-top: 0;
|
||||
|
||||
.cm-contentContainer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.el-pre.mod-frontmatter.mod-ui {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.view-content > .markdown-source-view.mod-cm6 > .cm-editor > .cm-scroller,
|
||||
.view-content .markdown-preview-view {
|
||||
.cm-contentContainer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.el-pre.mod-frontmatter.mod-ui {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&:has(.simple-banner) {
|
||||
padding-top: 0;
|
||||
|
||||
.metadata-container {
|
||||
position: absolute;
|
||||
container-type: normal;
|
||||
margin-left: calc(-1 * var(--size-4-5));
|
||||
padding: var(--size-4-2) var(--size-4-6) var(--size-4-6) var(--size-4-6);
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
max-width: calc(var(--file-line-width) + (var(--size-4-6) * 2));
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
background-color: color-mix(in srgb, var(--background-primary) 90%, transparent);
|
||||
backdrop-filter: blur(5px);
|
||||
opacity: 1;
|
||||
z-index: -1;
|
||||
border-radius: 0 0 var(--radius-m) var(--radius-m);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.65);
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
|
||||
&.is-collapsed {
|
||||
.metadata-properties-heading {
|
||||
opacity: 0.5;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s linear;
|
||||
& > .metadata-properties-title {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
}
|
||||
&:before {
|
||||
background-color: rgba(var(--background-primary), 0);
|
||||
box-shadow: 0 4px 0 rgba(0, 0, 0, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover, &:focus, &:focus-within {
|
||||
.metadata-properties-heading.is-collapsed {
|
||||
opacity: 1;
|
||||
&:before {
|
||||
opacity: 0;
|
||||
}
|
||||
& > .metadata-properties-title {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cm-contentContainer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding-top: 190px;
|
||||
}
|
||||
.el-pre.mod-frontmatter.mod-ui {
|
||||
padding-top: 210px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.workspace-leaf-content[data-sb] .view-content > .markdown-source-view.mod-cm6 > .cm-editor > .cm-scroller,
|
||||
.workspace-leaf-content[data-sb] .view-content .markdown-preview-view {
|
||||
padding-top: 0;
|
||||
|
||||
.metadata-container {
|
||||
position: absolute;
|
||||
container-type: normal;
|
||||
left: calc(50% + (var(--size-4-5) * 1));
|
||||
transform: translateX(-50%);
|
||||
padding: var(--size-4-2) var(--size-4-6) var(--size-4-6) var(--size-4-6);
|
||||
z-index: 2;
|
||||
width: 100%;
|
||||
|
||||
.metadata-properties-heading {
|
||||
width: 100%;
|
||||
transform: translateY(0);
|
||||
transition: opacity 0.2s linear, transform 0.2s ease-in-out;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
height: 2px;
|
||||
width: 100%;
|
||||
opacity: 0.1;
|
||||
background-color: black;
|
||||
box-shadow: 0 2px 2px black;
|
||||
transition: all 0.2s linear;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
background-color: color-mix(in srgb, var(--background-primary) 90%, transparent);
|
||||
backdrop-filter: blur(5px);
|
||||
opacity: 1;
|
||||
z-index: -1;
|
||||
border-radius: 0 0 var(--radius-m) var(--radius-m);
|
||||
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.4);
|
||||
transform: translateY(0);
|
||||
transition: opacity 0.2s linear, transform 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
&.is-collapsed {
|
||||
.metadata-properties-heading {
|
||||
opacity: 0.5;
|
||||
transform: translateY(-70px);
|
||||
& > .metadata-properties-title {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
}
|
||||
&:after {
|
||||
opacity: 0;
|
||||
box-shadow: 0 2px 2px black;
|
||||
}
|
||||
&:before {
|
||||
opacity: 0;
|
||||
transform: translateY(-70px);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover, &:focus, &:focus-within {
|
||||
&.is-collapsed {
|
||||
&:before {
|
||||
transform: translateY(-26px);
|
||||
opacity: 0.85;
|
||||
}
|
||||
&:after {
|
||||
opacity: 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
.metadata-properties-heading.is-collapsed {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
&:before {
|
||||
opacity: 0;
|
||||
}
|
||||
& > .metadata-properties-title {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cm-contentContainer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
padding-top: calc(var(--smpbn-height, 240px) + (var(--smpbn-note-offset) - 6px));
|
||||
}
|
||||
.el-pre.mod-frontmatter.mod-ui {
|
||||
padding-top: calc(var(--smpbn-height, 240px) + (var(--smpbn-note-offset) + 12px));
|
||||
}
|
||||
}
|
||||
|
||||
body.show-inline-title .workspace-leaf-content[data-sb] .view-content > .markdown-source-view.mod-cm6 > .cm-editor > .cm-scroller,
|
||||
body.show-inline-title .workspace-leaf-content[data-sb] .view-content .markdown-preview-view {
|
||||
.cm-contentContainer {
|
||||
padding-top: 0;
|
||||
}
|
||||
.inline-title {
|
||||
padding-top: calc(var(--smpbn-height, 240px) + (var(--smpbn-note-offset) + 12px));
|
||||
}
|
||||
.el-pre.mod-frontmatter.mod-ui {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
div.simple-banner {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
width: calc(100% - (var(--smpbn-padding, 8px) * 2));
|
||||
height: 100%;
|
||||
margin-left: var(--smpbn-padding, 8px);
|
||||
max-height: var(--smpbn-height, 240px);
|
||||
border-radius: var(--smpbn-radius, 0px);
|
||||
mask-image: var(--smpbn-fade);
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: '';
|
||||
box-shadow: inset 0 2px 4px 1px rgba(0, 0, 0, 0.1);
|
||||
border-radius: var(--smpbn-radius, 0px);
|
||||
background-color: rgba(0,0,0,.2);
|
||||
}
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: '';
|
||||
background-image: var(--smpbn-url);
|
||||
background-repeat: var(--smpbn-repeat, no-repeat);
|
||||
background-size: var(--smpbn-size, cover);
|
||||
background-position-x: calc(50% + var(--smpbn-img-x, 0));
|
||||
background-position-y: calc(50% + var(--smpbn-img-y, 0));
|
||||
animation: fade 0.6s linear forwards, move 0.8s ease-out;
|
||||
transition: background-position-x 0.5s ease-in-out, background-position-y 0.5s ease-in-out;
|
||||
will-change: transform, background-position-x, background-position-y;
|
||||
transform-style: preserve-3d;
|
||||
image-rendering: crisp-edges;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
&.static:after {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
& + div {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.setting-item-control.smpbn-radii {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto; /* Three columns */
|
||||
grid-template-rows: auto auto; /* Two rows */
|
||||
|
||||
& > *:nth-child(1) {
|
||||
grid-column: 1; /* Spans the first column */
|
||||
grid-row: 1 / 3; /* Spans from the first to the third row */
|
||||
}
|
||||
& > *:nth-child(2) {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
}
|
||||
& > *:nth-child(3) {
|
||||
grid-column: 3;
|
||||
grid-row: 1;
|
||||
}
|
||||
& > *:nth-child(4) {
|
||||
grid-column: 2;
|
||||
grid-row: 2;
|
||||
}
|
||||
& > *:nth-child(5) {
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
}
|
||||
& > input {
|
||||
max-width: 78.2px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
28
tsconfig.json
Normal file
28
tsconfig.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"inlineSourceMap": true,
|
||||
"inlineSources": true,
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"strictNullChecks": true,
|
||||
"lib": [
|
||||
"DOM",
|
||||
"ES5",
|
||||
"ES6",
|
||||
"ES7"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
}
|
||||
14
version-bump.mjs
Normal file
14
version-bump.mjs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { readFileSync, writeFileSync } from "fs";
|
||||
|
||||
const targetVersion = process.env.npm_package_version;
|
||||
|
||||
// read minAppVersion from manifest.json and bump version to target version
|
||||
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
|
||||
const { minAppVersion } = manifest;
|
||||
manifest.version = targetVersion;
|
||||
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
|
||||
|
||||
// update versions.json with target version and minAppVersion from manifest.json
|
||||
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
|
||||
versions[targetVersion] = minAppVersion;
|
||||
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));
|
||||
3
versions.json
Normal file
3
versions.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"0.1.0": "1.8.9"
|
||||
}
|
||||
Loading…
Reference in a new issue