Skip to content
On this page

Apps integration ​

Behold the artistry of integrating apps within your theme's grand tapestry. Just as a masterful painter weaves vibrant hues into their canvas, you shall weave the functionality of apps into your digital realm.

App Placements ​

Each theme boasts its unique app placements, with some placements mandated by required apps, like the Express Checkout App. Behold these examples:

App PlacementsTextType
REPLACE_BUYNOWTo show an app instead of the “Buy Now” buttonRequired
BEFORE_HEADERShow apps on the of of the pageOptional
AFTER_HEADERShow apps after the header sectionOptional
BEFORE_FOOTERShow apps before the footerOptional
AFTER_FOOTERShow apps on the bottom of the pageOptional
BEFORE_ADD_TO_CARTBefore “Add to cart” buttonOptional
AFTER_ADD_TO_CARTAfter “Add to cart” buttonOptional
AFTER_DESCRIPTIONAfter description contentOptional
REPLACE_REVIEWSReplace default theme reviews with reviews appOptional

App Installation ​

For testing and experimentation, visit https://markets.storeino.world/apps and install free apps into your store.

Implementation Unveiled ​

Prepare your symphony of apps by crafting a universal component named "AppLoader.vue" within the components folder.

vue
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useMainStore } from '@/stores/main';

// Define props
const props = defineProps({
  placement: {
    type: String,
    required: true,
  },
});

// Store and Reactive State
const store = useMainStore();
const loading = ref(false);
const { $tools }: any = useNuxtApp();

// Load App Function
function loadApp(app: any, element: HTMLElement | null) {
  if (!element) return;

  const uid = ${app.route}_${props.placement};
  if (!app[loaded_${uid}]) {
    try {
      const stateApp = store.apps.find((a: any) => a.route === app.route);
      if (!stateApp) return;

      let { manifest, html, css, js } = $tools.copy(stateApp.loaded);

      js = js.replace(
        '_DATA_',
        JSON.stringify({
          placement: props.placement,
          ...app.config,
        }).replace(/"/g, '"')
      );

      html = html.replace(
        new RegExp(app_${app.route}, 'g'),
        app_${app.route}_${uid}
      );

      css = css.replace(
        new RegExp(#app_${app.route}, 'g'),
        #app_${app.route}_${uid}
      );

      js = js.replace(
        new RegExp(app_${app.route}, 'g'),
        app_${app.route}_${uid}
      );

      app[loaded_${uid}] = { manifest, html, css, js };
    } catch (err) {
      console.error('Error loading app:', err);
    }
  }

  if (app[loaded_${uid}]) {
    const htmlElement = document.createElement('div');
    const styleElement = document.createElement('style');

    element.append(htmlElement);
    htmlElement.innerHTML = app[loaded_${uid}].html;

    element.append(styleElement);
    styleElement.innerHTML = app[loaded_${uid}].css;

    window.eval(app[loaded_${uid}].js);
  }
}

// Mounted Lifecycle Hook
onMounted(() => {
  const element: any = document.querySelector(#${props.placement});
  if (store.apps) {
    const apps = store.apps.filter((app: any) =>
      app.placement.split('|').includes(props.placement)
    );

    if (apps.length > 0) {
      loading.value = true;
      apps.forEach((app: any) => loadApp(app, element));
      loading.value = false;
    }
  }
});
</script>

<template>
  <div :id="placement"></div>
</template>

With this masterpiece ready, call your symphonic component <app-loader> and serenade it with the enchanting notes of the "placement" parameter.

vue
<template>
  <div>
    <app-loader placement="BEFORE_HEADER"></app-loader>
    <header>
      <hav>
        <ul>
          <li>Home</li>
          ...
        </ul>
      </hav>
    </header>
  </div>
</template>

Just as a maestro wields their baton, you now wield the power to orchestrate the harmonious fusion of apps into your theme. Let your digital realm resound with the symphony of innovation and functionality.

Released under the MIT License.