Setup

Before start to install Olotap the Node.js package must be installed on your computer.

Requirements

Only Node.js 18.15.0 and above are supported, check out the article below to install Node.js with Nvm in your environment.

Installation

Install olotap package with npm.

npm install olotap

After this stage, you can clone our demo project in which all features work, or you can start a new test project from scratch as in the example.

Create a Test Project with Vite

npm create vite@latest olotap-test --template vue
  • Select the framework as Vue.
  • Select the variant as Javascript.
cd olotap-test
npm install

Install the latest version of vue-i18n, vuetify, @mdi/font and olotap.

npm install vuetify@latest vue-i18n vite-plugin-vuetify @mdi/font olotap

Create plugins and i18n folders.

cd src/
mkdir -p plugins i18n/locales

Copy default locales to your application.

wget -O "$(pwd)/i18n/locales/en.json" https://raw.githubusercontent.com/olomadev/olotap-demo/main/src/i18n/locales/en.json
wget -O "$(pwd)/i18n/locales/tr.json" https://raw.githubusercontent.com/olomadev/olotap-demo/main/src/i18n/locales/tr.json

Configure Your i18n Files

i18n/index.js

import { createI18n } from "vue-i18n";
/**
 * app messages
 */
import _en from "./locales/en.json";
import _tr from "./locales/tr.json";

const i18n = createI18n({
  locale: "en",
  fallbackLocale: "en",
  legacy: false,
  globalInjection: true,
  // forceStringify: false,
  messages: { tr: _tr, en: _en },
  runtimeOnly: false,
});
/**
 * import locales
 */
export default i18n;

Configure Your Plugin Index

plugins/index.js

import i18n from "../i18n";
import { OlotapPlugin } from "olotap";
import vuetify from "./vuetify";
import "@mdi/font/css/materialdesignicons.css"; // material icons

/**
 * Main register function
 */
export async function registerPlugins(app) {
  app.use(i18n);
  app.use(vuetify);
  app.provide("vuetify", vuetify);

  const config = {
    i18n,
    t: i18n.global.t,
    defaultLang: i18n.global.locale.value,
    defaultMarkdownTheme: "default",
  }
  await OlotapPlugin.install(app, config);
}

Configure Your App.vue Template

src/App.vue

<template>
  <OlotapEditor 
    v-if="created && extensions.length > 0"
    :extensions="extensions"
    ref="editorRef"
    :key="getEditorKey"
    bg-color="grey-lighten-4"
    v-model="model.contentJson"
    v-model:markdown-theme="markdownTheme"
    output="json"
    :error-messages="errorMessages"
    :min-height="600"
    max-height="600"
    max-width="900"
    @change="onChange"
  >
  </OlotapEditor>
</template>

Configure App.vue Script

src/App.vue

<script>
import i18n from "@/i18n";
import "olotap/classic-editor.css";
import { OlotapEditor, defaultBubbleList } from "olotap";

export default {
  name: 'App',
  components: {
    OlotapEditor
  },
  data() {
    return {
      lang: "en",
      model: {
        contentJson: null,
        contentHtml: null
      },
      errorMessages: [],
      markdownTheme: "default",
      editorKey: "editor_",
      extensions: [],
    };
  },
  created() {
    this.created = false;
    this.createExtensions();
    this.created = true;
  },
  watch: {
    lang(val) {
      i18n.global.locale.value = val;
      this.createExtensions(); // re create extension for new locale
    }
  },
  computed: {
    getEditorKey() {
      return "olotap_" + i18n.global.locale.value;
    }
  },
  methods: {
    createExtensions() {
      const {
        BaseKit,
        History,
        Bold,
        Italic,
      } = this.$extensions;

      this.extensions = [
        BaseKit.configure({
          placeholder: {
            placeholder: this.$t("editor.placeholder")
          },
          bubble: {
            // default config
            list: {
              image: [ 'float-left', 'float-none', 'float-right', 'divider', 'image-size-small', 'image-size-medium', 'image-size-large', 'divider', 'textAlign', 'divider', 'image', 'image-aspect-ratio', 'remove'],
              text: ['bold', 'italic', 'underline', 'strike', 'divider', 'color', 'highlight', 'textAlign', 'divider', 'link'],
              video: ['video', 'video-size-small', 'video-size-medium', 'video-size-large', 'remove'],
              codeBlock: ['paste-code', 'change-language', 'copy-code', 'remove'],
              horizontalRule: ['remove'],
            },
            defaultBubbleList: editor => {
              // You can customize the bubble menu here
              const defaultBubble = defaultBubbleList(editor)
              return defaultBubble; // default customize bubble list
            }
          }
        }),
        History.configure({ divider: true  }),
        Bold,
        Italic,
      ];
    },
    onChange(val) {
      // console.error(val)
    },
  }
};
</script>

Configure Your Main File

main.js

Make the following changes in your main.js file for asynchronous loading of the component.

import { createApp } from 'vue'
import App from './App.vue'

// Plugins
import { registerPlugins } from "@/plugins";
const app = createApp(App);

async function init() {
  await registerPlugins(app);
  app.mount("#app");
}

init()