Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ziyafenn committed Sep 3, 2023
0 parents commit a786bb0
Show file tree
Hide file tree
Showing 28 changed files with 3,585 additions and 0 deletions.
10 changes: 10 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -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 = 4
tab_width = 4
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/

main.js
23 changes: 23 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -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"
}
}
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# vscode
.vscode

# Intellij
*.iml
.idea

# npm
node_modules

# Don't include the compiled main.js file in the repo.
# They should be uploaded to GitHub releases instead.
main.js

# Exclude sourcemaps
*.map

# obsidian
data.json

# Exclude macOS Finder (System Explorer) View States
.DS_Store
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tag-version-prefix=""
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Contentful Publisher

Contentful is a headless CMS that lets you create and deliver content to any platform.

The plugin can pull the content types from Contentful and create Obsidian templates based on them. It can also pull all your content entries from Contentful and create notes based on them, organizing them into folders based on the content type.

You can also update the content from Obsidian and push it back to Contentful. If the plugin detects that the content is out of sync (it will check if the content was updated on Contentful), it will warn you and create a copy of the content.

All the fields of the content will be added as frontmatter parameters, except for the title and body. Currently, the plugin will ignore these fields: _RichText_, _ResourceLink_, _Link_, _Object_ and _Location_.

## How to Use

1. Setup plugin from **Settings -> Contentful Publisher**
2. Use "Sync with Contentful" action from the Sidebar to pull your content
3. Once you are done editing a Note, select "Update Contentful Entry" from Command palette(ctrl+p) to update the Contentful Entry from Obsidian

## Requirements

- Obsidian core Template plugin must be enabled and configured
- _Wikilinks_ should be disabled from the **Settings -> Files & Links** so Markdown links are used by default instead
- Content model in Contentful are created
- Every content model must have a field that represents Entry title of the content
- Content type model should have at least one Text field representing the body of the entry

## Planned Features

- [ ] Create content from Obsidian
- [ ] Upload images from Obsidian
- [ ] Support for multiple locales
48 changes: 48 additions & 0 deletions esbuild.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";

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 context = await esbuild.context({
banner: {
js: banner,
},
entryPoints: ["main.ts"],
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,
outfile: "main.js",
});

if (prod) {
await context.rebuild();
process.exit(0);
} else {
await context.watch();
}
132 changes: 132 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { Notice, Plugin } from "obsidian";
import {
createNotesFromEntries,
createTemplatesFromTypes,
} from "src/createNotes";
import { getTemplatesFolderName } from "src/getTemplatesFolderName";
import ContentfulService from "src/contentfulClient";
import ContentfulSettingTab from "src/settings/settingTab";
import { ContentfulApiError, PluginSettings } from "src/types";
import { ErrorModal } from "src/errorModal";
import { isJSONString } from "src/utilities";
import strings from "src/strings";
import { updateEntry } from "src/updateEntry";

const DEFAULT_SETTINGS: PluginSettings = {
spaceID: "",
contentManagementToken: "",
environmentID: "master",
bodyFieldIDs: {},
titleFieldIDs: {},
ignoredFieldIDs: {},
defaultLocale: "",
};

export default class ContentfulPublisher extends Plugin {
settings: PluginSettings;
contentful: ContentfulService;
isFirstStart: boolean;
isSetupComplete: boolean;

async onload() {
await this.loadSettings();
const modal = new ErrorModal(this.app);

const vault = this.app.vault;
const templatesFolderName = getTemplatesFolderName(vault);

this.isFirstStart =
!this.settings.spaceID &&
!this.settings.contentManagementToken &&
!this.settings.environmentID;
this.isSetupComplete =
!this.isFirstStart &&
Object.keys(this.settings.bodyFieldIDs).length !== 0 &&
Object.keys(this.settings.titleFieldIDs).length !== 0 &&
!!this.settings.defaultLocale &&
!!templatesFolderName;

if (this.isSetupComplete) {
this.contentful = new ContentfulService(
this.settings.spaceID!,
this.settings.contentManagementToken!,
this.settings.environmentID
);
}
this.addSettingTab(new ContentfulSettingTab(this.app, this));

this.addCommand({
id: "updateContentfulEntry",
name: "Update Contentful entry",
callback: async () => {
const loading = new Notice(
"Updating file... Might take some time.",
0
);
try {
const updatedEntry = await updateEntry(this.app, this);
return new Notice(
`Entry "${updatedEntry}" was successfully updated`
);
} catch (error) {
if (
error instanceof Error &&
error.name === "OutOfSyncError"
) {
return modal.showOutOfSyncError([error.message]);
}
new Notice(error.message);
} finally {
loading.hide();
}
},
});

this.addRibbonIcon("refresh-ccw", "Sync with Contentful", async () => {
if (!this.isSetupComplete)
return new Notice("Plugin not configured");
const loading = new Notice(
"Syncing files with Contentful... Might take some time.",
0
);
try {
const contentTypes = await this.contentful.getContentTypes(
this
);
const entries = await this.contentful.getEntries(this.settings);

await createTemplatesFromTypes(
contentTypes,
vault,
this.settings
);
const notes = await createNotesFromEntries(
entries,
vault,
this.settings
);

if (notes.length > 0) return modal.showOutOfSyncError(notes);
new Notice(strings.syncSuccess);
} catch (err) {
if (!isJSONString(err.message)) return new Notice(err.message);
const error: ContentfulApiError = JSON.parse(err.message);
modal.showError(error);
} finally {
loading.hide();
}
});
}

async loadSettings() {
this.settings = Object.assign(
{},
DEFAULT_SETTINGS,
await this.loadData()
);
}

async saveSettings() {
await this.saveData(this.settings);
}
}
10 changes: 10 additions & 0 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"id": "contentful-publisher",
"name": "Contentful Publisher",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "Manage your Contentful content from Obsidian.",
"author": "Ziya Fenn",
"authorUrl": "https://ziyafenn.com",
"isDesktopOnly": false
}
Loading

0 comments on commit a786bb0

Please sign in to comment.