mirror of
https://github.com/oen/liquid-template.git
synced 2026-07-22 05:40:24 +00:00
commit
6c2b50047e
16 changed files with 294 additions and 50 deletions
79
README.md
79
README.md
|
|
@ -58,12 +58,83 @@ I'm just a footer
|
|||
|
||||
But other than that, you can use all the basic [tags](https://liquidjs.com/tags/overview.html) and [filters](https://liquidjs.com/filters/overview.html)
|
||||
|
||||
## Custom Filters
|
||||
|
||||
For now I'll keep the documentation of the filters here, when they become more I'll move it somewhere more convenient
|
||||
|
||||
## `date` filter
|
||||
|
||||
The LiquidJS [built-in `date` filter](https://liquidjs.com/filters/date.html) has been replaced with a custom one.
|
||||
For now, if there is a `%` character in the date format the old filter is used, otherwise the new one will take place.
|
||||
|
||||
The new `date` filter uses [date-fns](https://date-fns.org/) as library to handle dates, and the format strings to use are showed here: [date-fns formats](https://date-fns.org/v2.21.3/docs/format)
|
||||
|
||||
There are also some special words that can be used with this filter:
|
||||
|
||||
**"now"**<br/>
|
||||
`{{ "now" | date: "yyyy-MM-dd" }}`<br/>
|
||||
Use the date from `new Date` and formatted with the given format<br/>
|
||||
|
||||
|
||||
**"today"**<br/>
|
||||
`{{ "today" | date: "yyyy-MM-dd" }}`<br/>
|
||||
same as `now`<br/>
|
||||
|
||||
|
||||
**"yesterday"**<br/>
|
||||
`{{ "yesterday" | date: "yyyy-MM-dd" }}`<br/>
|
||||
use the [`subDays`](https://date-fns.org/v2.21.3/docs/subDays) function to subtract `1` from `Date.now()` and formatted with the given format<br/>
|
||||
|
||||
|
||||
**"tomorrow"**<br/>
|
||||
`{{ "tomorrow" | date: "yyyy-MM-dd" }}`<br/>
|
||||
use the [`addDays`](https://date-fns.org/v2.21.3/docs/addDays) function to add `1` to `Date.now()` and formatted with the given format<br/>
|
||||
|
||||
|
||||
### `date` Default format
|
||||
|
||||
Now you can use the "Date Format" you defined inside the plugin settings in a easier way:
|
||||
|
||||
**Before**: `{{ "now" | date: default_date_format }}`
|
||||
|
||||
**Now**: `{{ "now" | date }}` the format you specified in the settings is now used as default
|
||||
|
||||
## `days_ago` filter
|
||||
|
||||
A simple filter that uses the [`subDays`](https://date-fns.org/v2.21.3/docs/subDays) to subtract days from the current date (`Date.now()`)
|
||||
|
||||
Keep in mind that this filter returns a date that needs to be formatted, so needs to be used with the `date` filter, like this:
|
||||
|
||||
- `{{ 1 | days_ago | date }}` same as `{{ "yesterday" | date }}`
|
||||
- `{{ 2 | days_ago | date }}` return the date from two days ago
|
||||
|
||||
This can be used for a "Weekly Review" template, something like:
|
||||
|
||||
```
|
||||
- [[{{ 7 | days_ago | date }}]]
|
||||
- [[{{ 6 | days_ago | date }}]]
|
||||
- [[{{ 5 | days_ago | date }}]]
|
||||
- [[{{ 4 | days_ago | date }}]]
|
||||
- [[{{ 3 | days_ago | date }}]]
|
||||
- [[{{ 2 | days_ago | date }}]]
|
||||
- [[{{ 1 | days_ago | date }}]]
|
||||
```
|
||||
|
||||
## `days_after` filter
|
||||
|
||||
A simple filter that uses the [`addDays`](https://date-fns.org/v2.21.3/docs/addDays) to add days to the current date (`Date.now()`)
|
||||
|
||||
Keep in mind that this filter returns a date that needs to be formatted, so needs to be used with the `date` filter, like this:
|
||||
|
||||
- `{{ 1 | days_after | date }}` same as `{{ "tomorrow" | date }}`
|
||||
- `{{ 2 | days_after | date }}` return the date from two days from now
|
||||
|
||||
## Template context
|
||||
|
||||
Other than the classic, `date`, `time` and `title` variable you also have:
|
||||
|
||||
| Name | Description |
|
||||
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Name | Description |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| default_date_format | The date format that you have specified in the plugin settings and can be used like this: <code>{{ "now" | date: default_date_format }}</code> |
|
||||
| default_time_format | The time format that you have specified in the plugin settings and can be used like this: <code>{{ "now" | date: default_time_format }}</code> |
|
||||
|
||||
|
|
@ -73,5 +144,5 @@ For now, this plugin just includes the basic version of LiquidJS, but I want to
|
|||
|
||||
- [ ] Add autocomplete to the template folder, excluded folder settings
|
||||
- [ ] Implement a fuzzy finder for the autocomplete
|
||||
- [ ] Implement/install a filter that allows you to write `{{ 1 | days_ago | date: default_date_format }}`
|
||||
- [ ] Parse a selected template string, something like you select `{{ "dQw4w9WgXcQ" | youtube_iframe }}` run a command and end up with the parsed result, in this case, the youtube iframe. (the `youtube_iframe` tag does not exist yet)
|
||||
- [x] Implement/install a filter that allows you to write `{{ 1 | days_ago | date: default_date_format }}`
|
||||
- [ ] Parse a selected template string, something like you select `{{ "dQw4w9WgXcQ" | youtube_iframe }}` run a command and end up with the parsed result, in this case, the youtube iframe. (the `youtube_iframe` tag does not exist yet)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "liquid-templates",
|
||||
"name": "Liquid Templates",
|
||||
"version": "0.1.5",
|
||||
"version": "0.2.0",
|
||||
"minAppVersion": "0.12.3",
|
||||
"description": "Empower your template with LiquidJS tags",
|
||||
"author": "diomedet",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "liquid-templates",
|
||||
"version": "0.1.5",
|
||||
"version": "0.2.0",
|
||||
"description": "Empower your template with LiquidJS tags",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
"typescript": "^4.2.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"date-fns": "^2.21.3",
|
||||
"liquidjs": "^9.25.0",
|
||||
"lodash": "^4.17.21"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import commonjs from '@rollup/plugin-commonjs';
|
|||
|
||||
const isProd = (process.env.BUILD === 'production');
|
||||
|
||||
const banner =
|
||||
const banner =
|
||||
`/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
|
||||
if you want to view the source visit the plugins github repository
|
||||
|
|
@ -12,7 +12,7 @@ if you want to view the source visit the plugins github repository
|
|||
`;
|
||||
|
||||
export default {
|
||||
input: 'main.ts',
|
||||
input: 'src/main.ts',
|
||||
output: {
|
||||
dir: '.',
|
||||
sourcemap: 'inline',
|
||||
|
|
@ -27,4 +27,4 @@ export default {
|
|||
nodeResolve({browser: true}),
|
||||
commonjs(),
|
||||
]
|
||||
};
|
||||
};
|
||||
|
|
|
|||
26
src/engine/filters/base_filter.ts
Normal file
26
src/engine/filters/base_filter.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { Liquid, FilterImplOptions } from 'liquidjs';
|
||||
|
||||
import LiquidTemplates from '../../main';
|
||||
|
||||
export interface BaseFilterProps {
|
||||
engine: Liquid,
|
||||
plugin: LiquidTemplates,
|
||||
filterName?: string;
|
||||
}
|
||||
|
||||
export class BaseFilter {
|
||||
readonly plugin: LiquidTemplates;
|
||||
readonly engine: Liquid;
|
||||
readonly filterName: string;
|
||||
handler: FilterImplOptions;
|
||||
|
||||
constructor({ plugin, engine, filterName }: BaseFilterProps) {
|
||||
this.plugin = plugin;
|
||||
this.engine = engine;
|
||||
this.filterName = filterName;
|
||||
}
|
||||
|
||||
register(): void {
|
||||
this.engine.registerFilter(this.filterName, this.handler);
|
||||
}
|
||||
}
|
||||
41
src/engine/filters/date.ts
Normal file
41
src/engine/filters/date.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { addDays, format, subDays } from 'date-fns';
|
||||
|
||||
import { BaseFilter, BaseFilterProps } from './base_filter';
|
||||
|
||||
export default class DateFiler extends BaseFilter {
|
||||
originalFilter: Function;
|
||||
|
||||
constructor(props: BaseFilterProps) {
|
||||
super({ ...props, filterName: 'date' });
|
||||
this.originalFilter = this.engine.filters.get('date');
|
||||
}
|
||||
|
||||
handler = (givenValue: number | string, dateFormat?: string): string | number => {
|
||||
const dateToFormat = (typeof givenValue === 'number')
|
||||
? givenValue
|
||||
: this.parseDate(givenValue)
|
||||
const formatToUse = dateFormat || this.plugin.settings.dateFormat;
|
||||
|
||||
// TODO: improve or remove me: keep backwards compatibility with the current 0.1.5 version
|
||||
if (formatToUse.includes('%')) {
|
||||
// TODO: send a notification when using this function
|
||||
return this.originalFilter(givenValue, dateFormat);
|
||||
}
|
||||
|
||||
try {
|
||||
return format(dateToFormat, formatToUse)
|
||||
} catch (e) {
|
||||
if (!(e instanceof RangeError)) throw e;
|
||||
}
|
||||
|
||||
return givenValue;
|
||||
}
|
||||
|
||||
parseDate = (stringToParse: string): Date => {
|
||||
if(['now', 'today'].includes(stringToParse)) return new Date;
|
||||
if(stringToParse === 'yesterday') return subDays(Date.now(), 1);
|
||||
if(stringToParse === 'tomorrow') return addDays(Date.now(), 1);
|
||||
// try to parse the given string
|
||||
return new Date(Date.parse(stringToParse));
|
||||
}
|
||||
}
|
||||
11
src/engine/filters/days_after.ts
Normal file
11
src/engine/filters/days_after.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { addDays } from 'date-fns';
|
||||
|
||||
import { BaseFilter, BaseFilterProps } from './base_filter';
|
||||
|
||||
export default class DaysAfter extends BaseFilter {
|
||||
constructor(props: BaseFilterProps) {
|
||||
super({ ...props, filterName: 'days_after' });
|
||||
}
|
||||
|
||||
handler = (daysToSub: number): Date => addDays(Date.now(), daysToSub);
|
||||
}
|
||||
11
src/engine/filters/days_ago.ts
Normal file
11
src/engine/filters/days_ago.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { subDays } from 'date-fns';
|
||||
|
||||
import { BaseFilter, BaseFilterProps } from './base_filter';
|
||||
|
||||
export default class DaysAgo extends BaseFilter {
|
||||
constructor(props: BaseFilterProps) {
|
||||
super({ ...props, filterName: 'days_ago' });
|
||||
}
|
||||
|
||||
handler = (daysToSub: number): Date => subDays(Date.now(), daysToSub);
|
||||
}
|
||||
48
src/engine/index.ts
Normal file
48
src/engine/index.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { App } from 'obsidian';
|
||||
import { Liquid } from 'liquidjs';
|
||||
|
||||
import LiquidTemplates from '../main';
|
||||
import { getTFilesFromFolder } from 'src/utils';
|
||||
|
||||
import DateFilter from './filters/date';
|
||||
import DaysAgo from './filters/days_ago';
|
||||
import DaysAfter from './filters/days_after';
|
||||
|
||||
export function applyCustomFilters(engine: Liquid, plugin: LiquidTemplates) {
|
||||
[
|
||||
DateFilter,
|
||||
DaysAgo,
|
||||
DaysAfter
|
||||
].forEach(filter => new filter({ plugin, engine }).register())
|
||||
}
|
||||
|
||||
export function initEngine(app: App, plugin: LiquidTemplates): Liquid {
|
||||
const engine = new Liquid({
|
||||
fs: {
|
||||
readFileSync: (file) => {
|
||||
// TODO: implement me
|
||||
return "";
|
||||
},
|
||||
readFile: async (file) => {
|
||||
const [fileName, ...folder] = file.split('/').reverse()
|
||||
const folderToCheck = [plugin.settings.templatesFolder, ...folder.reverse()].join('/')
|
||||
// TODO: find a better way to do this
|
||||
const fileObj = getTFilesFromFolder(app, folderToCheck).find(f => f.basename === fileName);
|
||||
return app.vault.read(fileObj);
|
||||
},
|
||||
existsSync: () => {
|
||||
return true
|
||||
},
|
||||
exists: async () => {
|
||||
return true
|
||||
},
|
||||
resolve: (_root, file, _ext) => {
|
||||
return file
|
||||
}
|
||||
},
|
||||
extname: '.md',
|
||||
greedy: true,
|
||||
});
|
||||
applyCustomFilters(engine, plugin);
|
||||
return engine;
|
||||
}
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import { get, isEmpty } from "lodash";
|
||||
import { Plugin } from "obsidian";
|
||||
|
||||
import { LiquidTemplatesSettings, DEFAULT_SETTINGS, LiquidTemplatesSettingsTab } from "./settings";
|
||||
|
|
@ -40,11 +41,29 @@ export default class LiquidTemplates extends Plugin {
|
|||
};
|
||||
|
||||
async loadSettings(): Promise<void> {
|
||||
this.settings = Object.assign({ ...DEFAULT_SETTINGS }, await this.loadData());
|
||||
this.settings = this.settingsWithDefault(await this.loadData());
|
||||
}
|
||||
|
||||
async saveSettings(): Promise<void> {
|
||||
// the templates folder can change
|
||||
this.setupAutosuggest();
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
settingsWithDefault(savedSettings: LiquidTemplatesSettings): LiquidTemplatesSettings {
|
||||
// TODO: improve me
|
||||
return {
|
||||
templatesFolder: this.getSettingOrDefault(savedSettings, 'templatesFolder'),
|
||||
excludeFolders: this.getSettingOrDefault(savedSettings, 'excludeFolders'),
|
||||
dateFormat: this.getSettingOrDefault(savedSettings, 'dateFormat'),
|
||||
timeFormat: this.getSettingOrDefault(savedSettings, 'timeFormat'),
|
||||
autocompleteTrigger: this.getSettingOrDefault(savedSettings, 'autocompleteTrigger'),
|
||||
}
|
||||
}
|
||||
|
||||
getSettingOrDefault(savedSettings: LiquidTemplatesSettings, settingKey: string, defaultValue?: any): any {
|
||||
let currentValue = get(savedSettings, settingKey)
|
||||
if (!isEmpty(currentValue)) return currentValue;
|
||||
return get(DEFAULT_SETTINGS, settingKey, defaultValue);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { get, isEmpty } from "lodash";
|
||||
import { App, PluginSettingTab, Setting } from "obsidian";
|
||||
import LiquidTemplates from "./main";
|
||||
import { format } from 'date-fns';
|
||||
|
||||
export interface LiquidTemplatesSettings {
|
||||
templatesFolder: string;
|
||||
|
|
@ -13,8 +13,8 @@ export interface LiquidTemplatesSettings {
|
|||
export const DEFAULT_SETTINGS: LiquidTemplatesSettings = {
|
||||
templatesFolder: 'templates',
|
||||
excludeFolders: "",
|
||||
dateFormat: '%Y-%m-%d',
|
||||
timeFormat: '%H:%M',
|
||||
dateFormat: 'yyyy-MM-dd',
|
||||
timeFormat: 'k:m',
|
||||
autocompleteTrigger: ';;'
|
||||
};
|
||||
|
||||
|
|
@ -60,9 +60,26 @@ export class LiquidTemplatesSettingsTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
const dateFormatDesc = document.createDocumentFragment();
|
||||
dateFormatDesc.append(
|
||||
'Output format for render dates.',
|
||||
dateFormatDesc.createEl('br'),
|
||||
'For more syntax, refer to ',
|
||||
dateFormatDesc.createEl("a", {
|
||||
href: "https://date-fns.org/v2.21.3/docs/format",
|
||||
text: "format reference",
|
||||
}),
|
||||
dateFormatDesc.createEl('br'),
|
||||
'current format: ',
|
||||
dateFormatDesc.createEl('b', {
|
||||
cls: 'u-pop',
|
||||
text: format(new Date, this.plugin.settings.dateFormat)
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Date format')
|
||||
.setDesc('Output format for render dates')
|
||||
.setDesc(dateFormatDesc)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder(DEFAULT_SETTINGS.dateFormat)
|
||||
|
|
@ -73,9 +90,27 @@ export class LiquidTemplatesSettingsTab extends PluginSettingTab {
|
|||
})
|
||||
);
|
||||
|
||||
|
||||
const timeFormatDesc = document.createDocumentFragment();
|
||||
timeFormatDesc.append(
|
||||
'Output format for render time.',
|
||||
timeFormatDesc.createEl('br'),
|
||||
'For more syntax, refer to ',
|
||||
timeFormatDesc.createEl("a", {
|
||||
href: "https://date-fns.org/v2.21.3/docs/format",
|
||||
text: "format reference",
|
||||
}),
|
||||
timeFormatDesc.createEl('br'),
|
||||
'current format: ',
|
||||
timeFormatDesc.createEl('b', {
|
||||
cls: 'u-pop',
|
||||
text: format(new Date, this.plugin.settings.timeFormat)
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Time format')
|
||||
.setDesc('Output format for render time')
|
||||
.setDesc(timeFormatDesc)
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder(DEFAULT_SETTINGS.timeFormat)
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
import { App, TFile } from "obsidian";
|
||||
import { Liquid } from "liquidjs";
|
||||
import type PoweredTemplates from "../main";
|
||||
import { format } from "date-fns";
|
||||
|
||||
import CodeMirrorSuggest from "./codemirror-suggest";
|
||||
import { getTFilesFromFolder } from "utils";
|
||||
import type PoweredTemplates from "../main";
|
||||
import { getTFilesFromFolder } from "../utils";
|
||||
import { initEngine } from "src/engine";
|
||||
|
||||
interface ITemplateCompletion {
|
||||
label: string;
|
||||
|
|
@ -20,34 +23,7 @@ export default class TemplateSuggest extends CodeMirrorSuggest<ITemplateCompleti
|
|||
super(app, plugin.settings.autocompleteTrigger);
|
||||
|
||||
this.plugin = plugin;
|
||||
// TODO: move me in a separate class
|
||||
this.engine = new Liquid({
|
||||
fs: {
|
||||
readFileSync: (file) => {
|
||||
// TODO: implement me
|
||||
return "";
|
||||
},
|
||||
readFile: async (file) => {
|
||||
const [fileName, ...folder] = file.split('/').reverse()
|
||||
const { templatesFolder } = this.plugin.settings;
|
||||
const folderToCheck = [templatesFolder, ...folder.reverse()].join('/')
|
||||
// TODO: find a better way to do this
|
||||
const fileObj = getTFilesFromFolder(app, folderToCheck).find(f => f.basename === fileName);
|
||||
return app.vault.read(fileObj);
|
||||
},
|
||||
existsSync: () => {
|
||||
return true
|
||||
},
|
||||
exists: async () => {
|
||||
return true
|
||||
},
|
||||
resolve: (_root, file, _ext) => {
|
||||
return file
|
||||
}
|
||||
},
|
||||
extname: '.md',
|
||||
greedy: true,
|
||||
});
|
||||
this.engine = initEngine(app, plugin);
|
||||
}
|
||||
|
||||
open(): void {
|
||||
|
|
@ -83,13 +59,18 @@ export default class TemplateSuggest extends CodeMirrorSuggest<ITemplateCompleti
|
|||
}
|
||||
|
||||
async generateContext() {
|
||||
const {
|
||||
dateFormat,
|
||||
timeFormat
|
||||
} = this.plugin.settings;
|
||||
|
||||
return {
|
||||
// TODO: improve me
|
||||
date: await this.engine.parseAndRender(`{{ "now" | date: "${this.plugin.settings.dateFormat}"}}`),
|
||||
time: await this.engine.parseAndRender(`{{ "now" | date: "${this.plugin.settings.timeFormat}"}}`),
|
||||
date: format(Date.now(), dateFormat),
|
||||
time: format(Date.now(), timeFormat),
|
||||
title: await this.app.workspace.getActiveFile().basename,
|
||||
default_date_format: this.plugin.settings.dateFormat,
|
||||
default_time_format: this.plugin.settings.timeFormat
|
||||
default_date_format: dateFormat,
|
||||
default_time_format: timeFormat
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
{
|
||||
"0.1.5": "0.12.3"
|
||||
"0.2.0": "0.12.3"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue