├── .DS_Store
├── .gitattributes
├── .github
├── .DS_Store
└── workflows
│ └── publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── icon.png
├── index.html
├── index.ts
├── package.json
├── tsconfig.json
└── yarn.lock
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sawhney17/logseq-property-visualizer/aef03314e6fa97f305e2bd1b6f9c4b5217de4174/.DS_Store
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sawhney17/logseq-property-visualizer/aef03314e6fa97f305e2bd1b6f9c4b5217de4174/.github/.DS_Store
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Build plugin
2 |
3 | on:
4 | push:
5 | # Sequence of patterns matched against refs/tags
6 | tags:
7 | - '*' # Push events to matching any tag format, i.e. 1.0, 20.15.10
8 |
9 | env:
10 | PLUGIN_NAME: logseq-property-visualizer
11 |
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 |
16 | steps:
17 | - uses: actions/checkout@v2
18 | - name: Use Node.js
19 | uses: actions/setup-node@v1
20 | with:
21 | node-version: '16.x' # You might need to adjust this value to your own version
22 | - name: Build
23 | id: build
24 | run: |
25 | npm i && npm run build
26 | mkdir ${{ env.PLUGIN_NAME }}
27 | cp README.md package.json icon.png ${{ env.PLUGIN_NAME }}
28 | mv dist ${{ env.PLUGIN_NAME }}
29 | zip -r ${{ env.PLUGIN_NAME }}.zip ${{ env.PLUGIN_NAME }}
30 | ls
31 | echo "::set-output name=tag_name::$(git tag --sort version:refname | tail -n 1)"
32 | - name: Create Release
33 | uses: ncipollo/release-action@v1
34 | id: create_release
35 | env:
36 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37 | VERSION: ${{ github.ref }}
38 | with:
39 | allowUpdates: true
40 | draft: false
41 | prerelease: false
42 |
43 | - name: Upload zip file
44 | id: upload_zip
45 | uses: actions/upload-release-asset@v1
46 | env:
47 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48 | with:
49 | upload_url: ${{ steps.create_release.outputs.upload_url }}
50 | asset_path: ./${{ env.PLUGIN_NAME }}.zip
51 | asset_name: ${{ env.PLUGIN_NAME }}-${{ steps.build.outputs.tag_name }}.zip
52 | asset_content_type: application/zip
53 |
54 | - name: Upload package.json
55 | id: upload_metadata
56 | uses: actions/upload-release-asset@v1
57 | env:
58 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
59 | with:
60 | upload_url: ${{ steps.create_release.outputs.upload_url }}
61 | asset_path: ./package.json
62 | asset_name: package.json
63 | asset_content_type: application/json
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build and Release Folders
2 | bin-debug/
3 | bin-release/
4 | [Oo]bj/
5 | [Bb]in/
6 |
7 | # Other files and folders
8 | .settings/
9 |
10 | # Executables
11 | *.swf
12 | *.air
13 | *.ipa
14 | *.apk
15 |
16 | # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
17 | # should NOT be excluded as they contain compiler settings and other important
18 | # information for Eclipse / Flash Builder.
19 | node_modules
20 | dist
21 | .parcel-cache
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 sawhney17
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # logseq-property-visualizer
2 | A plugin to chart or visualize trends in the values of page properties over time.
3 | ## Setup
4 | 1. First ensure that you have [hkgnp's](https://github.com/hkgnp) [Table Render](https://github.com/hkgnp/logseq-tablerender-plugin) and [Chart Render](https://github.com/hkgnp/logseq-chartrender-plugin) plugins
5 | 2. Use the slash menu and type `property visualizer`
6 | 3. Assign variables in the syntax
7 | - {{renderer :property_visualizer, {property name}, {type of graph or table}, {graph or table}, {last x days}}
8 | 4. Base the types from the readme of either plugin
9 | 5. Samples
10 | - `{{renderer :property_visualizer, happiness, line white 300, chart, 40}}`
11 | - Will generate lined chart, with width 300, color white, graphing property "happiness" over the last 40 days
12 | -
13 |
14 | - `{{renderer :property_visualizer, fulfillment}}`
15 | - Will generate table with sum, median and average.
16 | -
17 |
18 | - `{{renderer :property_visualizer, happiness, data nosum}}`
19 | - Will generate simple table showing the values of happiness
20 | -
21 | 6. Important: Will only fetch page properties of journal pages
22 | - Add a page property to every journal page when you want to track something
23 | - Track habits, word written, etc.
24 | ## Limitations
25 | 1. Only works when property is mentioned on the page property of a journal page
26 | -
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sawhney17/logseq-property-visualizer/aef03314e6fa97f305e2bd1b6f9c4b5217de4174/icon.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | logseq-property-visualizer
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | import '@logseq/libs'
2 | import {
3 | BlockEntity,
4 | PageEntity,
5 | IBatchBlock,
6 | } from '@logseq/libs/dist/LSPlugin.user';
7 | /**
8 | * main entry
9 | */
10 | function timeConverter(x: number) {
11 | var a = new Date(x * 1000);
12 | var months = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'];
13 | var year = a.getFullYear();
14 | var month = months[a.getMonth()];
15 | var date = a.getDate();
16 | var time = year + month + date;
17 | return time;
18 | }
19 | function convertDate(inputDate: number) {
20 | const dateString = inputDate.toString()
21 | console.log("hi")
22 | const year = parseInt(dateString.substring(0, 4))
23 | const month = parseInt(dateString.substring(4, 6))
24 | const day = parseInt(dateString.substring(6, 8))
25 | console.log(year, month, day)
26 | console.log(new Date(year, month - 1, day))
27 | return new Date(year, month - 1, day);
28 | }
29 |
30 | async function main() {
31 | const uniqueIdentifier = () =>
32 | Math.random()
33 | .toString(36)
34 | .replace(/[^a-z]+/g, '');
35 |
36 | logseq.provideModel({
37 | async insertFormattedBlock(e: any) {
38 | const { blockUuid, propertyName, title, displayer, range } = e.dataset
39 | var query = `
40 | [:find (pull ?b [*])
41 | :where
42 | [?b :block/properties ?p]
43 | [(get ?p :${propertyName})]]
44 | `
45 | console.log(range)
46 |
47 | try {
48 | let ret = await logseq.DB.datascriptQuery(query)
49 | const result0 = ret?.flat()
50 | logseq.Editor.insertBlock(blockUuid, title, { sibling: false })
51 |
52 | logseq.Editor.insertBlock(blockUuid, "Date", { sibling: false })
53 | logseq.Editor.insertBlock(blockUuid, propertyName, { sibling: false })
54 |
55 | let parentBlock = await logseq.Editor.getBlock(blockUuid, { includeChildren: true })
56 | if (parentBlock?.children) { //Checking to make sure blocks were successfully created
57 | //defining constants
58 | let headerBlock = parentBlock.children[0]
59 | let x_value_block = parentBlock.children[1]
60 | let y_value_block = parentBlock.children[2]
61 | let header_uuid = headerBlock["uuid"]
62 | let x_uuid = x_value_block["uuid"]!
63 | let y_uuid = y_value_block["uuid"]
64 | let date = new Date()
65 | let cutoff = range * (1000 * 3600 * 24)
66 |
67 | if (result0 && result0.length > 0) { //Ensuring that the results of the datascript query isn't empty
68 | var results = []
69 | for (const constant in result0) {
70 | try {
71 | if ([result0[constant]][0]["journal?"]) {
72 | if (![result0[constant]][0]["page"] != undefined) {
73 | console.log(cutoff)
74 | console.log(date.getTime() - convertDate([result0[constant]][0]["journal-day"]).getTime())
75 | if (date.getTime() - convertDate([result0[constant]][0]["journal-day"]).getTime() < cutoff) {
76 | results.push([result0[constant]][0])
77 | }
78 | }
79 | }
80 | }
81 | catch (err) {
82 | console.log(err)
83 | }
84 | }
85 | console.log(results)
86 | console.log(results)
87 | for (const constant in results) {
88 | if ([results[constant]][0]["original-name"] !== undefined) {
89 | logseq.Editor.insertBlock(x_uuid, [results[constant]][0]["original-name"], { sibling: false });
90 | logseq.Editor.insertBlock(y_uuid, String([results[constant]][0]["properties"][propertyName]), { sibling: false });
91 | }
92 | }
93 |
94 | }
95 | logseq.Editor.updateBlock(blockUuid, `{{renderer :${displayer}s_${uniqueIdentifier()}}}`);
96 | logseq.Editor.moveBlock(y_uuid, header_uuid, { children: true });
97 | logseq.Editor.moveBlock(x_uuid, header_uuid, { children: true });
98 | }
99 |
100 | }
101 | catch (err) {
102 | console.log(err)
103 | }
104 |
105 | },
106 | }),
107 | logseq.provideStyle(`
108 | .formatter-btn {
109 | border: 1px solid var(--ls-border-color);
110 | white-space: initial;
111 | padding: 2px 4px;
112 | border-radius: 4px;
113 | user-select: none;
114 | cursor: default;
115 | display: flex;
116 | align-content: center;
117 | }
118 |
119 | .formatter-btn:hover {
120 | background-color: #defcf0;
121 | border-color: #9ddbc7;
122 | color: #0F9960;
123 | }
124 | `)
125 |
126 | logseq.Editor.registerSlashCommand('Property Visualizer', async () => {
127 | await logseq.Editor.insertAtEditingCursor(`{{renderer :property_visualizer, }}`);
128 | });
129 |
130 | logseq.Editor.registerSlashCommand('Property Visualizer (guided)', async () => {
131 | await logseq.Editor.insertAtEditingCursor(`{{renderer :property_visualizer, property name, chart/table styling(eg. data nosum, area white 500), chart/table, date range}}`);
132 | });
133 |
134 | logseq.App.onMacroRendererSlotted(async ({ slot, payload }) => {
135 | var [type, template, title, displayStyle, dateRange] = payload.arguments;
136 | if (title == undefined) {
137 | title = "data"
138 | }
139 |
140 | if (displayStyle == undefined) {
141 | displayStyle = "table"
142 | }
143 | if (dateRange == undefined) {
144 | dateRange = "10000"
145 | console.log("ultimate")
146 | }
147 | // logseq.Editor.removeBlock
148 |
149 | if (type == ':property_visualizer') {
150 | logseq.provideUI({
151 | key: 'logseq visualizer plugin',
152 | reset: true,
153 | slot,
154 | template: `
155 |
157 | `,
158 | });
159 | }
160 | else return;
161 | });
162 | }
163 |
164 | logseq.ready(main).catch(console.error)
165 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "logseq-property-visualizer",
3 | "version": "1.0.4",
4 | "description": "A plugin to visualize and graph trends in page properties",
5 | "author": "@sawhney17",
6 | "license": "MIT",
7 | "scripts": {
8 | "dev": "parcel ./index.html --public-url ./",
9 | "build": "parcel build --public-url . --no-source-maps index.html"
10 | },
11 | "devDependencies": {
12 | "@logseq/libs": "^0.0.1-alpha.34",
13 | "parcel": "^2.0.0"
14 | },
15 | "logseq": {
16 | "id": "_km4vf3swk",
17 | "main": "dist/index.html",
18 | "icon": "./logo.png"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */
4 |
5 | /* Basic Options */
6 | // "incremental": true, /* Enable incremental compilation */
7 | "target": "ESNext",
8 | /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
9 | "module": "ESNext",
10 | /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
11 | // "lib": [], /* Specify library files to be included in the compilation. */
12 | // "allowJs": true, /* Allow javascript files to be compiled. */
13 | // "checkJs": true, /* Report errors in .js files. */
14 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
15 | // "declaration": true, /* Generates corresponding '.d.ts' file. */
16 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
17 | // "sourceMap": true, /* Generates corresponding '.map' file. */
18 | // "outFile": "./", /* Concatenate and emit output to single file. */
19 | // "outDir": "./", /* Redirect output structure to the directory. */
20 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
21 | // "composite": true, /* Enable project compilation */
22 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
23 | // "removeComments": true, /* Do not emit comments to output. */
24 | "noEmit": true,
25 | /* Do not emit outputs. */
26 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */
27 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
28 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
29 |
30 | /* Strict Type-Checking Options */
31 | "strict": true,
32 | /* Enable all strict type-checking options. */
33 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
34 | // "strictNullChecks": true, /* Enable strict null checks. */
35 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */
36 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
37 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
38 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
39 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
40 |
41 | /* Additional Checks */
42 | // "noUnusedLocals": true, /* Report errors on unused locals. */
43 | // "noUnusedParameters": true, /* Report errors on unused parameters. */
44 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
45 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
46 |
47 | /* Module Resolution Options */
48 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
49 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
50 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
51 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
52 | // "typeRoots": [], /* List of folders to include type definitions from. */
53 | // "types": [], /* Type declaration files to be included in compilation. */
54 | "allowSyntheticDefaultImports": true,
55 | /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
56 | "esModuleInterop": true,
57 | /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
58 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
59 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
60 |
61 | /* Source Map Options */
62 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
63 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
64 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
65 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
66 |
67 | /* Experimental Options */
68 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
69 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
70 |
71 | /* Advanced Options */
72 | "skipLibCheck": true,
73 | /* Skip type checking of declaration files. */
74 | "forceConsistentCasingInFileNames": true
75 | /* Disallow inconsistently-cased references to the same file. */
76 | }
77 | }
78 |
--------------------------------------------------------------------------------