Full Code of dashpilot/vue-pagebuilder for AI

main 05e3f7fbc11b cached
26 files
130.8 KB
39.4k tokens
44 symbols
1 requests
Download .txt
Repository: dashpilot/vue-pagebuilder
Branch: main
Commit: 05e3f7fbc11b
Files: 26
Total size: 130.8 KB

Directory structure:
gitextract_ssjr_prk/

├── .gitignore
├── README.md
├── build/
│   └── bundle.mjs
├── components/
│   ├── featured/
│   │   └── featured.mjs
│   ├── features/
│   │   └── features.mjs
│   ├── header/
│   │   └── header.mjs
│   ├── helpers.mjs
│   ├── news/
│   │   └── news.mjs
│   ├── newsleft/
│   │   └── newsleft.mjs
│   └── post/
│       └── post.mjs
├── editor/
│   ├── components/
│   │   ├── add-content.mjs
│   │   ├── fa-picker.mjs
│   │   └── image-resize.mjs
│   ├── editor.css
│   ├── editor.mjs
│   └── js/
│       └── iconpicker/
│           ├── iconpicker-1.5.0.css
│           ├── iconpicker-1.5.0.js
│           └── iconpicker-1.5.0.json
├── index.html
├── main.mjs
├── package.json
├── rollup.build.mjs
├── rollup.serve.mjs
├── style.css
├── test-inline.html
└── test.html

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.DS_Store
.env
node_modules



================================================
FILE: README.md
================================================
# vue-pagebuilder

A visual pagebuilder for Vue 3.

Features:

- Add premade layout blocks to the page
- Rearrange and delete layout blocks
- Edit text
- Upload images (with automatic resize)
- Font Awesome icon chooser
- Change colors and fonts
- Download generated HTML

# demo

https://vue-pagebuilder.vercel.app

# preview

![App Preview](https://github.com/dashpilot/vue-pagebuilder/blob/main/editor/img/app-preview2.png?raw=true)

## Run the demo locally

To run the project locally, run:

```bash
npm run serve
```

This will start a local server on localhost:8000

## Press the :star: button

Don't forget to press the :star: button to let me know I should continue improving this project.


================================================
FILE: build/bundle.mjs
================================================
const html$8 = String.raw;

const template$9 = html$8`
  <section
    :id="item.id"
    class="editable text-center"
    data-fields="icon=icon&amp;title=txt&amp;subtitle=txt&amp;button_text=txt&amp;button_link=txt"
  >
    <div class="container">
      <i :class="item.icon+' fa-big'"></i>

      <h1>{{item.title}}</h1>
      <p>{{item.subtitle}}</p>

      <a
        :href="item.button_link"
        class="btn btn-secondary"
        v-if="item.button_text"
        >{{item.button_text}}</a
      >
    </div>
  </section>
`;

var Header = {
  template: template$9,
  props: ["item"],
  mounted() {
    //console.log('Banner component mounted.')
  },
};

const html$7 = String.raw;

const template$8 = html$7`
  <section :id="item.id" class="editable" data-fields="title=txt&amp;body=rte">
    <div class="container">
      <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8">
          <h2>{{item.title}}</h2>
          <p>{{item.body}}</p>
        </div>
        <div class="col-md-2"></div>
      </div>
    </div>
  </section>
`;

var Post = {
  template: template$8,
  props: ["item"],
  mounted() {
    //console.log('Post component mounted.')
  },
};

var helpers = {
  def: function (key, val) {
    if (key) {
      return key;
    } else {
      return val;
    }
  },
  youtube_parser: function (url) {
    var regExp =
      /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
    var match = url.match(regExp);
    return match && match[7].length == 11 ? match[7] : false;
  },
};

const html$6 = String.raw;

const template$7 = html$6`
  <section
    :id="item.id"
    class="editable"
    data-fields="title=txt&amp;body=rte&amp;image=img&amp;youtube_url=vid"
  >
    <div class="container">
      <div class="row">
        <div class="col-md-6">
          <h2>{{item.title}}</h2>
          <p>{{item.body}}</p>
        </div>
        <div class="col-md-6">
          <template v-if="item.image">
            <img :src="item.image" class="img-fluid" />
          </template>
          <template v-else-if="item.youtube_url">
            <div class="responsive-container">
              <iframe
                title="video"
                class="responsive-iframe"
                width="560"
                height="315"
                :src="'https://www.youtube.com/embed/' + youtube_parser(item.youtube_url)"
                frameborder="0"
                allowfullscreen
              />
            </div>
          </template>
          <template v-else>
            <img
              src="https://vue-pagebuilder.vercel.app/editor/img/placeholder.jpg"
              class="img-fluid"
            />
          </template>
        </div>
      </div>
    </div>
  </section>
`;

var News = {
  template: template$7,
  props: ["item"],
  created() {
    this.youtube_parser = helpers.youtube_parser;
  },
  mounted() {
    //console.log('News component mounted.')
  },
};

const html$5 = String.raw;

const template$6 = html$5`
  <section
    :id="item.id"
    class="editable"
    data-fields="title=txt&amp;body=rte&amp;image=img&amp;youtube_url=vid"
  >
    <div class="container">
      <div class="row">
        <div class="col-md-6">
          <template v-if="item.image">
            <img :src="item.image" class="img-fluid" />
          </template>
          <template v-else-if="item.youtube_url">
            <div class="responsive-container">
              <iframe
                title="video"
                class="responsive-iframe"
                width="560"
                height="315"
                :src="'https://www.youtube.com/embed/' + youtube_parser(item.youtube_url)"
                frameborder="0"
                allowfullscreen
              />
            </div>
          </template>
          <template v-else>
            <img
              src="https://vue-pagebuilder.vercel.app/editor/img/placeholder.jpg"
              class="img-fluid"
            />
          </template>
        </div>

        <div class="col-md-6">
          <h2>{{item.title}}</h2>
          <p>{{item.body}}</p>
        </div>
      </div>
    </div>
  </section>
`;

var NewsLeft = {
  template: template$6,
  props: ["item"],
  created() {
    this.youtube_parser = helpers.youtube_parser;
  },
  mounted() {
    //console.log('News component mounted.')
  },
};

const html$4 = String.raw;

const template$5 = html$4`
  <section :id="item.id" class="editable" data-fields="title=txt&amp;body=rte">
    <div class="container">
      <div class="w-50 m-auto text-center">
        <h2>{{item.title}}</h2>
        <p>{{item.body}}</p>
      </div>
    </div>
  </section>
`;

var Featured = {
  template: template$5,
  props: ["item"],
  mounted() {
    //console.log('Featured component mounted.')
  },
};

const template$4 = `
  <section
    :id="item.id"
    class="editable"
    data-fields="title=txt&amp;body=rte&amp;title2=txt&amp;body2=rte"
  >
    <div class="container">
      <div class="row">
        <div class="col-md-6 text-center">
          <h3>{{item.title}}</h3>
          <p>{{item.body}}</p>
        </div>
        <div class="col-md-6 text-center">
          <h3>{{def(item.title2, 'Lorem Ipsum')}}</h3>
          <p>
            {{def(item.body2, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eleifend ligula ut augue scelerisque venenatis.")}}
          </p>
        </div>
      </div>
    </div>
  </section>
`;

var Features = {
  template: template$4,
  props: ["item"],
  created() {
    this.def = helpers.def;
  },
  mounted() {
    //console.log('Features component mounted.')
  },
};

const html$3 = String.raw;
const template$3 = html$3`
  <button
    :id="'launchIconPicker-'+mykey"
    class="btn btn-outline-secondary"
    :data-iconpicker-input="'#iconPicker-'+mykey"
    :data-iconpicker-preview="'#icon-preview-'+mykey"
  >
    <i :id="'icon-preview-'+mykey" :class="value"></i>
    &nbsp;Choose Icon
  </button>
  <input type="hidden" :id="'iconPicker-' + mykey" class="form-control" />
`;

var Picker = {
  template: template$3,
  props: ["mykey", "value"],
  emits: ["input"],
  mounted() {
    var app = this;
    IconPicker.Init({
      // Required: You have to set the path of IconPicker JSON file to "jsonUrl" option. e.g. '/content/plugins/IconPicker/dist/iconpicker-1.5.0.json'
      jsonUrl: "/editor/js/iconpicker/iconpicker-1.5.0.json",
      // Optional: Change the buttons or search placeholder text according to the language.
      searchPlaceholder: "Search Icon",
      showAllButton: "Show All",
      cancelButton: "Cancel",
      noResultsFound: "No results found.", // v1.5.0 and the next versions
      borderRadius: "20px", // v1.5.0 and the next versions
    });
    IconPicker.Run("#launchIconPicker-" + app.mykey, function () {
      //app.value = document.querySelector('#iconPicker').value;
      app.$emit("input", {
        key: app.mykey,
        value: document.querySelector("#iconPicker-" + app.mykey).value,
      });
    });
  },
};

const html$2 = String.raw;

const template$2 = html$2`
  <transition name="slide-left">
    <div class="slidein-left" id="adder" v-if="add">
      <div class="editor-header">
        <h4 class="float-left">Add Content</h4>
        <div class="close" @click="add = false">&times;</div>
      </div>
      <div class="editor-content mt-4">
        <img
          @click="addLayout"
          v-for="layout in layouts"
          :data-layout="layout"
          class="box img-fluid"
          :src="'components/'+layout+'/preview.png'"
        />
      </div>
    </div>
  </transition>

  <transition name="slide-left">
    <div class="slidein-left" id="designer" v-if="designer">
      <div class="editor-header">
        <h4 class="float-left">Change Design</h4>
        <div class="close" @click="designer = false">&times;</div>
      </div>

      <div class="editor-content">
        <div class="label">Color</div>

        <div class="input-group mb-3">
          <input
            class="form-control"
            v-model="color"
            @change="setColor(color)"
          />
          <div class="input-group-append">
            <button
              class="btn btn-outline-secondary w-100px"
              type="button"
              @click="choose=!choose"
            >
              <span v-if="!choose">Choose</span><span v-if="choose">Close</span>
            </button>
          </div>
        </div>

        <div v-if="choose">
          <span v-for="mycolor in colors">
            <div
              class="swatch"
              :style="'background-color: '+mycolor"
              @click="setColor(mycolor)"
            >
              <i class="fas fa-check fa-center" v-if="color == mycolor"></i>
            </div>
          </span>
        </div>

        <div class="label">Font</div>

        <div class="list-group">
          <a class="list-group-item" @click="setFont('Rubik')"
            ><i class="fas fa-check mr-2" v-if="font == 'Rubik'"></i> Default</a
          >
          <a class="list-group-item" @click="setFont('Lobster')"
            ><i class="fas fa-check mr-2" v-if="font == 'Lobster'"></i>
            Lobster</a
          >
          <a class="list-group-item" @click="setFont('Playfair Display')"
            ><i class="fas fa-check mr-2" v-if="font == 'Playfair Display'"></i>
            Playfair Display</a
          >
          <a class="list-group-item" @click="setFont('Raleway')"
            ><i class="fas fa-check mr-2" v-if="font == 'Raleway'"></i>
            Raleway</a
          >
          <a class="list-group-item" @click="setFont('Cutive Mono')"
            ><i class="fas fa-check mr-2" v-if="font == 'Cutive Mono'"></i>
            Cutive Mono</a
          >
          <a class="list-group-item" @click="setFont('Helvetica')"
            ><i class="fas fa-check mr-2" v-if="font == 'Helvetica'"></i>
            Helvetica</a
          >
          <a class="list-group-item" @click="setFont('Georgia')"
            ><i class="fas fa-check mr-2" v-if="font == 'Georgia'"></i>
            Georgia</a
          >
        </div>
      </div>
    </div>
  </transition>

  <transition name="slide-left">
    <div class="slidein-left" id="saver" v-if="save">
      <div class="editor-header">
        <h4 class="float-left">Save</h4>
        <div class="close" @click="save = false">&times;</div>
      </div>
      <div class="editor-content mt-1">
        <div class="label">
          <span>Download</span>
          <span class="badge badge-pill badge-success float-right">free</span>
        </div>

        <p class="info">
          Download your design as a html file, so you can tweak it further and
          upload it to any hosting you like.
        </p>

        <button class="btn btn-outline-dark w-100" @click="downloadFile">
          <i class="fa fa-download"></i> &nbsp;Download
        </button>
      </div>
    </div>
  </transition>

  <div id="dock">
    <img
      src="editor/img/add.png"
      class="grow"
      @click="add = true; designer = false; save= false;"
    />
    <img
      src="editor/img/settings.png"
      class="grow"
      @click="designer = true; add = false; save = false;"
    />
    <img
      src="editor/img/save.png"
      class="grow"
      @click="save = true; designer = false; add = false;"
    />
  </div>
`;

var Add = {
  template: template$2,

  props: ["layouts", "entries"],

  data() {
    return {
      add: false,
      designer: false,
      choose: false,
      save: false,
      color: "#F7FAFC",
      font: "Rubik",
      spacing: "-0.04em",
      colors: [
        "#1CA085",
        "#27AF60",
        "#1FBC9C",
        "#2ECC70",
        "#3398DB",
        "#2980B9",
        "#575fcf",
        "#3D556E",
        "#222F3D",
        "#ffdd59",
        "#F2C511",
        "#F39C19",
        "#E84B3C",
        "#C0382B",
        "#BDC3C8",
        "#DDE6E8",
        "#F7FAFC",
        "#FFFFFF",
      ],
    };
  },

  methods: {
    addLayout: function (event) {
      let layout = event.target.getAttribute("data-layout");
      let newItem = {};
      newItem.id = "item-" + Date.now();
      newItem.layout = layout;
      newItem.title = "Lorem Ipsum";
      newItem.body =
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eleifend ligula ut augue scelerisque venenatis.";
      console.log(newItem);
      this.entries.unshift(newItem);
      this.add = false;
    },
    setColor: function (hex) {
      this.color = hex;
      let hex2 = colorContrast(hex);
      let root = document.documentElement;
      root.style.setProperty("--bg-color", hex);
      root.style.setProperty("--fg-color", hex2);
      localStorage.setItem("bg-color", hex);
      localStorage.setItem("fg-color", hex2);
    },
    setFont: function (font) {
      this.font = font;
      let spacing = "0";
      if (font == "Rubik") {
        spacing = "-0.04em";
      }
      let root = document.documentElement;
      root.style.setProperty("--font", font);
      root.style.setProperty("--spacing", spacing);
      localStorage.setItem("font", font);
      localStorage.setItem("spacing", spacing);
    },
    swapStyleSheet(font) {
      let sheet = "css/" + font;
      document.getElementById("fonts").setAttribute("href", sheet);
    },
    downloadFile() {
      var css = `<style>`;
      if (localStorage.getItem("bg-color") !== null) {
        css += `:root {--bg-color:${localStorage.getItem(
          "bg-color"
        )};--fg-color:${localStorage.getItem("fg-color")};`;
      }
      if (localStorage.getItem("font") !== null) {
        css += `--font:${localStorage.getItem(
          "font"
        )};--spacing:${localStorage.getItem("spacing")};`;
      }
      css += `}
      </style>`;

      let header = `<!DOCTYPE html>
    		<html lang="en">
        <head>
          <meta charset="utf-8">
          <title>My Website</title>

          <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" />
          <link rel="stylesheet" href="https://vue-pagebuilder.vercel.app/style.css">

          ${css}

          <link rel="preconnect" href="https://fonts.gstatic.com">
          <link href="https://fonts.googleapis.com/css2?family=Rubik:wght@300;600&family=Lobster&family=Playfair+Display&family=Raleway&family=Cutive+Mono&display=swap" rel="stylesheet">

        </head>
    		<body>\n\n`;
      let html = document.querySelector("#page").innerHTML;
      let footer = `\n\n</body>
    		</html>`;
      dl(
        "index.html",
        html_beautify(header + html.replaceAll("<!---->", "") + footer)
      );
    },
  },
  mounted() {
    //console.log('Adder component mounted.')
  },
};

function colorContrast(hex) {
  var threshold = 150; /* about half of 256. Lower threshold equals more dark text on dark background  */
  var hRed = hexToR(hex);
  var hGreen = hexToG(hex);
  var hBlue = hexToB(hex);

  function hexToR(h) {
    return parseInt(cutHex(h).substring(0, 2), 16);
  }

  function hexToG(h) {
    return parseInt(cutHex(h).substring(2, 4), 16);
  }

  function hexToB(h) {
    return parseInt(cutHex(h).substring(4, 6), 16);
  }

  function cutHex(h) {
    return h.charAt(0) == "#" ? h.substring(1, 7) : h;
  }

  var cBrightness = (hRed * 299 + hGreen * 587 + hBlue * 114) / 1000;
  if (cBrightness > threshold) {
    return "#000000";
  } else {
    return "#ffffff";
  }
}

function dl(filename, data) {
  var blob = new Blob([data], {
    type: "text/html",
  });
  if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveBlob(blob, filename);
  } else {
    var elem = window.document.createElement("a");
    elem.href = window.URL.createObjectURL(blob);
    elem.download = filename;
    document.body.appendChild(elem);
    elem.click();
    document.body.removeChild(elem);
  }
}

const html$1 = String.raw;
const template$1 = html$1`
  <input
    type="file"
    id="fileInput"
    class="fileInput"
    accept="image/png, image/jpeg, image/gif"
    style="display: none;"
  />
  <button class="btn btn-outline-secondary" @click="choose">Upload</button>
`;

var Image$1 = {
  template: template$1,

  props: ["mykey"],
  emits: ["image"],

  data() {
    return {};
  },
  methods: {
    choose: function () {
      document.getElementById("fileInput").click();
    },
  },
  mounted() {
    var app = this;

    document
      .getElementById("fileInput")
      .addEventListener("change", function (e) {
        var img_width = 500;

        var img = new Image();
        img.onload = function () {
          var canvas = document.createElement("canvas"),
            ctx = canvas.getContext("2d"),
            oc = document.createElement("canvas"),
            octx = oc.getContext("2d");

          canvas.width = img_width; // destination canvas size
          canvas.height = (canvas.width * img.height) / img.width;

          var cur = {
            width: Math.floor(img.width * 0.5),
            height: Math.floor(img.height * 0.5),
          };
          oc.width = cur.width;
          oc.height = cur.height;
          octx.drawImage(img, 0, 0, cur.width, cur.height);
          while (cur.width * 0.5 > img_width) {
            cur = {
              width: Math.floor(cur.width * 0.5),
              height: Math.floor(cur.height * 0.5),
            };
            octx.drawImage(
              oc,
              0,
              0,
              cur.width * 2,
              cur.height * 2,
              0,
              0,
              cur.width,
              cur.height
            );
          }
          ctx.drawImage(
            oc,
            0,
            0,
            cur.width,
            cur.height,
            0,
            0,
            canvas.width,
            canvas.height
          );
          var base64Image = canvas.toDataURL("image/jpeg");

          //console.log(base64Image);
          //window.cur_img.src = base64Image;
          //app.item[app.mykey] = base64Image;

          app.$emit("image", {
            key: app.mykey,
            value: base64Image,
          });
        };
        img.src = URL.createObjectURL(e.target.files[0]);
      });
  },
};

const html = String.raw;

const template = html`
  <transition name="slide-right">
    <div class="editor slidein-right" v-if="item" spellcheck="false">
      <div class="editor-header">
        <h4 class="float-left">Edit</h4>
        <div class="close" @click="item = false">&times;</div>
      </div>
      <div class="editor-content">
        <div v-for="(val, key) in fields">
          <div class="label">{{key.replace('_', ' ')}}</div>

          <input
            type="text"
            class="form-control"
            v-if="val == 'txt'"
            v-model="item[key]"
          />
          <textarea
            class="form-control"
            v-if="val == 'rte'"
            v-model="item[key]"
          ></textarea>
          <fa-picker
            v-if="val == 'icon'"
            v-bind:mykey="key"
            v-bind:value="item[key]"
            @input="setIcon"
          ></fa-picker>

          <image-resize
            v-if="val == 'img'"
            v-bind:mykey="key"
            @image="setImage"
          ></image-resize>
          <input
            v-if="val == 'vid'"
            type="text"
            class="form-control"
            v-model="item[key]"
          />
        </div>

        <span v-if="item.layout != 'header'">
          <div class="label">Options</div>
          <div class="btn-group w-100">
            <button
              class="btn btn-outline-secondary w-50"
              @click="moveItem(item.id)"
            >
              Move Down
            </button>
            <button
              class="btn btn-outline-secondary w-50"
              @click="deleteItem(item.id)"
            >
              Delete
            </button>
          </div>
        </span>

        <button class="btn btn-outline-success mb-5 w-100 save" @click="save">
          Save
        </button>
      </div>
    </div>
  </transition>

  <add-content v-bind:layouts="layouts" v-bind:entries="entries"></add-content>
`;

var Editor = {
  template,

  props: ["layouts", "entries"],

  data() {
    return {
      item: false,
      fields: false,
    };
  },

  components: {
    "fa-picker": Picker,
    "add-content": Add,
    "image-resize": Image$1,
  },

  methods: {
    save: function () {
      console.log(JSON.stringify(this.entries));
      this.item = false;
    },
    setIcon: function (e) {
      this.item[e.key] = e.value;
    },
    setImage: function (e) {
      this.item[e.key] = e.value;
    },
    deleteItem: function (id) {
      let r = confirm("Are you sure you want to delete this item?");
      if (r == true) {
        this.entries.splice(
          this.entries.findIndex((x) => x.id === id),
          1
        );
        this.item = false;
      }
    },
    moveItem: function (id) {
      var from = this.entries.findIndex((x) => x.id == id);
      var to = from + 1;
      console.log(from);
      console.log(to);
      var f = this.entries.splice(from, 1)[0];
      this.entries.splice(to, 0, f);
    },
  },

  mounted() {
    //console.log('Editor component mounted.')

    var app = this;
    document.body.addEventListener("click", function (e) {
      if (e.target.closest(".editable")) {
        let el = e.target.closest(".editable");
        let id = el.id;
        app.item = app.entries.filter((x) => x.id === id)[0];

        let myfields = el.getAttribute("data-fields");
        let params = new URLSearchParams(myfields);
        myfields = Object.fromEntries(params.entries());
        //console.log(myfields);
        app.fields = myfields;
      }
    });
  },
};

const { createApp } = Vue;
const App = createApp({
  data() {
    return {
      editing: true,
      layouts: ["featured", "post", "news", "newsleft", "features"],
      entries: [
        {
          id: "item-1",
          layout: "header",
          title: "Vue Pagebuilder",
          subtitle: "Lorem ipsum dolor site amet.",
          button_text: "Contact Us",
          button_link: "#",
          icon: "fas fa-bolt",
        },
        {
          id: "item-2",
          layout: "post",
          title: "Mauris eleifend ligula",
          body: " Vivamus in nisi commodo, auctor magna vel, viverra turpis. Quisque dapibus risus nec justo euismod, id fringilla dui lobortis. Mauris vitae semper arcu. Ut ac lorem felis.",
        },
        {
          id: "item-3",
          layout: "news",
          title: "Maecenas tincidunt sem quis rutrum",
          body: "Mauris in porttitor elit. Aenean elementum eleifend quam, in tristique eros auctor porta. Donec et est in tellus blandit feugiat id nec nunc.",
        },
        {
          id: "item-4",
          layout: "features",
          title: "Lorem Ipsum",
          body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eleifend ligula ut augue scelerisque venenatis.",
        },
      ],
    };
  },

  methods: {
    defaultVal(key, def) {
      if (key == "") {
        return def;
      } else {
        return key;
      }
    },
  },

  components: {
    "wdgt-post": Post,
    "wdgt-header": Header,
    "wdgt-news": News,
    "wdgt-newsleft": NewsLeft,
    "wdgt-featured": Featured,
    "wdgt-features": Features,
    "page-editor": Editor,
  },
});

window.addEventListener("load", () => {
  App.mount("main");
});


================================================
FILE: components/featured/featured.mjs
================================================
const html = String.raw;

const template = html`
  <section :id="item.id" class="editable" data-fields="title=txt&amp;body=rte">
    <div class="container">
      <div class="w-50 m-auto text-center">
        <h2>{{item.title}}</h2>
        <p>{{item.body}}</p>
      </div>
    </div>
  </section>
`;

export default {
  template,
  props: ["item"],
  mounted() {
    //console.log('Featured component mounted.')
  },
};


================================================
FILE: components/features/features.mjs
================================================
import helpers from "./../helpers.mjs";

const template = `
  <section
    :id="item.id"
    class="editable"
    data-fields="title=txt&amp;body=rte&amp;title2=txt&amp;body2=rte"
  >
    <div class="container">
      <div class="row">
        <div class="col-md-6 text-center">
          <h3>{{item.title}}</h3>
          <p>{{item.body}}</p>
        </div>
        <div class="col-md-6 text-center">
          <h3>{{def(item.title2, 'Lorem Ipsum')}}</h3>
          <p>
            {{def(item.body2, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eleifend ligula ut augue scelerisque venenatis.")}}
          </p>
        </div>
      </div>
    </div>
  </section>
`;

export default {
  template,
  props: ["item"],
  created() {
    this.def = helpers.def;
  },
  mounted() {
    //console.log('Features component mounted.')
  },
};


================================================
FILE: components/header/header.mjs
================================================
const html = String.raw;

const template = html`
  <section
    :id="item.id"
    class="editable text-center"
    data-fields="icon=icon&amp;title=txt&amp;subtitle=txt&amp;button_text=txt&amp;button_link=txt"
  >
    <div class="container">
      <i :class="item.icon+' fa-big'"></i>

      <h1>{{item.title}}</h1>
      <p>{{item.subtitle}}</p>

      <a
        :href="item.button_link"
        class="btn btn-secondary"
        v-if="item.button_text"
        >{{item.button_text}}</a
      >
    </div>
  </section>
`;

export default {
  template,
  props: ["item"],
  mounted() {
    //console.log('Banner component mounted.')
  },
};


================================================
FILE: components/helpers.mjs
================================================
export default {
  def: function (key, val) {
    if (key) {
      return key;
    } else {
      return val;
    }
  },
  youtube_parser: function (url) {
    var regExp =
      /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
    var match = url.match(regExp);
    return match && match[7].length == 11 ? match[7] : false;
  },
};


================================================
FILE: components/news/news.mjs
================================================
import helpers from "./../helpers.mjs";
const html = String.raw;

const template = html`
  <section
    :id="item.id"
    class="editable"
    data-fields="title=txt&amp;body=rte&amp;image=img&amp;youtube_url=vid"
  >
    <div class="container">
      <div class="row">
        <div class="col-md-6">
          <h2>{{item.title}}</h2>
          <p>{{item.body}}</p>
        </div>
        <div class="col-md-6">
          <template v-if="item.image">
            <img :src="item.image" class="img-fluid" />
          </template>
          <template v-else-if="item.youtube_url">
            <div class="responsive-container">
              <iframe
                title="video"
                class="responsive-iframe"
                width="560"
                height="315"
                :src="'https://www.youtube.com/embed/' + youtube_parser(item.youtube_url)"
                frameborder="0"
                allowfullscreen
              />
            </div>
          </template>
          <template v-else>
            <img
              src="https://vue-pagebuilder.vercel.app/editor/img/placeholder.jpg"
              class="img-fluid"
            />
          </template>
        </div>
      </div>
    </div>
  </section>
`;

export default {
  template,
  props: ["item"],
  created() {
    this.youtube_parser = helpers.youtube_parser;
  },
  mounted() {
    //console.log('News component mounted.')
  },
};


================================================
FILE: components/newsleft/newsleft.mjs
================================================
import helpers from "./../helpers.mjs";
const html = String.raw;

const template = html`
  <section
    :id="item.id"
    class="editable"
    data-fields="title=txt&amp;body=rte&amp;image=img&amp;youtube_url=vid"
  >
    <div class="container">
      <div class="row">
        <div class="col-md-6">
          <template v-if="item.image">
            <img :src="item.image" class="img-fluid" />
          </template>
          <template v-else-if="item.youtube_url">
            <div class="responsive-container">
              <iframe
                title="video"
                class="responsive-iframe"
                width="560"
                height="315"
                :src="'https://www.youtube.com/embed/' + youtube_parser(item.youtube_url)"
                frameborder="0"
                allowfullscreen
              />
            </div>
          </template>
          <template v-else>
            <img
              src="https://vue-pagebuilder.vercel.app/editor/img/placeholder.jpg"
              class="img-fluid"
            />
          </template>
        </div>

        <div class="col-md-6">
          <h2>{{item.title}}</h2>
          <p>{{item.body}}</p>
        </div>
      </div>
    </div>
  </section>
`;

export default {
  template,
  props: ["item"],
  created() {
    this.youtube_parser = helpers.youtube_parser;
  },
  mounted() {
    //console.log('News component mounted.')
  },
};


================================================
FILE: components/post/post.mjs
================================================
const html = String.raw;

const template = html`
  <section :id="item.id" class="editable" data-fields="title=txt&amp;body=rte">
    <div class="container">
      <div class="row">
        <div class="col-md-2"></div>
        <div class="col-md-8">
          <h2>{{item.title}}</h2>
          <p>{{item.body}}</p>
        </div>
        <div class="col-md-2"></div>
      </div>
    </div>
  </section>
`;

export default {
  template,
  props: ["item"],
  mounted() {
    //console.log('Post component mounted.')
  },
};


================================================
FILE: editor/components/add-content.mjs
================================================
const html = String.raw;

const template = html`
  <transition name="slide-left">
    <div class="slidein-left" id="adder" v-if="add">
      <div class="editor-header">
        <h4 class="float-left">Add Content</h4>
        <div class="close" @click="add = false">&times;</div>
      </div>
      <div class="editor-content mt-4">
        <img
          @click="addLayout"
          v-for="layout in layouts"
          :data-layout="layout"
          class="box img-fluid"
          :src="'components/'+layout+'/preview.png'"
        />
      </div>
    </div>
  </transition>

  <transition name="slide-left">
    <div class="slidein-left" id="designer" v-if="designer">
      <div class="editor-header">
        <h4 class="float-left">Change Design</h4>
        <div class="close" @click="designer = false">&times;</div>
      </div>

      <div class="editor-content">
        <div class="label">Color</div>

        <div class="input-group mb-3">
          <input
            class="form-control"
            v-model="color"
            @change="setColor(color)"
          />
          <div class="input-group-append">
            <button
              class="btn btn-outline-secondary w-100px"
              type="button"
              @click="choose=!choose"
            >
              <span v-if="!choose">Choose</span><span v-if="choose">Close</span>
            </button>
          </div>
        </div>

        <div v-if="choose">
          <span v-for="mycolor in colors">
            <div
              class="swatch"
              :style="'background-color: '+mycolor"
              @click="setColor(mycolor)"
            >
              <i class="fas fa-check fa-center" v-if="color == mycolor"></i>
            </div>
          </span>
        </div>

        <div class="label">Font</div>

        <div class="list-group">
          <a class="list-group-item" @click="setFont('Rubik')"
            ><i class="fas fa-check mr-2" v-if="font == 'Rubik'"></i> Default</a
          >
          <a class="list-group-item" @click="setFont('Lobster')"
            ><i class="fas fa-check mr-2" v-if="font == 'Lobster'"></i>
            Lobster</a
          >
          <a class="list-group-item" @click="setFont('Playfair Display')"
            ><i class="fas fa-check mr-2" v-if="font == 'Playfair Display'"></i>
            Playfair Display</a
          >
          <a class="list-group-item" @click="setFont('Raleway')"
            ><i class="fas fa-check mr-2" v-if="font == 'Raleway'"></i>
            Raleway</a
          >
          <a class="list-group-item" @click="setFont('Cutive Mono')"
            ><i class="fas fa-check mr-2" v-if="font == 'Cutive Mono'"></i>
            Cutive Mono</a
          >
          <a class="list-group-item" @click="setFont('Helvetica')"
            ><i class="fas fa-check mr-2" v-if="font == 'Helvetica'"></i>
            Helvetica</a
          >
          <a class="list-group-item" @click="setFont('Georgia')"
            ><i class="fas fa-check mr-2" v-if="font == 'Georgia'"></i>
            Georgia</a
          >
        </div>
      </div>
    </div>
  </transition>

  <transition name="slide-left">
    <div class="slidein-left" id="saver" v-if="save">
      <div class="editor-header">
        <h4 class="float-left">Save</h4>
        <div class="close" @click="save = false">&times;</div>
      </div>
      <div class="editor-content mt-1">
        <div class="label">
          <span>Download</span>
          <span class="badge badge-pill badge-success float-right">free</span>
        </div>

        <p class="info">
          Download your design as a html file, so you can tweak it further and
          upload it to any hosting you like.
        </p>

        <button class="btn btn-outline-dark w-100" @click="downloadFile">
          <i class="fa fa-download"></i> &nbsp;Download
        </button>
      </div>
    </div>
  </transition>

  <div id="dock">
    <img
      src="editor/img/add.png"
      class="grow"
      @click="add = true; designer = false; save= false;"
    />
    <img
      src="editor/img/settings.png"
      class="grow"
      @click="designer = true; add = false; save = false;"
    />
    <img
      src="editor/img/save.png"
      class="grow"
      @click="save = true; designer = false; add = false;"
    />
  </div>
`;

export default {
  template,

  props: ["layouts", "entries"],

  data() {
    return {
      add: false,
      designer: false,
      choose: false,
      save: false,
      color: "#F7FAFC",
      font: "Rubik",
      spacing: "-0.04em",
      colors: [
        "#1CA085",
        "#27AF60",
        "#1FBC9C",
        "#2ECC70",
        "#3398DB",
        "#2980B9",
        "#575fcf",
        "#3D556E",
        "#222F3D",
        "#ffdd59",
        "#F2C511",
        "#F39C19",
        "#E84B3C",
        "#C0382B",
        "#BDC3C8",
        "#DDE6E8",
        "#F7FAFC",
        "#FFFFFF",
      ],
    };
  },

  methods: {
    addLayout: function (event) {
      let layout = event.target.getAttribute("data-layout");
      let newItem = {};
      newItem.id = "item-" + Date.now();
      newItem.layout = layout;
      newItem.title = "Lorem Ipsum";
      newItem.body =
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eleifend ligula ut augue scelerisque venenatis.";
      console.log(newItem);
      this.entries.unshift(newItem);
      this.add = false;
    },
    setColor: function (hex) {
      this.color = hex;
      let hex2 = colorContrast(hex);
      let root = document.documentElement;
      root.style.setProperty("--bg-color", hex);
      root.style.setProperty("--fg-color", hex2);
      localStorage.setItem("bg-color", hex);
      localStorage.setItem("fg-color", hex2);
    },
    setFont: function (font) {
      this.font = font;
      let spacing = "0";
      if (font == "Rubik") {
        spacing = "-0.04em";
      }
      let root = document.documentElement;
      root.style.setProperty("--font", font);
      root.style.setProperty("--spacing", spacing);
      localStorage.setItem("font", font);
      localStorage.setItem("spacing", spacing);
    },
    swapStyleSheet(font) {
      let sheet = "css/" + font;
      document.getElementById("fonts").setAttribute("href", sheet);
    },
    downloadFile() {
      var css = `<style>`;
      if (localStorage.getItem("bg-color") !== null) {
        css += `:root {--bg-color:${localStorage.getItem(
          "bg-color"
        )};--fg-color:${localStorage.getItem("fg-color")};`;
      }
      if (localStorage.getItem("font") !== null) {
        css += `--font:${localStorage.getItem(
          "font"
        )};--spacing:${localStorage.getItem("spacing")};`;
      }
      css += `}
      </style>`;

      let header = `<!DOCTYPE html>
    		<html lang="en">
        <head>
          <meta charset="utf-8">
          <title>My Website</title>

          <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
          <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css" />
          <link rel="stylesheet" href="https://vue-pagebuilder.vercel.app/style.css">

          ${css}

          <link rel="preconnect" href="https://fonts.gstatic.com">
          <link href="https://fonts.googleapis.com/css2?family=Rubik:wght@300;600&family=Lobster&family=Playfair+Display&family=Raleway&family=Cutive+Mono&display=swap" rel="stylesheet">

        </head>
    		<body>\n\n`;
      let html = document.querySelector("#page").innerHTML;
      let footer = `\n\n</body>
    		</html>`;
      dl(
        "index.html",
        html_beautify(header + html.replaceAll("<!---->", "") + footer)
      );
    },
  },
  mounted() {
    //console.log('Adder component mounted.')
  },
};

function colorContrast(hex) {
  var threshold = 150; /* about half of 256. Lower threshold equals more dark text on dark background  */
  var hRed = hexToR(hex);
  var hGreen = hexToG(hex);
  var hBlue = hexToB(hex);

  function hexToR(h) {
    return parseInt(cutHex(h).substring(0, 2), 16);
  }

  function hexToG(h) {
    return parseInt(cutHex(h).substring(2, 4), 16);
  }

  function hexToB(h) {
    return parseInt(cutHex(h).substring(4, 6), 16);
  }

  function cutHex(h) {
    return h.charAt(0) == "#" ? h.substring(1, 7) : h;
  }

  var cBrightness = (hRed * 299 + hGreen * 587 + hBlue * 114) / 1000;
  if (cBrightness > threshold) {
    return "#000000";
  } else {
    return "#ffffff";
  }
}

function dl(filename, data) {
  var blob = new Blob([data], {
    type: "text/html",
  });
  if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveBlob(blob, filename);
  } else {
    var elem = window.document.createElement("a");
    elem.href = window.URL.createObjectURL(blob);
    elem.download = filename;
    document.body.appendChild(elem);
    elem.click();
    document.body.removeChild(elem);
  }
}


================================================
FILE: editor/components/fa-picker.mjs
================================================
const html = String.raw;
const template = html`
  <button
    :id="'launchIconPicker-'+mykey"
    class="btn btn-outline-secondary"
    :data-iconpicker-input="'#iconPicker-'+mykey"
    :data-iconpicker-preview="'#icon-preview-'+mykey"
  >
    <i :id="'icon-preview-'+mykey" :class="value"></i>
    &nbsp;Choose Icon
  </button>
  <input type="hidden" :id="'iconPicker-' + mykey" class="form-control" />
`;

export default {
  template,
  props: ["mykey", "value"],
  emits: ["input"],
  mounted() {
    var app = this;
    IconPicker.Init({
      // Required: You have to set the path of IconPicker JSON file to "jsonUrl" option. e.g. '/content/plugins/IconPicker/dist/iconpicker-1.5.0.json'
      jsonUrl: "/editor/js/iconpicker/iconpicker-1.5.0.json",
      // Optional: Change the buttons or search placeholder text according to the language.
      searchPlaceholder: "Search Icon",
      showAllButton: "Show All",
      cancelButton: "Cancel",
      noResultsFound: "No results found.", // v1.5.0 and the next versions
      borderRadius: "20px", // v1.5.0 and the next versions
    });
    IconPicker.Run("#launchIconPicker-" + app.mykey, function () {
      //app.value = document.querySelector('#iconPicker').value;
      app.$emit("input", {
        key: app.mykey,
        value: document.querySelector("#iconPicker-" + app.mykey).value,
      });
    });
  },
};


================================================
FILE: editor/components/image-resize.mjs
================================================
const html = String.raw;
const template = html`
  <input
    type="file"
    id="fileInput"
    class="fileInput"
    accept="image/png, image/jpeg, image/gif"
    style="display: none;"
  />
  <button class="btn btn-outline-secondary" @click="choose">Upload</button>
`;

export default {
  template,

  props: ["mykey"],
  emits: ["image"],

  data() {
    return {};
  },
  methods: {
    choose: function () {
      document.getElementById("fileInput").click();
    },
  },
  mounted() {
    var app = this;

    document
      .getElementById("fileInput")
      .addEventListener("change", function (e) {
        var img_width = 500;

        var img = new Image();
        img.onload = function () {
          var canvas = document.createElement("canvas"),
            ctx = canvas.getContext("2d"),
            oc = document.createElement("canvas"),
            octx = oc.getContext("2d");

          canvas.width = img_width; // destination canvas size
          canvas.height = (canvas.width * img.height) / img.width;

          var cur = {
            width: Math.floor(img.width * 0.5),
            height: Math.floor(img.height * 0.5),
          };
          oc.width = cur.width;
          oc.height = cur.height;
          octx.drawImage(img, 0, 0, cur.width, cur.height);
          while (cur.width * 0.5 > img_width) {
            cur = {
              width: Math.floor(cur.width * 0.5),
              height: Math.floor(cur.height * 0.5),
            };
            octx.drawImage(
              oc,
              0,
              0,
              cur.width * 2,
              cur.height * 2,
              0,
              0,
              cur.width,
              cur.height
            );
          }
          ctx.drawImage(
            oc,
            0,
            0,
            cur.width,
            cur.height,
            0,
            0,
            canvas.width,
            canvas.height
          );
          var base64Image = canvas.toDataURL("image/jpeg");

          //console.log(base64Image);
          //window.cur_img.src = base64Image;
          //app.item[app.mykey] = base64Image;

          app.$emit("image", {
            key: app.mykey,
            value: base64Image,
          });
        };
        img.src = URL.createObjectURL(e.target.files[0]);
      });
  },
};


================================================
FILE: editor/editor.css
================================================
.edit {
  display: block;
  width: 50px;
  height: 50px;
  background-image: url(img/cog.png);
  background-size: cover;
  position: absolute;
  top: 25px;
  right: 25px;
  cursor: pointer;
}

.editor {
  overflow-y: auto;
}

#adder,
#designer,
#saver {
  position: fixed;
  top: 0;
  width: 300px;
  height: 100%;
  background-color: white;
  border-left: 1px solid #ddd;
  box-shadow: 0px 3px 15px rgba(0, 0, 0, 0.2);
  overflow-y: auto;
}

.editable > .container {
  border: 1px solid transparent;
}

.editable > .container:hover {
  border: 1px dashed #333;
  cursor: pointer;
}

.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.5s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

.slidein-right {
  width: 400px;
  position: fixed;
  z-index: 9999;
  top: 0;
  height: 100%;
  background-color: white;
  box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.5);
  right: 0px;
}

.slide-right-enter-active,
.slide-right-leave-active {
  transition: 0.5s ease;
}

.slide-right-enter-from,
.slide-right-leave-to {
  right: -400px;
}

.slidein-left {
  left: 0;
}

.slide-left-enter-active,
.slide-left-leave-active {
  transition: 0.5s ease;
}

.slide-left-enter-from,
.slide-left-leave-to {
  left: -300px;
}

.editor textarea {
  min-height: 200px;
  resize: none;
}

.editor-header {
  padding-bottom: 5px;
  background-color: #f8f8f8;
  padding: 10px;
  padding-left: 20px;
  padding-right: 20px;
  height: 50px;
  border-bottom: 1px solid #dddddd;
  position: fixed;
  z-index: 99;
}

.slidein-left .editor-header {
  width: 300px;
}

.slidein-right .editor-header {
  width: 400px;
}

.editor-header h4 {
  font-size: 16px;
  padding-top: 5px;
}

.close:hover {
  cursor: pointer;
}

.editor-content {
  padding: 20px;
  padding-top: 50px;
}

.editor-content:first-child {
  margin-top: 0;
}

.label {
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 14px;
  margin-bottom: 5px;
  margin-top: 20px;
  color: #212529;
}

.save {
  margin-top: 30px;
}

.box {
  display: block;
  border: 1px solid #ddd;
  margin-bottom: 10px;
}

.box:hover {
  background-color: #f8f8f8;
  cursor: pointer;
  text-decoration: none;
}

#dock {
  position: fixed;
  bottom: 15px;
  text-align: center;
  width: 300px;
  left: calc(50% - 150px);
}

#dock img {
  width: 60px;
  margin: 5px;
}

.grow {
  transition: all 0.2s ease-in-out;
}
.grow:hover {
  transform: scale(1.1);
  cursor: pointer;
}

#editor .btn-outline-danger {
  border: 1px solid #6c757d;
  color: #6c757d;
}

#editor .btn-primary {
  position: fixed;
  right: 15px;
  bottom: 15px;
  width: 370px;
}

.swatch {
  display: inline-block;
  vertical-align: top;
  width: 32px;
  height: 32px;
  margin-right: 11px;
  margin-bottom: 6px;
  border-radius: 6px;
  cursor: pointer;
  text-align: center;
  border: 1px solid #ddd;
}

.fa-center {
  margin-top: 8px;
}

.w-100px {
  width: 100px;
}

a.list-group-item {
  color: black;
}

a.list-group-item:hover {
  background-color: #f8f8f8;
  text-decoration: none;
  cursor: pointer;
}

.info {
  padding-top: 5px;
  color: #777;
}


================================================
FILE: editor/editor.mjs
================================================
import Picker from "./components/fa-picker.mjs";
import Add from "./components/add-content.mjs";
import Image from "./components/image-resize.mjs";
const html = String.raw;

const template = html`
  <transition name="slide-right">
    <div class="editor slidein-right" v-if="item" spellcheck="false">
      <div class="editor-header">
        <h4 class="float-left">Edit</h4>
        <div class="close" @click="item = false">&times;</div>
      </div>
      <div class="editor-content">
        <div v-for="(val, key) in fields">
          <div class="label">{{key.replace('_', ' ')}}</div>

          <input
            type="text"
            class="form-control"
            v-if="val == 'txt'"
            v-model="item[key]"
          />
          <textarea
            class="form-control"
            v-if="val == 'rte'"
            v-model="item[key]"
          ></textarea>
          <fa-picker
            v-if="val == 'icon'"
            v-bind:mykey="key"
            v-bind:value="item[key]"
            @input="setIcon"
          ></fa-picker>

          <image-resize
            v-if="val == 'img'"
            v-bind:mykey="key"
            @image="setImage"
          ></image-resize>
          <input
            v-if="val == 'vid'"
            type="text"
            class="form-control"
            v-model="item[key]"
          />
        </div>

        <span v-if="item.layout != 'header'">
          <div class="label">Options</div>
          <div class="btn-group w-100">
            <button
              class="btn btn-outline-secondary w-50"
              @click="moveItem(item.id)"
            >
              Move Down
            </button>
            <button
              class="btn btn-outline-secondary w-50"
              @click="deleteItem(item.id)"
            >
              Delete
            </button>
          </div>
        </span>

        <button class="btn btn-outline-success mb-5 w-100 save" @click="save">
          Save
        </button>
      </div>
    </div>
  </transition>

  <add-content v-bind:layouts="layouts" v-bind:entries="entries"></add-content>
`;

export default {
  template,

  props: ["layouts", "entries"],

  data() {
    return {
      item: false,
      fields: false,
    };
  },

  components: {
    "fa-picker": Picker,
    "add-content": Add,
    "image-resize": Image,
  },

  methods: {
    save: function () {
      console.log(JSON.stringify(this.entries));
      this.item = false;
    },
    setIcon: function (e) {
      this.item[e.key] = e.value;
    },
    setImage: function (e) {
      this.item[e.key] = e.value;
    },
    deleteItem: function (id) {
      let r = confirm("Are you sure you want to delete this item?");
      if (r == true) {
        this.entries.splice(
          this.entries.findIndex((x) => x.id === id),
          1
        );
        this.item = false;
      }
    },
    moveItem: function (id) {
      var from = this.entries.findIndex((x) => x.id == id);
      var to = from + 1;
      console.log(from);
      console.log(to);
      var f = this.entries.splice(from, 1)[0];
      this.entries.splice(to, 0, f);
    },
  },

  mounted() {
    //console.log('Editor component mounted.')

    var app = this;
    document.body.addEventListener("click", function (e) {
      if (e.target.closest(".editable")) {
        let el = e.target.closest(".editable");
        let id = el.id;
        app.item = app.entries.filter((x) => x.id === id)[0];

        let myfields = el.getAttribute("data-fields");
        let params = new URLSearchParams(myfields);
        myfields = Object.fromEntries(params.entries());
        //console.log(myfields);
        app.fields = myfields;
      }
    });
  },
};


================================================
FILE: editor/js/iconpicker/iconpicker-1.5.0.css
================================================
/*!
* IconPicker ('https://github.com/furcan/IconPicker')
* Version: 1.5.0 
* Author: Furkan MT ('https://github.com/furcan')
* Dependencies: Font Awesome Free v5.11.2 (https://fontawesome.com/license/free)
* Copyright 2019 IconPicker, MIT Licence ('https://opensource.org/licenses/MIT')*
*/

div#IconPickerModal {
display:none;
position: absolute;
z-index: 999999;
width: 95%;
max-width: 1440px;
left: 0;
right: 0;
top: 100px;
margin: auto;}

div#IconPickerModal:before {
transition:all .4s ease-in-out;
opacity: 0;
visibility: hidden;
content:"";
position: fixed;
z-index:-1;
left:0;
top:0;
width:100%;
height:100%;
background:rgba(0, 0, 0, 0.5);}

div#IconPickerModal.animate:before {
opacity: 1;
visibility: visible;}

div#IconPickerModal .ip-icons-content {
transition:all .4s ease-in-out;
transform:scale(.5);
opacity:0;
float: left;
width: 100%;
background: #ffffff;
box-shadow: 0 0 24px -8px rgba(0, 0, 0, 0.2);
border-radius: 20px;
padding: 20px;
position:relative;
z-index:2;}

div#IconPickerModal.animate .ip-icons-content {
transform:scale(1);
opacity:1;}

div#IconPickerModal .ip-icons-content .ip-icons-search {
border-bottom: 1px dashed #e8e8e8;
padding: 0 0 20px;
margin: 0 0 10px;
position:relative;
float: left;
width: 100%;}

div#IconPickerModal .ip-icons-content .ip-icons-search > input#IconPickerSearch {
transition: all .2s ease-in-out;
float: left;
width: 100%;
height:50px;
line-height:50px;
font-size: 18px;
color: #1e1e1e;
background: #fff;
font-weight: 400;
border: 1px solid #f4f4f4;
box-shadow:0 0 15px -8px rgba(0, 0, 0, 0.4);
border-radius: 50px;
padding: 0 50px 0 20px;}
div#IconPickerModal .ip-icons-content .ip-icons-search > input#IconPickerSearch:hover,
div#IconPickerModal .ip-icons-content .ip-icons-search > input#IconPickerSearch:focus {
border-color:#1e1e1e;}

div#IconPickerModal .ip-icons-content .ip-icons-search > i.placeholder-icon {
transition: all .2s ease-in-out;
position: absolute;
z-index: 2;
pointer-events: none;
right: 0;
top: 0;
width: 50px;
height: 50px;
border-radius: 50px;
font-size: 25px;
line-height: 50px;
text-align: center;
color: #eaeaea;}
div#IconPickerModal .ip-icons-content .ip-icons-search > input#IconPickerSearch:hover + i.placeholder-icon,
div#IconPickerModal .ip-icons-content .ip-icons-search > input#IconPickerSearch:focus + i.placeholder-icon {
color:#1e1e1e;}

div#IconPickerModal .ip-icons-content .ip-icons-search-results {
position:relative;
float: left;
width: 100%;}

div#IconPickerModal .ip-icons-content .ip-icons-search-results p.ip-no-results-found {
float: left;
width: 100%;
margin: 20px 0;
text-align: center;
font-size: 15px;
line-height: 1.4;
color: #9b9b9b;}

div#IconPickerModal .ip-icons-content .ip-icons-area {
padding: 10px;
max-height:400px;
overflow:hidden;
position:relative;
float: left;
width: 100%;}
div#IconPickerModal.show-all .ip-icons-content .ip-icons-area {
max-height:unset;
overflow:unset;}

div#IconPickerModal .ip-icons-content .ip-icons-area:before {
transition:all .2s ease-in-out;
content: "";
position: absolute;
z-index: 9;
width: 100%;
height: 60px;
left: 0;
bottom: 0;
box-shadow: 0 0 50px 25px rgba(255, 255, 255, 0.75);
background: rgba(255, 255, 255, 0.8);}
div#IconPickerModal.show-all .ip-icons-content .ip-icons-area:before {
opacity:0;
visibility:hidden;}

div#IconPickerModal .ip-icons-content .ip-icons-search-results > * > i,
div#IconPickerModal .ip-icons-content .ip-icons-area > i {
cursor:pointer;
position: relative;
transition:all .2s ease-in-out;
font-size: 21px;
line-height: 26px;
float: left;
border-radius:5px;
margin: 3px;
padding: 2px;
min-width: 30px;
text-align: center;}

div#IconPickerModal .ip-icons-content .ip-icons-search-results > * > i:hover,
div#IconPickerModal .ip-icons-content .ip-icons-area > i:hover {
transform:scale(1.8);
z-index: 2;
-moz-box-shadow: 0 0 14px -6px rgba(0, 0, 0, 0.5);
box-shadow: 0 0 16px -6px rgba(0, 0, 0, 0.5);
background:#fff;}

div#IconPickerModal .ip-icons-content .ip-icons-area > a.ip-show-all-icons {
transition: all .2s ease-in-out;
position: absolute;
width: 120px;
z-index: 10;
left: 0;
right: 0;
bottom: 10px;
margin: auto;
text-align: center;
box-shadow:0 0 24px -8px rgba(0, 0, 0, 0.2);
background: #fff;
color: #9b9b9b;
border: 1px solid #bcbcbc;
padding: 12px;
border-radius: 30px;
font-weight:500;
font-size: 13px;
line-height: 16px;}
div#IconPickerModal .ip-icons-content .ip-icons-area > a.ip-show-all-icons:hover {
color: #fff;
border-color: #1e1e1e;
background: #1e1e1e;}

div#IconPickerModal .ip-icons-content .ip-icons-footer {
border-top: 1px dashed #e8e8e8;
padding: 15px 0 0;
margin:10px 0 0;
float: left;
width: 100%;}

div#IconPickerModal .ip-icons-content .ip-icons-footer a.cancel {
transition: all .2s ease-in-out;
float: right;
color: #9b9b9b;
padding: 10px 18px;
border: 1px solid #bcbcbc;
border-radius: 20px;
font-size: 14px;
line-height: 15px;
font-weight: 500;}

div#IconPickerModal .ip-icons-content .ip-icons-footer a.cancel:hover {
color: #fff;
border-color: #1e1e1e;
background: #1e1e1e;}

div#IconPickerLoading {
transition: all .3s ease-in-out;
opacity: 1;
position: absolute;
z-index: 2;
width: 100%;
height: 100%;
background: #fff;
text-align: center;}

div#IconPickerLoading.hide {
opacity: 0;}

div#IconPickerLoading > svg {
width: 60px;
height: 60px;
position: absolute;
z-index: 2;
left: 0;
top: 0;
right: 0;
bottom: 60px;
margin: auto;}

================================================
FILE: editor/js/iconpicker/iconpicker-1.5.0.js
================================================
/*!
* IconPicker ('https://github.com/furcan/IconPicker')
* Version: 1.5.0 
* Author: Furkan MT ('https://github.com/furcan')
* Dependencies: Font Awesome Free v5.11.2 (https://fontawesome.com/license/free)
* Copyright 2019 IconPicker, MIT Licence ('https://opensource.org/licenses/MIT')*
*/

'use strict';

// IconPicker: Default Options on
var ipDefaultOptions = {
    jsonUrl: null,
    searchPlaceholder: 'Search Icon',
    showAllButton: 'Show All',
    cancelButton: 'Cancel',
    noResultsFound: 'No results found.',
    borderRadius: '20px',
}
var ipNewOptions;
var ipGithubUrl = 'https://github.com/furcan/IconPicker';
// IconPicker: Default Options off

// IconPicker: Extend Options on
var extendIconPicker = function () {
    var extended = {};
    var deep = false;
    var i = 0;
    if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') {
        deep = arguments[0];
        i++;
    }
    var merge = function (obj) {
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
                    extended[prop] = extendIconPicker(extended[prop], obj[prop]);
                } else {
                    extended[prop] = obj[prop];
                }
            }
        }
    };
    for (; i < arguments.length; i++) {
        merge(arguments[i]);
    }
    return extended;
};
// IconPicker: Extend Options off


// IconPicker: Main on
var IconPicker = {

    // init
    Init: function (ipUserOptions) {
        ipNewOptions = extendIconPicker(true, ipDefaultOptions, ipUserOptions);
    },

    // run
    Run: function (theButton, theCallback) {

        // IconPicker: Console Error Function on
        var ipConsoleError = function (errorMessage) {
            return console.error('%c IconPicker (Error) ', 'padding:2px;border-radius:20px;color:#fff;background:#f44336', '\n' + errorMessage);
        }
        // IconPicker: Console Error Function off

        // IconPicker: Console Log Function on
        var ipConsoleLog = function (errorMessage) {
            return console.log('%c IconPicker (Info) ', 'padding:2px;border-radius:20px;color:#fff;background:#00bcd4', '\n' + errorMessage);
        }
        // IconPicker: Console Log Function off

        // IconPicker: Check The Arguments For Proceed on
        if (arguments && arguments.length <= 2) {

            // query selector
            var ipButtons = document.querySelectorAll(theButton);

            // if button exist on the document
            if (ipButtons && ipButtons.length > 0) {
                for (var i = 0; i < ipButtons.length; i++) {

                    // IconPicker: Button Listeners -> Send XMLHttpRequest on
                    var ipButton = ipButtons[i];
                    ipButton.addEventListener('click', function () {
                        var jsonUrl = ipNewOptions.jsonUrl;
                        var inputElement = this.dataset.iconpickerInput;
                        var previewElement = this.dataset.iconpickerPreview;
                        var showAllButton = ipNewOptions.showAllButton;
                        if (!showAllButton || (showAllButton && showAllButton.length < 1)) {
                            showAllButton = ipDefaultOptions.showAllButton;
                        }
                        var cancelButton = ipNewOptions.cancelButton;
                        if (!cancelButton || (cancelButton && cancelButton.length < 1)) {
                            cancelButton = ipDefaultOptions.cancelButton;
                        }
                        var searchPlaceholder = ipNewOptions.searchPlaceholder;
                        if (!searchPlaceholder || (searchPlaceholder && searchPlaceholder.length < 1)) {
                            searchPlaceholder = ipDefaultOptions.searchPlaceholder;
                        }
                        var borderRadius = ipNewOptions.borderRadius;
                        if (!borderRadius || (borderRadius && borderRadius.length < 1)) {
                            borderRadius = ipDefaultOptions.borderRadius;
                        }

                        // check the json url on
                        if (!jsonUrl) {
                            ipConsoleError('You have to set the path of IconPicker JSON file to "jsonUrl" option. \n\nVisit to learn how: ' + ipGithubUrl);
                            return false;
                        }
                        // check the json url off

                        // check the input on
                        var checkInput = document.querySelectorAll(inputElement);
                        if (checkInput.length <= 0) {
                            ipConsoleError('You must define your Input element with it\'s ID or Class Name to your Button element data attribute. \n\nExample: \ndata-iconpicker-input="#MyIconInput" or \ndata-iconpicker-input=".my-icon-input" \n\nVisit to learn how: ' + ipGithubUrl);
                            return false;
                        }
                        // check the input off

                        // check the preview icon on
                        var checkPreviewIcon = document.querySelectorAll(previewElement);
                        if (checkPreviewIcon.length <= 0) {
                            ipConsoleLog('You can define your Preview Icon element with it\'s ID or Class Name to your Button element data attribute. \n\nExample: \ndata-iconpicker-preview="i#MyIconElement" or \ndata-iconpicker-preview="i.my-icon-element" \n\nVisit to learn how: ' + ipGithubUrl);
                        }
                        // check the preview icon off

                        // check the callback on
                        if (!theCallback && typeof theCallback !== 'function') {
                            theCallback = undefined;
                        }
                        // check the callback off

                        getIconListXmlHttpRequest(jsonUrl, showAllButton, cancelButton, searchPlaceholder, borderRadius, inputElement, previewElement, theCallback);

                    });
                    // IconPicker: Button Listeners -> Send XMLHttpRequest off

                }
            }
            // not exist
            else {
                ipConsoleError('You called the IconPicker with "' + theButton + '" selector, but there is no such element on the document.');
            }

        } else if (arguments && arguments.length > 2) {
            ipConsoleError('More parameters than allowed.');
            return false;
        } else {
            ipConsoleError('You have to call the IconPicker with an Element(Button or etc.) Class or ID. \n\nYou can also find the other required data attributes in the Documentation. \n\nVisit: ' + ipGithubUrl);
            return false;
        }
        // IconPicker: Check The Arguments For Proceed off


        // IconPicker: Get Library from JSON and AppendTo Body on
        var getIconListXmlHttpRequest = function (jsonUrl, buttonShowAll, buttonCancel, searchPlaceholder, borderRadius, inputElement, previewElement, theCallback) {

            // if chrome browser
            if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
                // check the protocol
                if (window.location.protocol.indexOf('http') <= -1) {
                    ipConsoleLog('Chrome Browser blocked this request by CORS policy.');
                    return false;
                }
            }

            // modal element
            var ipElement = document.getElementById('IconPickerModal');

            // if modal element doesn't exist on document send XMLHttpRequest
            if (!ipElement) {
                var xmlHttp = new XMLHttpRequest();
                xmlHttp.open('GET', jsonUrl, true);
                xmlHttp.setRequestHeader('Content-type', 'application/json; charset=utf-8');
                xmlHttp.send();
                xmlHttp.onreadystatechange = function () {
                    if (this.readyState === 4) {
                        if (this.status === 200) { // success
                            var data = this.responseText;
                            appendIconListToBody(data, buttonShowAll, buttonCancel, searchPlaceholder, borderRadius, inputElement, previewElement, theCallback);
                        } else {
                            ipConsoleError('XMLHttpRequest Failed.');
                        }
                    }
                };
            }
        }
        // IconPicker: Get Library from JSON and AppendTo Body off


        // IconPicker: Append Library to Body on
        var appendIconListToBody = function (data, buttonShowAll, buttonCancel, searchPlaceholder, borderRadius, inputElement, previewElement, theCallback) {

            // data
            var jsonData = JSON.parse(data);

            // icons
            var icons = '';
            for (var key in jsonData) {
                if (jsonData.hasOwnProperty(key)) {
                    var forObj = jsonData[key];
                    var icon = '<i data-search="' + forObj + '" data-class="' + forObj + '" class="first-icon select-icon ' + forObj + '"></i>';
                    icons += icon;
                }
            }

            // loading indicator
            var loadingIndicator = '<div id="IconPickerLoading"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="60" height="60" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid"><g transform="translate(25 50)"><circle cx="0" cy="0" r="9" fill="#1e1e1e" transform="scale(0.24 0.24)"><animateTransform attributeName="transform" type="scale" begin="-0.2666s" calcMode="spline" keySplines="0.3 0 0.7 1;0.3 0 0.7 1" values="0;1;0" keyTimes="0;0.5;1" dur="0.8s" repeatCount="indefinite"/></circle></g><g transform="translate(50 50)"><circle cx="0" cy="0" r="9" fill="#1e1e1e" transform="scale(0.00153 0.00153)"><animateTransform attributeName="transform" type="scale" begin="-0.1333s" calcMode="spline" keySplines="0.3 0 0.7 1;0.3 0 0.7 1" values="0;1;0" keyTimes="0;0.5;1" dur="0.8s" repeatCount="indefinite"/></circle></g><g transform="translate(75 50)"><circle cx="0" cy="0" r="9" fill="#1e1e1e" transform="scale(0.3 0.3)"><animateTransform attributeName="transform" type="scale" begin="0s" calcMode="spline" keySplines="0.3 0 0.7 1;0.3 0 0.7 1" values="0;1;0" keyTimes="0;0.5;1" dur="0.8s" repeatCount="indefinite"/></circle></g></svg></div>';

            // icons wrap
            var iconWrap = '<div class="ip-icons-content" style="border-radius:' + borderRadius + ';">' +
                '<div class="ip-icons-search"><input id="IconPickerSearch" type="text" spellcheck="false" autocomplete="off" placeholder="' + searchPlaceholder + '" style="border-radius:' + borderRadius + ';" /><i class="placeholder-icon fas fa-search"></i></div>' +
                '<div class="ip-icons-search-results"></div>' +
                '<div class="ip-icons-area">' +
                loadingIndicator +
                icons +
                '<a class="ip-show-all-icons" style="border-radius:' + borderRadius + ';">' + buttonShowAll + '</a>' +
                '</div>' +
                '<div class="ip-icons-footer"><a class="cancel" style="border-radius:' + borderRadius + ';">' + buttonCancel + '</a></div>' +
                '</div>';

            // create the modal element
            var IconPickerModal = document.createElement('div')
            IconPickerModal.id = 'IconPickerModal';
            IconPickerModal.innerHTML = iconWrap;

            // body
            var docBody = document.body;

            // append to body
            docBody.appendChild(IconPickerModal);

            // get the modal element
            var ipElement = document.getElementById(IconPickerModal.id);

            // modal element display css
            ipElement.style.display = 'block';

            // heights
            var ipHeight = parseInt(ipElement.offsetHeight);
            var winHeight = parseInt(window.innerHeight);

            // modal element position top css on
            var liveScrollTop = parseInt(window.pageYOffset || document.documentElement.scrollTop);
            var totalTopPos = liveScrollTop + ((winHeight - ipHeight) / 2);
            if (winHeight + 20 <= ipHeight) {
                totalTopPos = liveScrollTop;
            }
            ipElement.style.top = totalTopPos + 'px';
            // modal element position top css off

            // add css animation class to modal
            ipElement.classList.add('animate');

            // remove loading indicator on
            var loadingElement = document.getElementById('IconPickerLoading');
            var ltAnimate = setTimeout(function () {
                loadingElement.classList.add('hide');
                clearTimeout(ltAnimate);
            }, 600);
            var ltRemove = setTimeout(function () {
                loadingElement.parentNode.removeChild(loadingElement);
                clearTimeout(ltRemove);
            }, 900);
            // remove loading indicator off

            // show all button click listener on
            var showAllButtonElm = document.getElementById(IconPickerModal.id).getElementsByClassName('ip-show-all-icons')[0];
            showAllButtonElm.addEventListener('click', function () {
                ipElement.classList.add('show-all');
                this.parentNode.removeChild(this);
            }, false);
            // show all button click listener off

            // close and remove all on
            var removeIpElement = function (delay) {
                ipElement.classList.remove('animate');
                setTimeout(function () {
                    docBody.removeChild(ipElement);
                }, delay);
            }
            // close and remove all off

            // cancel button click listener on
            var cancelButtonElm = document.getElementById(IconPickerModal.id).getElementsByClassName('cancel')[0];
            cancelButtonElm.addEventListener('click', function () {
                removeIpElement(400);
            }, false);
            // cancel button click listener off

            // search input keyup listener on
            var searchInputElm = document.getElementById('IconPickerSearch');
            searchInputElm.addEventListener('keyup', function (e) {

                // keycodes
                var eKeyCode = e.keyCode;
                var eCode = e.code.toString().toLowerCase();

                // check space and backspace keyup
                var spaceOrBackspace = false;
                if (eKeyCode === 32 || eCode === 'space' || eKeyCode === 8 || eCode === 'backspace') {
                    spaceOrBackspace = true;
                }

                // cant type space
                if (eKeyCode === 32 || eCode === 'space') {
                    this.value = this.value.replace(' ', '');
                    return false;
                }

                // this val
                var searchVal = this.value.toString().toLowerCase();

                // define icons areas
                var firstIconsArea = document.getElementById(IconPickerModal.id).getElementsByClassName('ip-icons-area')[0];
                var searchResultArea = document.getElementById(IconPickerModal.id).getElementsByClassName('ip-icons-search-results')[0];

                // clear old results
                searchResultArea.innerHTML = '';

                // (if not space or backspace) and (if typed at least one char) able to search
                if (!spaceOrBackspace && searchVal.length > 0) {

                    // for "serch term" in Json
                    var tempIcons = '';
                    for (var key in jsonData) {
                        if (jsonData.hasOwnProperty(key)) {
                            var forObj = jsonData[key];
                            // if there is results create them
                            if (forObj.toString().indexOf(searchVal) > -1) {
                                firstIconsArea.style.display = 'none';
                                var tempIcon = '<i data-search="' + forObj + '" data-class="' + forObj + '" class="search-icon select-icon ' + forObj + '"></i>';
                                tempIcons += tempIcon;
                            }
                        }
                    }

                    // create a temp container
                    var tempResults = document.createElement('div');
                    tempResults.id = 'IconsTempResults';
                    tempResults.innerHTML = tempIcons;

                    // no results found on
                    if (tempIcons.length < 1) {
                        firstIconsArea.style.display = 'none';
                        var noResultsText = ipNewOptions.noResultsFound;
                        if (!noResultsText || (noResultsText && noResultsText.length < 1)) {
                            noResultsText = ipDefaultOptions.noResultsFound;
                        }
                        var noResultElm = '<p class="ip-no-results-found">' + noResultsText + '</p>';
                        tempResults.innerHTML = noResultElm;
                    }
                    // no results found off

                    // append temp container to results area
                    searchResultArea.appendChild(tempResults);

                    // event listener for each temp icon
                    eachIconEventListener('search');

                }
                // show first icons        
                else {
                    firstIconsArea.style.display = 'block';
                }

            }, false);
            // search input keyup listener off


            // each icon click listener on
            var eachIconEventListener = function (firstOrSearch) {

                var inputElm = document.querySelectorAll(inputElement);
                var previewElm = document.querySelectorAll(previewElement);

                // define icons on
                var eachIconElm;
                if (firstOrSearch === 'first') { // first
                    eachIconElm = document.getElementById(IconPickerModal.id).getElementsByClassName('first-icon');
                } else if (firstOrSearch === 'search') { // search
                    eachIconElm = document.getElementById(IconPickerModal.id).getElementsByClassName('search-icon');
                }
                // define icons off

                // add listeners each on
                for (var i = 0; i < eachIconElm.length; i++) {
                    var singleIconElm = eachIconElm[i];
                    singleIconElm.addEventListener('click', function (e) {
                        e.preventDefault();
                        var iconClassName = this.dataset.class;

                        // each input value on
                        for (var i = 0; i < inputElm.length; i++) {

                            var getTagName = inputElm[i].tagName.toString().toLowerCase();
                            // if an input or textarea element
                            if (getTagName === 'input' || getTagName === 'textarea') {
                                inputElm[i].value = iconClassName;
                            }
                            // else any of element
                            else {
                                inputElm[i].innerHTML = iconClassName;
                            }

                        }
                        // each input value off

                        // each preview on
                        for (var i = 0; i < previewElm.length; i++) {
                            previewElm[i].className = iconClassName;
                        }
                        // each preview off

                        // callback on
                        if (theCallback) {
                            theCallback();
                        }
                        // callback off

                        removeIpElement(400);
                    }, false);
                }
                // add listeners each off

            }
            // each icon click listener off

            // first icons listeners
            eachIconEventListener('first');

        }
        // IconPicker: Append Library to Body off
    },
}
// IconPicker: Main off

================================================
FILE: editor/js/iconpicker/iconpicker-1.5.0.json
================================================
{
  "0":"fab fa-500px",
  "1":"fab fa-accessible-icon",
  "2":"fab fa-accusoft",
  "3":"fab fa-acquisitions-incorporated",
  "4":"fas fa-ad",
  "5":"fas fa-address-book",
  "6":"far fa-address-book",
  "7":"fas fa-address-card",
  "8":"far fa-address-card",
  "9":"fas fa-adjust",
  "10":"fab fa-adn",
  "11":"fab fa-adobe",
  "12":"fab fa-adversal",
  "13":"fab fa-affiliatetheme",
  "14":"fas fa-air-freshener",
  "15":"fab fa-airbnb",
  "16":"fab fa-algolia",
  "17":"fas fa-align-center",
  "18":"fas fa-align-justify",
  "19":"fas fa-align-left",
  "20":"fas fa-align-right",
  "21":"fab fa-alipay",
  "22":"fas fa-allergies",
  "23":"fab fa-amazon",
  "24":"fab fa-amazon-pay",
  "25":"fas fa-ambulance",
  "26":"fas fa-american-sign-language-interpreting",
  "27":"fab fa-amilia",
  "28":"fas fa-anchor",
  "29":"fab fa-android",
  "30":"fab fa-angellist",
  "31":"fas fa-angle-double-down",
  "32":"fas fa-angle-double-left",
  "33":"fas fa-angle-double-right",
  "34":"fas fa-angle-double-up",
  "35":"fas fa-angle-down",
  "36":"fas fa-angle-left",
  "37":"fas fa-angle-right",
  "38":"fas fa-angle-up",
  "39":"fas fa-angry",
  "40":"far fa-angry",
  "41":"fab fa-angrycreative",
  "42":"fab fa-angular",
  "43":"fas fa-ankh",
  "44":"fab fa-app-store",
  "45":"fab fa-app-store-ios",
  "46":"fab fa-apper",
  "47":"fab fa-apple",
  "48":"fas fa-apple-alt",
  "49":"fab fa-apple-pay",
  "50":"fas fa-archive",
  "51":"fas fa-archway",
  "52":"fas fa-arrow-alt-circle-down",
  "53":"far fa-arrow-alt-circle-down",
  "54":"fas fa-arrow-alt-circle-left",
  "55":"far fa-arrow-alt-circle-left",
  "56":"fas fa-arrow-alt-circle-right",
  "57":"far fa-arrow-alt-circle-right",
  "58":"fas fa-arrow-alt-circle-up",
  "59":"far fa-arrow-alt-circle-up",
  "60":"fas fa-arrow-circle-down",
  "61":"fas fa-arrow-circle-left",
  "62":"fas fa-arrow-circle-right",
  "63":"fas fa-arrow-circle-up",
  "64":"fas fa-arrow-down",
  "65":"fas fa-arrow-left",
  "66":"fas fa-arrow-right",
  "67":"fas fa-arrow-up",
  "68":"fas fa-arrows-alt",
  "69":"fas fa-arrows-alt-h",
  "70":"fas fa-arrows-alt-v",
  "71":"fab fa-artstation",
  "72":"fas fa-assistive-listening-systems",
  "73":"fas fa-asterisk",
  "74":"fab fa-asymmetrik",
  "75":"fas fa-at",
  "76":"fas fa-atlas",
  "77":"fab fa-atlassian",
  "78":"fas fa-atom",
  "79":"fab fa-audible",
  "80":"fas fa-audio-description",
  "81":"fab fa-autoprefixer",
  "82":"fab fa-avianex",
  "83":"fab fa-aviato",
  "84":"fas fa-award",
  "85":"fab fa-aws",
  "86":"fas fa-baby",
  "87":"fas fa-baby-carriage",
  "88":"fas fa-backspace",
  "89":"fas fa-backward",
  "90":"fas fa-bacon",
  "91":"fas fa-balance-scale",
  "92":"fas fa-balance-scale-left",
  "93":"fas fa-balance-scale-right",
  "94":"fas fa-ban",
  "95":"fas fa-band-aid",
  "96":"fab fa-bandcamp",
  "97":"fas fa-barcode",
  "98":"fas fa-bars",
  "99":"fas fa-baseball-ball",
  "100":"fas fa-basketball-ball",
  "101":"fas fa-bath",
  "102":"fas fa-battery-empty",
  "103":"fas fa-battery-full",
  "104":"fas fa-battery-half",
  "105":"fas fa-battery-quarter",
  "106":"fas fa-battery-three-quarters",
  "107":"fab fa-battle-net",
  "108":"fas fa-bed",
  "109":"fas fa-beer",
  "110":"fab fa-behance",
  "111":"fab fa-behance-square",
  "112":"fas fa-bell",
  "113":"far fa-bell",
  "114":"fas fa-bell-slash",
  "115":"far fa-bell-slash",
  "116":"fas fa-bezier-curve",
  "117":"fas fa-bible",
  "118":"fas fa-bicycle",
  "119":"fas fa-biking",
  "120":"fab fa-bimobject",
  "121":"fas fa-binoculars",
  "122":"fas fa-biohazard",
  "123":"fas fa-birthday-cake",
  "124":"fab fa-bitbucket",
  "125":"fab fa-bitcoin",
  "126":"fab fa-bity",
  "127":"fab fa-black-tie",
  "128":"fab fa-blackberry",
  "129":"fas fa-blender",
  "130":"fas fa-blender-phone",
  "131":"fas fa-blind",
  "132":"fas fa-blog",
  "133":"fab fa-blogger",
  "134":"fab fa-blogger-b",
  "135":"fab fa-bluetooth",
  "136":"fab fa-bluetooth-b",
  "137":"fas fa-bold",
  "138":"fas fa-bolt",
  "139":"fas fa-bomb",
  "140":"fas fa-bone",
  "141":"fas fa-bong",
  "142":"fas fa-book",
  "143":"fas fa-book-dead",
  "144":"fas fa-book-medical",
  "145":"fas fa-book-open",
  "146":"fas fa-book-reader",
  "147":"fas fa-bookmark",
  "148":"far fa-bookmark",
  "149":"fab fa-bootstrap",
  "150":"fas fa-border-all",
  "151":"fas fa-border-none",
  "152":"fas fa-border-style",
  "153":"fas fa-bowling-ball",
  "154":"fas fa-box",
  "155":"fas fa-box-open",
  "156":"fas fa-boxes",
  "157":"fas fa-braille",
  "158":"fas fa-brain",
  "159":"fas fa-bread-slice",
  "160":"fas fa-briefcase",
  "161":"fas fa-briefcase-medical",
  "162":"fas fa-broadcast-tower",
  "163":"fas fa-broom",
  "164":"fas fa-brush",
  "165":"fab fa-btc",
  "166":"fab fa-buffer",
  "167":"fas fa-bug",
  "168":"fas fa-building",
  "169":"far fa-building",
  "170":"fas fa-bullhorn",
  "171":"fas fa-bullseye",
  "172":"fas fa-burn",
  "173":"fab fa-buromobelexperte",
  "174":"fas fa-bus",
  "175":"fas fa-bus-alt",
  "176":"fas fa-business-time",
  "177":"fab fa-buy-n-large",
  "178":"fab fa-buysellads",
  "179":"fas fa-calculator",
  "180":"fas fa-calendar",
  "181":"far fa-calendar",
  "182":"fas fa-calendar-alt",
  "183":"far fa-calendar-alt",
  "184":"fas fa-calendar-check",
  "185":"far fa-calendar-check",
  "186":"fas fa-calendar-day",
  "187":"fas fa-calendar-minus",
  "188":"far fa-calendar-minus",
  "189":"fas fa-calendar-plus",
  "190":"far fa-calendar-plus",
  "191":"fas fa-calendar-times",
  "192":"far fa-calendar-times",
  "193":"fas fa-calendar-week",
  "194":"fas fa-camera",
  "195":"fas fa-camera-retro",
  "196":"fas fa-campground",
  "197":"fab fa-canadian-maple-leaf",
  "198":"fas fa-candy-cane",
  "199":"fas fa-cannabis",
  "200":"fas fa-capsules",
  "201":"fas fa-car",
  "202":"fas fa-car-alt",
  "203":"fas fa-car-battery",
  "204":"fas fa-car-crash",
  "205":"fas fa-car-side",
  "206":"fas fa-caret-down",
  "207":"fas fa-caret-left",
  "208":"fas fa-caret-right",
  "209":"fas fa-caret-square-down",
  "210":"far fa-caret-square-down",
  "211":"fas fa-caret-square-left",
  "212":"far fa-caret-square-left",
  "213":"fas fa-caret-square-right",
  "214":"far fa-caret-square-right",
  "215":"fas fa-caret-square-up",
  "216":"far fa-caret-square-up",
  "217":"fas fa-caret-up",
  "218":"fas fa-carrot",
  "219":"fas fa-cart-arrow-down",
  "220":"fas fa-cart-plus",
  "221":"fas fa-cash-register",
  "222":"fas fa-cat",
  "223":"fab fa-cc-amazon-pay",
  "224":"fab fa-cc-amex",
  "225":"fab fa-cc-apple-pay",
  "226":"fab fa-cc-diners-club",
  "227":"fab fa-cc-discover",
  "228":"fab fa-cc-jcb",
  "229":"fab fa-cc-mastercard",
  "230":"fab fa-cc-paypal",
  "231":"fab fa-cc-stripe",
  "232":"fab fa-cc-visa",
  "233":"fab fa-centercode",
  "234":"fab fa-centos",
  "235":"fas fa-certificate",
  "236":"fas fa-chair",
  "237":"fas fa-chalkboard",
  "238":"fas fa-chalkboard-teacher",
  "239":"fas fa-charging-station",
  "240":"fas fa-chart-area",
  "241":"fas fa-chart-bar",
  "242":"far fa-chart-bar",
  "243":"fas fa-chart-line",
  "244":"fas fa-chart-pie",
  "245":"fas fa-check",
  "246":"fas fa-check-circle",
  "247":"far fa-check-circle",
  "248":"fas fa-check-double",
  "249":"fas fa-check-square",
  "250":"far fa-check-square",
  "251":"fas fa-cheese",
  "252":"fas fa-chess",
  "253":"fas fa-chess-bishop",
  "254":"fas fa-chess-board",
  "255":"fas fa-chess-king",
  "256":"fas fa-chess-knight",
  "257":"fas fa-chess-pawn",
  "258":"fas fa-chess-queen",
  "259":"fas fa-chess-rook",
  "260":"fas fa-chevron-circle-down",
  "261":"fas fa-chevron-circle-left",
  "262":"fas fa-chevron-circle-right",
  "263":"fas fa-chevron-circle-up",
  "264":"fas fa-chevron-down",
  "265":"fas fa-chevron-left",
  "266":"fas fa-chevron-right",
  "267":"fas fa-chevron-up",
  "268":"fas fa-child",
  "269":"fab fa-chrome",
  "270":"fab fa-chromecast",
  "271":"fas fa-church",
  "272":"fas fa-circle",
  "273":"far fa-circle",
  "274":"fas fa-circle-notch",
  "275":"fas fa-city",
  "276":"fas fa-clinic-medical",
  "277":"fas fa-clipboard",
  "278":"far fa-clipboard",
  "279":"fas fa-clipboard-check",
  "280":"fas fa-clipboard-list",
  "281":"fas fa-clock",
  "282":"far fa-clock",
  "283":"fas fa-clone",
  "284":"far fa-clone",
  "285":"fas fa-closed-captioning",
  "286":"far fa-closed-captioning",
  "287":"fas fa-cloud",
  "288":"fas fa-cloud-download-alt",
  "289":"fas fa-cloud-meatball",
  "290":"fas fa-cloud-moon",
  "291":"fas fa-cloud-moon-rain",
  "292":"fas fa-cloud-rain",
  "293":"fas fa-cloud-showers-heavy",
  "294":"fas fa-cloud-sun",
  "295":"fas fa-cloud-sun-rain",
  "296":"fas fa-cloud-upload-alt",
  "297":"fab fa-cloudscale",
  "298":"fab fa-cloudsmith",
  "299":"fab fa-cloudversify",
  "300":"fas fa-cocktail",
  "301":"fas fa-code",
  "302":"fas fa-code-branch",
  "303":"fab fa-codepen",
  "304":"fab fa-codiepie",
  "305":"fas fa-coffee",
  "306":"fas fa-cog",
  "307":"fas fa-cogs",
  "308":"fas fa-coins",
  "309":"fas fa-columns",
  "310":"fas fa-comment",
  "311":"far fa-comment",
  "312":"fas fa-comment-alt",
  "313":"far fa-comment-alt",
  "314":"fas fa-comment-dollar",
  "315":"fas fa-comment-dots",
  "316":"far fa-comment-dots",
  "317":"fas fa-comment-medical",
  "318":"fas fa-comment-slash",
  "319":"fas fa-comments",
  "320":"far fa-comments",
  "321":"fas fa-comments-dollar",
  "322":"fas fa-compact-disc",
  "323":"fas fa-compass",
  "324":"far fa-compass",
  "325":"fas fa-compress",
  "326":"fas fa-compress-arrows-alt",
  "327":"fas fa-concierge-bell",
  "328":"fab fa-confluence",
  "329":"fab fa-connectdevelop",
  "330":"fab fa-contao",
  "331":"fas fa-cookie",
  "332":"fas fa-cookie-bite",
  "333":"fas fa-copy",
  "334":"far fa-copy",
  "335":"fas fa-copyright",
  "336":"far fa-copyright",
  "337":"fab fa-cotton-bureau",
  "338":"fas fa-couch",
  "339":"fab fa-cpanel",
  "340":"fab fa-creative-commons",
  "341":"fab fa-creative-commons-by",
  "342":"fab fa-creative-commons-nc",
  "343":"fab fa-creative-commons-nc-eu",
  "344":"fab fa-creative-commons-nc-jp",
  "345":"fab fa-creative-commons-nd",
  "346":"fab fa-creative-commons-pd",
  "347":"fab fa-creative-commons-pd-alt",
  "348":"fab fa-creative-commons-remix",
  "349":"fab fa-creative-commons-sa",
  "350":"fab fa-creative-commons-sampling",
  "351":"fab fa-creative-commons-sampling-plus",
  "352":"fab fa-creative-commons-share",
  "353":"fab fa-creative-commons-zero",
  "354":"fas fa-credit-card",
  "355":"far fa-credit-card",
  "356":"fab fa-critical-role",
  "357":"fas fa-crop",
  "358":"fas fa-crop-alt",
  "359":"fas fa-cross",
  "360":"fas fa-crosshairs",
  "361":"fas fa-crow",
  "362":"fas fa-crown",
  "363":"fas fa-crutch",
  "364":"fab fa-css3",
  "365":"fab fa-css3-alt",
  "366":"fas fa-cube",
  "367":"fas fa-cubes",
  "368":"fas fa-cut",
  "369":"fab fa-cuttlefish",
  "370":"fab fa-d-and-d",
  "371":"fab fa-d-and-d-beyond",
  "372":"fab fa-dashcube",
  "373":"fas fa-database",
  "374":"fas fa-deaf",
  "375":"fab fa-delicious",
  "376":"fas fa-democrat",
  "377":"fab fa-deploydog",
  "378":"fab fa-deskpro",
  "379":"fas fa-desktop",
  "380":"fab fa-dev",
  "381":"fab fa-deviantart",
  "382":"fas fa-dharmachakra",
  "383":"fab fa-dhl",
  "384":"fas fa-diagnoses",
  "385":"fab fa-diaspora",
  "386":"fas fa-dice",
  "387":"fas fa-dice-d20",
  "388":"fas fa-dice-d6",
  "389":"fas fa-dice-five",
  "390":"fas fa-dice-four",
  "391":"fas fa-dice-one",
  "392":"fas fa-dice-six",
  "393":"fas fa-dice-three",
  "394":"fas fa-dice-two",
  "395":"fab fa-digg",
  "396":"fab fa-digital-ocean",
  "397":"fas fa-digital-tachograph",
  "398":"fas fa-directions",
  "399":"fab fa-discord",
  "400":"fab fa-discourse",
  "401":"fas fa-divide",
  "402":"fas fa-dizzy",
  "403":"far fa-dizzy",
  "404":"fas fa-dna",
  "405":"fab fa-dochub",
  "406":"fab fa-docker",
  "407":"fas fa-dog",
  "408":"fas fa-dollar-sign",
  "409":"fas fa-dolly",
  "410":"fas fa-dolly-flatbed",
  "411":"fas fa-donate",
  "412":"fas fa-door-closed",
  "413":"fas fa-door-open",
  "414":"fas fa-dot-circle",
  "415":"far fa-dot-circle",
  "416":"fas fa-dove",
  "417":"fas fa-download",
  "418":"fab fa-draft2digital",
  "419":"fas fa-drafting-compass",
  "420":"fas fa-dragon",
  "421":"fas fa-draw-polygon",
  "422":"fab fa-dribbble",
  "423":"fab fa-dribbble-square",
  "424":"fab fa-dropbox",
  "425":"fas fa-drum",
  "426":"fas fa-drum-steelpan",
  "427":"fas fa-drumstick-bite",
  "428":"fab fa-drupal",
  "429":"fas fa-dumbbell",
  "430":"fas fa-dumpster",
  "431":"fas fa-dumpster-fire",
  "432":"fas fa-dungeon",
  "433":"fab fa-dyalog",
  "434":"fab fa-earlybirds",
  "435":"fab fa-ebay",
  "436":"fab fa-edge",
  "437":"fas fa-edit",
  "438":"far fa-edit",
  "439":"fas fa-egg",
  "440":"fas fa-eject",
  "441":"fab fa-elementor",
  "442":"fas fa-ellipsis-h",
  "443":"fas fa-ellipsis-v",
  "444":"fab fa-ello",
  "445":"fab fa-ember",
  "446":"fab fa-empire",
  "447":"fas fa-envelope",
  "448":"far fa-envelope",
  "449":"fas fa-envelope-open",
  "450":"far fa-envelope-open",
  "451":"fas fa-envelope-open-text",
  "452":"fas fa-envelope-square",
  "453":"fab fa-envira",
  "454":"fas fa-equals",
  "455":"fas fa-eraser",
  "456":"fab fa-erlang",
  "457":"fab fa-ethereum",
  "458":"fas fa-ethernet",
  "459":"fab fa-etsy",
  "460":"fas fa-euro-sign",
  "461":"fab fa-evernote",
  "462":"fas fa-exchange-alt",
  "463":"fas fa-exclamation",
  "464":"fas fa-exclamation-circle",
  "465":"fas fa-exclamation-triangle",
  "466":"fas fa-expand",
  "467":"fas fa-expand-arrows-alt",
  "468":"fab fa-expeditedssl",
  "469":"fas fa-external-link-alt",
  "470":"fas fa-external-link-square-alt",
  "471":"fas fa-eye",
  "472":"far fa-eye",
  "473":"fas fa-eye-dropper",
  "474":"fas fa-eye-slash",
  "475":"far fa-eye-slash",
  "476":"fab fa-facebook",
  "477":"fab fa-facebook-f",
  "478":"fab fa-facebook-messenger",
  "479":"fab fa-facebook-square",
  "480":"fas fa-fan",
  "481":"fab fa-fantasy-flight-games",
  "482":"fas fa-fast-backward",
  "483":"fas fa-fast-forward",
  "484":"fas fa-fax",
  "485":"fas fa-feather",
  "486":"fas fa-feather-alt",
  "487":"fab fa-fedex",
  "488":"fab fa-fedora",
  "489":"fas fa-female",
  "490":"fas fa-fighter-jet",
  "491":"fab fa-figma",
  "492":"fas fa-file",
  "493":"far fa-file",
  "494":"fas fa-file-alt",
  "495":"far fa-file-alt",
  "496":"fas fa-file-archive",
  "497":"far fa-file-archive",
  "498":"fas fa-file-audio",
  "499":"far fa-file-audio",
  "500":"fas fa-file-code",
  "501":"far fa-file-code",
  "502":"fas fa-file-contract",
  "503":"fas fa-file-csv",
  "504":"fas fa-file-download",
  "505":"fas fa-file-excel",
  "506":"far fa-file-excel",
  "507":"fas fa-file-export",
  "508":"fas fa-file-image",
  "509":"far fa-file-image",
  "510":"fas fa-file-import",
  "511":"fas fa-file-invoice",
  "512":"fas fa-file-invoice-dollar",
  "513":"fas fa-file-medical",
  "514":"fas fa-file-medical-alt",
  "515":"fas fa-file-pdf",
  "516":"far fa-file-pdf",
  "517":"fas fa-file-powerpoint",
  "518":"far fa-file-powerpoint",
  "519":"fas fa-file-prescription",
  "520":"fas fa-file-signature",
  "521":"fas fa-file-upload",
  "522":"fas fa-file-video",
  "523":"far fa-file-video",
  "524":"fas fa-file-word",
  "525":"far fa-file-word",
  "526":"fas fa-fill",
  "527":"fas fa-fill-drip",
  "528":"fas fa-film",
  "529":"fas fa-filter",
  "530":"fas fa-fingerprint",
  "531":"fas fa-fire",
  "532":"fas fa-fire-alt",
  "533":"fas fa-fire-extinguisher",
  "534":"fab fa-firefox",
  "535":"fas fa-first-aid",
  "536":"fab fa-first-order",
  "537":"fab fa-first-order-alt",
  "538":"fab fa-firstdraft",
  "539":"fas fa-fish",
  "540":"fas fa-fist-raised",
  "541":"fas fa-flag",
  "542":"far fa-flag",
  "543":"fas fa-flag-checkered",
  "544":"fas fa-flag-usa",
  "545":"fas fa-flask",
  "546":"fab fa-flickr",
  "547":"fab fa-flipboard",
  "548":"fas fa-flushed",
  "549":"far fa-flushed",
  "550":"fab fa-fly",
  "551":"fas fa-folder",
  "552":"far fa-folder",
  "553":"fas fa-folder-minus",
  "554":"fas fa-folder-open",
  "555":"far fa-folder-open",
  "556":"fas fa-folder-plus",
  "557":"fas fa-font",
  "558":"fab fa-font-awesome",
  "559":"fab fa-font-awesome-alt",
  "560":"fab fa-font-awesome-flag",
  "561":"fab fa-fonticons",
  "562":"fab fa-fonticons-fi",
  "563":"fas fa-football-ball",
  "564":"fab fa-fort-awesome",
  "565":"fab fa-fort-awesome-alt",
  "566":"fab fa-forumbee",
  "567":"fas fa-forward",
  "568":"fab fa-foursquare",
  "569":"fab fa-free-code-camp",
  "570":"fab fa-freebsd",
  "571":"fas fa-frog",
  "572":"fas fa-frown",
  "573":"far fa-frown",
  "574":"fas fa-frown-open",
  "575":"far fa-frown-open",
  "576":"fab fa-fulcrum",
  "577":"fas fa-funnel-dollar",
  "578":"fas fa-futbol",
  "579":"far fa-futbol",
  "580":"fab fa-galactic-republic",
  "581":"fab fa-galactic-senate",
  "582":"fas fa-gamepad",
  "583":"fas fa-gas-pump",
  "584":"fas fa-gavel",
  "585":"fas fa-gem",
  "586":"far fa-gem",
  "587":"fas fa-genderless",
  "588":"fab fa-get-pocket",
  "589":"fab fa-gg",
  "590":"fab fa-gg-circle",
  "591":"fas fa-ghost",
  "592":"fas fa-gift",
  "593":"fas fa-gifts",
  "594":"fab fa-git",
  "595":"fab fa-git-alt",
  "596":"fab fa-git-square",
  "597":"fab fa-github",
  "598":"fab fa-github-alt",
  "599":"fab fa-github-square",
  "600":"fab fa-gitkraken",
  "601":"fab fa-gitlab",
  "602":"fab fa-gitter",
  "603":"fas fa-glass-cheers",
  "604":"fas fa-glass-martini",
  "605":"fas fa-glass-martini-alt",
  "606":"fas fa-glass-whiskey",
  "607":"fas fa-glasses",
  "608":"fab fa-glide",
  "609":"fab fa-glide-g",
  "610":"fas fa-globe",
  "611":"fas fa-globe-africa",
  "612":"fas fa-globe-americas",
  "613":"fas fa-globe-asia",
  "614":"fas fa-globe-europe",
  "615":"fab fa-gofore",
  "616":"fas fa-golf-ball",
  "617":"fab fa-goodreads",
  "618":"fab fa-goodreads-g",
  "619":"fab fa-google",
  "620":"fab fa-google-drive",
  "621":"fab fa-google-play",
  "622":"fab fa-google-plus",
  "623":"fab fa-google-plus-g",
  "624":"fab fa-google-plus-square",
  "625":"fab fa-google-wallet",
  "626":"fas fa-gopuram",
  "627":"fas fa-graduation-cap",
  "628":"fab fa-gratipay",
  "629":"fab fa-grav",
  "630":"fas fa-greater-than",
  "631":"fas fa-greater-than-equal",
  "632":"fas fa-grimace",
  "633":"far fa-grimace",
  "634":"fas fa-grin",
  "635":"far fa-grin",
  "636":"fas fa-grin-alt",
  "637":"far fa-grin-alt",
  "638":"fas fa-grin-beam",
  "639":"far fa-grin-beam",
  "640":"fas fa-grin-beam-sweat",
  "641":"far fa-grin-beam-sweat",
  "642":"fas fa-grin-hearts",
  "643":"far fa-grin-hearts",
  "644":"fas fa-grin-squint",
  "645":"far fa-grin-squint",
  "646":"fas fa-grin-squint-tears",
  "647":"far fa-grin-squint-tears",
  "648":"fas fa-grin-stars",
  "649":"far fa-grin-stars",
  "650":"fas fa-grin-tears",
  "651":"far fa-grin-tears",
  "652":"fas fa-grin-tongue",
  "653":"far fa-grin-tongue",
  "654":"fas fa-grin-tongue-squint",
  "655":"far fa-grin-tongue-squint",
  "656":"fas fa-grin-tongue-wink",
  "657":"far fa-grin-tongue-wink",
  "658":"fas fa-grin-wink",
  "659":"far fa-grin-wink",
  "660":"fas fa-grip-horizontal",
  "661":"fas fa-grip-lines",
  "662":"fas fa-grip-lines-vertical",
  "663":"fas fa-grip-vertical",
  "664":"fab fa-gripfire",
  "665":"fab fa-grunt",
  "666":"fas fa-guitar",
  "667":"fab fa-gulp",
  "668":"fas fa-h-square",
  "669":"fab fa-hacker-news",
  "670":"fab fa-hacker-news-square",
  "671":"fab fa-hackerrank",
  "672":"fas fa-hamburger",
  "673":"fas fa-hammer",
  "674":"fas fa-hamsa",
  "675":"fas fa-hand-holding",
  "676":"fas fa-hand-holding-heart",
  "677":"fas fa-hand-holding-usd",
  "678":"fas fa-hand-lizard",
  "679":"far fa-hand-lizard",
  "680":"fas fa-hand-middle-finger",
  "681":"fas fa-hand-paper",
  "682":"far fa-hand-paper",
  "683":"fas fa-hand-peace",
  "684":"far fa-hand-peace",
  "685":"fas fa-hand-point-down",
  "686":"far fa-hand-point-down",
  "687":"fas fa-hand-point-left",
  "688":"far fa-hand-point-left",
  "689":"fas fa-hand-point-right",
  "690":"far fa-hand-point-right",
  "691":"fas fa-hand-point-up",
  "692":"far fa-hand-point-up",
  "693":"fas fa-hand-pointer",
  "694":"far fa-hand-pointer",
  "695":"fas fa-hand-rock",
  "696":"far fa-hand-rock",
  "697":"fas fa-hand-scissors",
  "698":"far fa-hand-scissors",
  "699":"fas fa-hand-spock",
  "700":"far fa-hand-spock",
  "701":"fas fa-hands",
  "702":"fas fa-hands-helping",
  "703":"fas fa-handshake",
  "704":"far fa-handshake",
  "705":"fas fa-hanukiah",
  "706":"fas fa-hard-hat",
  "707":"fas fa-hashtag",
  "708":"fas fa-hat-cowboy",
  "709":"fas fa-hat-cowboy-side",
  "710":"fas fa-hat-wizard",
  "711":"fas fa-haykal",
  "712":"fas fa-hdd",
  "713":"far fa-hdd",
  "714":"fas fa-heading",
  "715":"fas fa-headphones",
  "716":"fas fa-headphones-alt",
  "717":"fas fa-headset",
  "718":"fas fa-heart",
  "719":"far fa-heart",
  "720":"fas fa-heart-broken",
  "721":"fas fa-heartbeat",
  "722":"fas fa-helicopter",
  "723":"fas fa-highlighter",
  "724":"fas fa-hiking",
  "725":"fas fa-hippo",
  "726":"fab fa-hips",
  "727":"fab fa-hire-a-helper",
  "728":"fas fa-history",
  "729":"fas fa-hockey-puck",
  "730":"fas fa-holly-berry",
  "731":"fas fa-home",
  "732":"fab fa-hooli",
  "733":"fab fa-hornbill",
  "734":"fas fa-horse",
  "735":"fas fa-horse-head",
  "736":"fas fa-hospital",
  "737":"far fa-hospital",
  "738":"fas fa-hospital-alt",
  "739":"fas fa-hospital-symbol",
  "740":"fas fa-hot-tub",
  "741":"fas fa-hotdog",
  "742":"fas fa-hotel",
  "743":"fab fa-hotjar",
  "744":"fas fa-hourglass",
  "745":"far fa-hourglass",
  "746":"fas fa-hourglass-end",
  "747":"fas fa-hourglass-half",
  "748":"fas fa-hourglass-start",
  "749":"fas fa-house-damage",
  "750":"fab fa-houzz",
  "751":"fas fa-hryvnia",
  "752":"fab fa-html5",
  "753":"fab fa-hubspot",
  "754":"fas fa-i-cursor",
  "755":"fas fa-ice-cream",
  "756":"fas fa-icicles",
  "757":"fas fa-icons",
  "758":"fas fa-id-badge",
  "759":"far fa-id-badge",
  "760":"fas fa-id-card",
  "761":"far fa-id-card",
  "762":"fas fa-id-card-alt",
  "763":"fas fa-igloo",
  "764":"fas fa-image",
  "765":"far fa-image",
  "766":"fas fa-images",
  "767":"far fa-images",
  "768":"fab fa-imdb",
  "769":"fas fa-inbox",
  "770":"fas fa-indent",
  "771":"fas fa-industry",
  "772":"fas fa-infinity",
  "773":"fas fa-info",
  "774":"fas fa-info-circle",
  "775":"fab fa-instagram",
  "776":"fab fa-intercom",
  "777":"fab fa-internet-explorer",
  "778":"fab fa-invision",
  "779":"fab fa-ioxhost",
  "780":"fas fa-italic",
  "781":"fab fa-itch-io",
  "782":"fab fa-itunes",
  "783":"fab fa-itunes-note",
  "784":"fab fa-java",
  "785":"fas fa-jedi",
  "786":"fab fa-jedi-order",
  "787":"fab fa-jenkins",
  "788":"fab fa-jira",
  "789":"fab fa-joget",
  "790":"fas fa-joint",
  "791":"fab fa-joomla",
  "792":"fas fa-journal-whills",
  "793":"fab fa-js",
  "794":"fab fa-js-square",
  "795":"fab fa-jsfiddle",
  "796":"fas fa-kaaba",
  "797":"fab fa-kaggle",
  "798":"fas fa-key",
  "799":"fab fa-keybase",
  "800":"fas fa-keyboard",
  "801":"far fa-keyboard",
  "802":"fab fa-keycdn",
  "803":"fas fa-khanda",
  "804":"fab fa-kickstarter",
  "805":"fab fa-kickstarter-k",
  "806":"fas fa-kiss",
  "807":"far fa-kiss",
  "808":"fas fa-kiss-beam",
  "809":"far fa-kiss-beam",
  "810":"fas fa-kiss-wink-heart",
  "811":"far fa-kiss-wink-heart",
  "812":"fas fa-kiwi-bird",
  "813":"fab fa-korvue",
  "814":"fas fa-landmark",
  "815":"fas fa-language",
  "816":"fas fa-laptop",
  "817":"fas fa-laptop-code",
  "818":"fas fa-laptop-medical",
  "819":"fab fa-laravel",
  "820":"fab fa-lastfm",
  "821":"fab fa-lastfm-square",
  "822":"fas fa-laugh",
  "823":"far fa-laugh",
  "824":"fas fa-laugh-beam",
  "825":"far fa-laugh-beam",
  "826":"fas fa-laugh-squint",
  "827":"far fa-laugh-squint",
  "828":"fas fa-laugh-wink",
  "829":"far fa-laugh-wink",
  "830":"fas fa-layer-group",
  "831":"fas fa-leaf",
  "832":"fab fa-leanpub",
  "833":"fas fa-lemon",
  "834":"far fa-lemon",
  "835":"fab fa-less",
  "836":"fas fa-less-than",
  "837":"fas fa-less-than-equal",
  "838":"fas fa-level-down-alt",
  "839":"fas fa-level-up-alt",
  "840":"fas fa-life-ring",
  "841":"far fa-life-ring",
  "842":"fas fa-lightbulb",
  "843":"far fa-lightbulb",
  "844":"fab fa-line",
  "845":"fas fa-link",
  "846":"fab fa-linkedin",
  "847":"fab fa-linkedin-in",
  "848":"fab fa-linode",
  "849":"fab fa-linux",
  "850":"fas fa-lira-sign",
  "851":"fas fa-list",
  "852":"fas fa-list-alt",
  "853":"far fa-list-alt",
  "854":"fas fa-list-ol",
  "855":"fas fa-list-ul",
  "856":"fas fa-location-arrow",
  "857":"fas fa-lock",
  "858":"fas fa-lock-open",
  "859":"fas fa-long-arrow-alt-down",
  "860":"fas fa-long-arrow-alt-left",
  "861":"fas fa-long-arrow-alt-right",
  "862":"fas fa-long-arrow-alt-up",
  "863":"fas fa-low-vision",
  "864":"fas fa-luggage-cart",
  "865":"fab fa-lyft",
  "866":"fab fa-magento",
  "867":"fas fa-magic",
  "868":"fas fa-magnet",
  "869":"fas fa-mail-bulk",
  "870":"fab fa-mailchimp",
  "871":"fas fa-male",
  "872":"fab fa-mandalorian",
  "873":"fas fa-map",
  "874":"far fa-map",
  "875":"fas fa-map-marked",
  "876":"fas fa-map-marked-alt",
  "877":"fas fa-map-marker",
  "878":"fas fa-map-marker-alt",
  "879":"fas fa-map-pin",
  "880":"fas fa-map-signs",
  "881":"fab fa-markdown",
  "882":"fas fa-marker",
  "883":"fas fa-mars",
  "884":"fas fa-mars-double",
  "885":"fas fa-mars-stroke",
  "886":"fas fa-mars-stroke-h",
  "887":"fas fa-mars-stroke-v",
  "888":"fas fa-mask",
  "889":"fab fa-mastodon",
  "890":"fab fa-maxcdn",
  "891":"fab fa-mdb",
  "892":"fas fa-medal",
  "893":"fab fa-medapps",
  "894":"fab fa-medium",
  "895":"fab fa-medium-m",
  "896":"fas fa-medkit",
  "897":"fab fa-medrt",
  "898":"fab fa-meetup",
  "899":"fab fa-megaport",
  "900":"fas fa-meh",
  "901":"far fa-meh",
  "902":"fas fa-meh-blank",
  "903":"far fa-meh-blank",
  "904":"fas fa-meh-rolling-eyes",
  "905":"far fa-meh-rolling-eyes",
  "906":"fas fa-memory",
  "907":"fab fa-mendeley",
  "908":"fas fa-menorah",
  "909":"fas fa-mercury",
  "910":"fas fa-meteor",
  "911":"fas fa-microchip",
  "912":"fas fa-microphone",
  "913":"fas fa-microphone-alt",
  "914":"fas fa-microphone-alt-slash",
  "915":"fas fa-microphone-slash",
  "916":"fas fa-microscope",
  "917":"fab fa-microsoft",
  "918":"fas fa-minus",
  "919":"fas fa-minus-circle",
  "920":"fas fa-minus-square",
  "921":"far fa-minus-square",
  "922":"fas fa-mitten",
  "923":"fab fa-mix",
  "924":"fab fa-mixcloud",
  "925":"fab fa-mizuni",
  "926":"fas fa-mobile",
  "927":"fas fa-mobile-alt",
  "928":"fab fa-modx",
  "929":"fab fa-monero",
  "930":"fas fa-money-bill",
  "931":"fas fa-money-bill-alt",
  "932":"far fa-money-bill-alt",
  "933":"fas fa-money-bill-wave",
  "934":"fas fa-money-bill-wave-alt",
  "935":"fas fa-money-check",
  "936":"fas fa-money-check-alt",
  "937":"fas fa-monument",
  "938":"fas fa-moon",
  "939":"far fa-moon",
  "940":"fas fa-mortar-pestle",
  "941":"fas fa-mosque",
  "942":"fas fa-motorcycle",
  "943":"fas fa-mountain",
  "944":"fas fa-mouse",
  "945":"fas fa-mouse-pointer",
  "946":"fas fa-mug-hot",
  "947":"fas fa-music",
  "948":"fab fa-napster",
  "949":"fab fa-neos",
  "950":"fas fa-network-wired",
  "951":"fas fa-neuter",
  "952":"fas fa-newspaper",
  "953":"far fa-newspaper",
  "954":"fab fa-nimblr",
  "955":"fab fa-node",
  "956":"fab fa-node-js",
  "957":"fas fa-not-equal",
  "958":"fas fa-notes-medical",
  "959":"fab fa-npm",
  "960":"fab fa-ns8",
  "961":"fab fa-nutritionix",
  "962":"fas fa-object-group",
  "963":"far fa-object-group",
  "964":"fas fa-object-ungroup",
  "965":"far fa-object-ungroup",
  "966":"fab fa-odnoklassniki",
  "967":"fab fa-odnoklassniki-square",
  "968":"fas fa-oil-can",
  "969":"fab fa-old-republic",
  "970":"fas fa-om",
  "971":"fab fa-opencart",
  "972":"fab fa-openid",
  "973":"fab fa-opera",
  "974":"fab fa-optin-monster",
  "975":"fab fa-orcid",
  "976":"fab fa-osi",
  "977":"fas fa-otter",
  "978":"fas fa-outdent",
  "979":"fab fa-page4",
  "980":"fab fa-pagelines",
  "981":"fas fa-pager",
  "982":"fas fa-paint-brush",
  "983":"fas fa-paint-roller",
  "984":"fas fa-palette",
  "985":"fab fa-palfed",
  "986":"fas fa-pallet",
  "987":"fas fa-paper-plane",
  "988":"far fa-paper-plane",
  "989":"fas fa-paperclip",
  "990":"fas fa-parachute-box",
  "991":"fas fa-paragraph",
  "992":"fas fa-parking",
  "993":"fas fa-passport",
  "994":"fas fa-pastafarianism",
  "995":"fas fa-paste",
  "996":"fab fa-patreon",
  "997":"fas fa-pause",
  "998":"fas fa-pause-circle",
  "999":"far fa-pause-circle",
  "1000":"fas fa-paw",
  "1001":"fab fa-paypal",
  "1002":"fas fa-peace",
  "1003":"fas fa-pen",
  "1004":"fas fa-pen-alt",
  "1005":"fas fa-pen-fancy",
  "1006":"fas fa-pen-nib",
  "1007":"fas fa-pen-square",
  "1008":"fas fa-pencil-alt",
  "1009":"fas fa-pencil-ruler",
  "1010":"fab fa-penny-arcade",
  "1011":"fas fa-people-carry",
  "1012":"fas fa-pepper-hot",
  "1013":"fas fa-percent",
  "1014":"fas fa-percentage",
  "1015":"fab fa-periscope",
  "1016":"fas fa-person-booth",
  "1017":"fab fa-phabricator",
  "1018":"fab fa-phoenix-framework",
  "1019":"fab fa-phoenix-squadron",
  "1020":"fas fa-phone",
  "1021":"fas fa-phone-alt",
  "1022":"fas fa-phone-slash",
  "1023":"fas fa-phone-square",
  "1024":"fas fa-phone-square-alt",
  "1025":"fas fa-phone-volume",
  "1026":"fas fa-photo-video",
  "1027":"fab fa-php",
  "1028":"fab fa-pied-piper",
  "1029":"fab fa-pied-piper-alt",
  "1030":"fab fa-pied-piper-hat",
  "1031":"fab fa-pied-piper-pp",
  "1032":"fas fa-piggy-bank",
  "1033":"fas fa-pills",
  "1034":"fab fa-pinterest",
  "1035":"fab fa-pinterest-p",
  "1036":"fab fa-pinterest-square",
  "1037":"fas fa-pizza-slice",
  "1038":"fas fa-place-of-worship",
  "1039":"fas fa-plane",
  "1040":"fas fa-plane-arrival",
  "1041":"fas fa-plane-departure",
  "1042":"fas fa-play",
  "1043":"fas fa-play-circle",
  "1044":"far fa-play-circle",
  "1045":"fab fa-playstation",
  "1046":"fas fa-plug",
  "1047":"fas fa-plus",
  "1048":"fas fa-plus-circle",
  "1049":"fas fa-plus-square",
  "1050":"far fa-plus-square",
  "1051":"fas fa-podcast",
  "1052":"fas fa-poll",
  "1053":"fas fa-poll-h",
  "1054":"fas fa-poo",
  "1055":"fas fa-poo-storm",
  "1056":"fas fa-poop",
  "1057":"fas fa-portrait",
  "1058":"fas fa-pound-sign",
  "1059":"fas fa-power-off",
  "1060":"fas fa-pray",
  "1061":"fas fa-praying-hands",
  "1062":"fas fa-prescription",
  "1063":"fas fa-prescription-bottle",
  "1064":"fas fa-prescription-bottle-alt",
  "1065":"fas fa-print",
  "1066":"fas fa-procedures",
  "1067":"fab fa-product-hunt",
  "1068":"fas fa-project-diagram",
  "1069":"fab fa-pushed",
  "1070":"fas fa-puzzle-piece",
  "1071":"fab fa-python",
  "1072":"fab fa-qq",
  "1073":"fas fa-qrcode",
  "1074":"fas fa-question",
  "1075":"fas fa-question-circle",
  "1076":"far fa-question-circle",
  "1077":"fas fa-quidditch",
  "1078":"fab fa-quinscape",
  "1079":"fab fa-quora",
  "1080":"fas fa-quote-left",
  "1081":"fas fa-quote-right",
  "1082":"fas fa-quran",
  "1083":"fab fa-r-project",
  "1084":"fas fa-radiation",
  "1085":"fas fa-radiation-alt",
  "1086":"fas fa-rainbow",
  "1087":"fas fa-random",
  "1088":"fab fa-raspberry-pi",
  "1089":"fab fa-ravelry",
  "1090":"fab fa-react",
  "1091":"fab fa-reacteurope",
  "1092":"fab fa-readme",
  "1093":"fab fa-rebel",
  "1094":"fas fa-receipt",
  "1095":"fas fa-record-vinyl",
  "1096":"fas fa-recycle",
  "1097":"fab fa-red-river",
  "1098":"fab fa-reddit",
  "1099":"fab fa-reddit-alien",
  "1100":"fab fa-reddit-square",
  "1101":"fab fa-redhat",
  "1102":"fas fa-redo",
  "1103":"fas fa-redo-alt",
  "1104":"fas fa-registered",
  "1105":"far fa-registered",
  "1106":"fas fa-remove-format",
  "1107":"fab fa-renren",
  "1108":"fas fa-reply",
  "1109":"fas fa-reply-all",
  "1110":"fab fa-replyd",
  "1111":"fas fa-republican",
  "1112":"fab fa-researchgate",
  "1113":"fab fa-resolving",
  "1114":"fas fa-restroom",
  "1115":"fas fa-retweet",
  "1116":"fab fa-rev",
  "1117":"fas fa-ribbon",
  "1118":"fas fa-ring",
  "1119":"fas fa-road",
  "1120":"fas fa-robot",
  "1121":"fas fa-rocket",
  "1122":"fab fa-rocketchat",
  "1123":"fab fa-rockrms",
  "1124":"fas fa-route",
  "1125":"fas fa-rss",
  "1126":"fas fa-rss-square",
  "1127":"fas fa-ruble-sign",
  "1128":"fas fa-ruler",
  "1129":"fas fa-ruler-combined",
  "1130":"fas fa-ruler-horizontal",
  "1131":"fas fa-ruler-vertical",
  "1132":"fas fa-running",
  "1133":"fas fa-rupee-sign",
  "1134":"fas fa-sad-cry",
  "1135":"far fa-sad-cry",
  "1136":"fas fa-sad-tear",
  "1137":"far fa-sad-tear",
  "1138":"fab fa-safari",
  "1139":"fab fa-salesforce",
  "1140":"fab fa-sass",
  "1141":"fas fa-satellite",
  "1142":"fas fa-satellite-dish",
  "1143":"fas fa-save",
  "1144":"far fa-save",
  "1145":"fab fa-schlix",
  "1146":"fas fa-school",
  "1147":"fas fa-screwdriver",
  "1148":"fab fa-scribd",
  "1149":"fas fa-scroll",
  "1150":"fas fa-sd-card",
  "1151":"fas fa-search",
  "1152":"fas fa-search-dollar",
  "1153":"fas fa-search-location",
  "1154":"fas fa-search-minus",
  "1155":"fas fa-search-plus",
  "1156":"fab fa-searchengin",
  "1157":"fas fa-seedling",
  "1158":"fab fa-sellcast",
  "1159":"fab fa-sellsy",
  "1160":"fas fa-server",
  "1161":"fab fa-servicestack",
  "1162":"fas fa-shapes",
  "1163":"fas fa-share",
  "1164":"fas fa-share-alt",
  "1165":"fas fa-share-alt-square",
  "1166":"fas fa-share-square",
  "1167":"far fa-share-square",
  "1168":"fas fa-shekel-sign",
  "1169":"fas fa-shield-alt",
  "1170":"fas fa-ship",
  "1171":"fas fa-shipping-fast",
  "1172":"fab fa-shirtsinbulk",
  "1173":"fas fa-shoe-prints",
  "1174":"fas fa-shopping-bag",
  "1175":"fas fa-shopping-basket",
  "1176":"fas fa-shopping-cart",
  "1177":"fab fa-shopware",
  "1178":"fas fa-shower",
  "1179":"fas fa-shuttle-van",
  "1180":"fas fa-sign",
  "1181":"fas fa-sign-in-alt",
  "1182":"fas fa-sign-language",
  "1183":"fas fa-sign-out-alt",
  "1184":"fas fa-signal",
  "1185":"fas fa-signature",
  "1186":"fas fa-sim-card",
  "1187":"fab fa-simplybuilt",
  "1188":"fab fa-sistrix",
  "1189":"fas fa-sitemap",
  "1190":"fab fa-sith",
  "1191":"fas fa-skating",
  "1192":"fab fa-sketch",
  "1193":"fas fa-skiing",
  "1194":"fas fa-skiing-nordic",
  "1195":"fas fa-skull",
  "1196":"fas fa-skull-crossbones",
  "1197":"fab fa-skyatlas",
  "1198":"fab fa-skype",
  "1199":"fab fa-slack",
  "1200":"fab fa-slack-hash",
  "1201":"fas fa-slash",
  "1202":"fas fa-sleigh",
  "1203":"fas fa-sliders-h",
  "1204":"fab fa-slideshare",
  "1205":"fas fa-smile",
  "1206":"far fa-smile",
  "1207":"fas fa-smile-beam",
  "1208":"far fa-smile-beam",
  "1209":"fas fa-smile-wink",
  "1210":"far fa-smile-wink",
  "1211":"fas fa-smog",
  "1212":"fas fa-smoking",
  "1213":"fas fa-smoking-ban",
  "1214":"fas fa-sms",
  "1215":"fab fa-snapchat",
  "1216":"fab fa-snapchat-ghost",
  "1217":"fab fa-snapchat-square",
  "1218":"fas fa-snowboarding",
  "1219":"fas fa-snowflake",
  "1220":"far fa-snowflake",
  "1221":"fas fa-snowman",
  "1222":"fas fa-snowplow",
  "1223":"fas fa-socks",
  "1224":"fas fa-solar-panel",
  "1225":"fas fa-sort",
  "1226":"fas fa-sort-alpha-down",
  "1227":"fas fa-sort-alpha-down-alt",
  "1228":"fas fa-sort-alpha-up",
  "1229":"fas fa-sort-alpha-up-alt",
  "1230":"fas fa-sort-amount-down",
  "1231":"fas fa-sort-amount-down-alt",
  "1232":"fas fa-sort-amount-up",
  "1233":"fas fa-sort-amount-up-alt",
  "1234":"fas fa-sort-down",
  "1235":"fas fa-sort-numeric-down",
  "1236":"fas fa-sort-numeric-down-alt",
  "1237":"fas fa-sort-numeric-up",
  "1238":"fas fa-sort-numeric-up-alt",
  "1239":"fas fa-sort-up",
  "1240":"fab fa-soundcloud",
  "1241":"fab fa-sourcetree",
  "1242":"fas fa-spa",
  "1243":"fas fa-space-shuttle",
  "1244":"fab fa-speakap",
  "1245":"fab fa-speaker-deck",
  "1246":"fas fa-spell-check",
  "1247":"fas fa-spider",
  "1248":"fas fa-spinner",
  "1249":"fas fa-splotch",
  "1250":"fab fa-spotify",
  "1251":"fas fa-spray-can",
  "1252":"fas fa-square",
  "1253":"far fa-square",
  "1254":"fas fa-square-full",
  "1255":"fas fa-square-root-alt",
  "1256":"fab fa-squarespace",
  "1257":"fab fa-stack-exchange",
  "1258":"fab fa-stack-overflow",
  "1259":"fab fa-stackpath",
  "1260":"fas fa-stamp",
  "1261":"fas fa-star",
  "1262":"far fa-star",
  "1263":"fas fa-star-and-crescent",
  "1264":"fas fa-star-half",
  "1265":"far fa-star-half",
  "1266":"fas fa-star-half-alt",
  "1267":"fas fa-star-of-david",
  "1268":"fas fa-star-of-life",
  "1269":"fab fa-staylinked",
  "1270":"fab fa-steam",
  "1271":"fab fa-steam-square",
  "1272":"fab fa-steam-symbol",
  "1273":"fas fa-step-backward",
  "1274":"fas fa-step-forward",
  "1275":"fas fa-stethoscope",
  "1276":"fab fa-sticker-mule",
  "1277":"fas fa-sticky-note",
  "1278":"far fa-sticky-note",
  "1279":"fas fa-stop",
  "1280":"fas fa-stop-circle",
  "1281":"far fa-stop-circle",
  "1282":"fas fa-stopwatch",
  "1283":"fas fa-store",
  "1284":"fas fa-store-alt",
  "1285":"fab fa-strava",
  "1286":"fas fa-stream",
  "1287":"fas fa-street-view",
  "1288":"fas fa-strikethrough",
  "1289":"fab fa-stripe",
  "1290":"fab fa-stripe-s",
  "1291":"fas fa-stroopwafel",
  "1292":"fab fa-studiovinari",
  "1293":"fab fa-stumbleupon",
  "1294":"fab fa-stumbleupon-circle",
  "1295":"fas fa-subscript",
  "1296":"fas fa-subway",
  "1297":"fas fa-suitcase",
  "1298":"fas fa-suitcase-rolling",
  "1299":"fas fa-sun",
  "1300":"far fa-sun",
  "1301":"fab fa-superpowers",
  "1302":"fas fa-superscript",
  "1303":"fab fa-supple",
  "1304":"fas fa-surprise",
  "1305":"far fa-surprise",
  "1306":"fab fa-suse",
  "1307":"fas fa-swatchbook",
  "1308":"fab fa-swift",
  "1309":"fas fa-swimmer",
  "1310":"fas fa-swimming-pool",
  "1311":"fab fa-symfony",
  "1312":"fas fa-synagogue",
  "1313":"fas fa-sync",
  "1314":"fas fa-sync-alt",
  "1315":"fas fa-syringe",
  "1316":"fas fa-table",
  "1317":"fas fa-table-tennis",
  "1318":"fas fa-tablet",
  "1319":"fas fa-tablet-alt",
  "1320":"fas fa-tablets",
  "1321":"fas fa-tachometer-alt",
  "1322":"fas fa-tag",
  "1323":"fas fa-tags",
  "1324":"fas fa-tape",
  "1325":"fas fa-tasks",
  "1326":"fas fa-taxi",
  "1327":"fab fa-teamspeak",
  "1328":"fas fa-teeth",
  "1329":"fas fa-teeth-open",
  "1330":"fab fa-telegram",
  "1331":"fab fa-telegram-plane",
  "1332":"fas fa-temperature-high",
  "1333":"fas fa-temperature-low",
  "1334":"fab fa-tencent-weibo",
  "1335":"fas fa-tenge",
  "1336":"fas fa-terminal",
  "1337":"fas fa-text-height",
  "1338":"fas fa-text-width",
  "1339":"fas fa-th",
  "1340":"fas fa-th-large",
  "1341":"fas fa-th-list",
  "1342":"fab fa-the-red-yeti",
  "1343":"fas fa-theater-masks",
  "1344":"fab fa-themeco",
  "1345":"fab fa-themeisle",
  "1346":"fas fa-thermometer",
  "1347":"fas fa-thermometer-empty",
  "1348":"fas fa-thermometer-full",
  "1349":"fas fa-thermometer-half",
  "1350":"fas fa-thermometer-quarter",
  "1351":"fas fa-thermometer-three-quarters",
  "1352":"fab fa-think-peaks",
  "1353":"fas fa-thumbs-down",
  "1354":"far fa-thumbs-down",
  "1355":"fas fa-thumbs-up",
  "1356":"far fa-thumbs-up",
  "1357":"fas fa-thumbtack",
  "1358":"fas fa-ticket-alt",
  "1359":"fas fa-times",
  "1360":"fas fa-times-circle",
  "1361":"far fa-times-circle",
  "1362":"fas fa-tint",
  "1363":"fas fa-tint-slash",
  "1364":"fas fa-tired",
  "1365":"far fa-tired",
  "1366":"fas fa-toggle-off",
  "1367":"fas fa-toggle-on",
  "1368":"fas fa-toilet",
  "1369":"fas fa-toilet-paper",
  "1370":"fas fa-toolbox",
  "1371":"fas fa-tools",
  "1372":"fas fa-tooth",
  "1373":"fas fa-torah",
  "1374":"fas fa-torii-gate",
  "1375":"fas fa-tractor",
  "1376":"fab fa-trade-federation",
  "1377":"fas fa-trademark",
  "1378":"fas fa-traffic-light",
  "1379":"fas fa-train",
  "1380":"fas fa-tram",
  "1381":"fas fa-transgender",
  "1382":"fas fa-transgender-alt",
  "1383":"fas fa-trash",
  "1384":"fas fa-trash-alt",
  "1385":"far fa-trash-alt",
  "1386":"fas fa-trash-restore",
  "1387":"fas fa-trash-restore-alt",
  "1388":"fas fa-tree",
  "1389":"fab fa-trello",
  "1390":"fab fa-tripadvisor",
  "1391":"fas fa-trophy",
  "1392":"fas fa-truck",
  "1393":"fas fa-truck-loading",
  "1394":"fas fa-truck-monster",
  "1395":"fas fa-truck-moving",
  "1396":"fas fa-truck-pickup",
  "1397":"fas fa-tshirt",
  "1398":"fas fa-tty",
  "1399":"fab fa-tumblr",
  "1400":"fab fa-tumblr-square",
  "1401":"fas fa-tv",
  "1402":"fab fa-twitch",
  "1403":"fab fa-twitter",
  "1404":"fab fa-twitter-square",
  "1405":"fab fa-typo3",
  "1406":"fab fa-uber",
  "1407":"fab fa-ubuntu",
  "1408":"fab fa-uikit",
  "1409":"fab fa-umbraco",
  "1410":"fas fa-umbrella",
  "1411":"fas fa-umbrella-beach",
  "1412":"fas fa-underline",
  "1413":"fas fa-undo",
  "1414":"fas fa-undo-alt",
  "1415":"fab fa-uniregistry",
  "1416":"fas fa-universal-access",
  "1417":"fas fa-university",
  "1418":"fas fa-unlink",
  "1419":"fas fa-unlock",
  "1420":"fas fa-unlock-alt",
  "1421":"fab fa-untappd",
  "1422":"fas fa-upload",
  "1423":"fab fa-ups",
  "1424":"fab fa-usb",
  "1425":"fas fa-user",
  "1426":"far fa-user",
  "1427":"fas fa-user-alt",
  "1428":"fas fa-user-alt-slash",
  "1429":"fas fa-user-astronaut",
  "1430":"fas fa-user-check",
  "1431":"fas fa-user-circle",
  "1432":"far fa-user-circle",
  "1433":"fas fa-user-clock",
  "1434":"fas fa-user-cog",
  "1435":"fas fa-user-edit",
  "1436":"fas fa-user-friends",
  "1437":"fas fa-user-graduate",
  "1438":"fas fa-user-injured",
  "1439":"fas fa-user-lock",
  "1440":"fas fa-user-md",
  "1441":"fas fa-user-minus",
  "1442":"fas fa-user-ninja",
  "1443":"fas fa-user-nurse",
  "1444":"fas fa-user-plus",
  "1445":"fas fa-user-secret",
  "1446":"fas fa-user-shield",
  "1447":"fas fa-user-slash",
  "1448":"fas fa-user-tag",
  "1449":"fas fa-user-tie",
  "1450":"fas fa-user-times",
  "1451":"fas fa-users",
  "1452":"fas fa-users-cog",
  "1453":"fab fa-usps",
  "1454":"fab fa-ussunnah",
  "1455":"fas fa-utensil-spoon",
  "1456":"fas fa-utensils",
  "1457":"fab fa-vaadin",
  "1458":"fas fa-vector-square",
  "1459":"fas fa-venus",
  "1460":"fas fa-venus-double",
  "1461":"fas fa-venus-mars",
  "1462":"fab fa-viacoin",
  "1463":"fab fa-viadeo",
  "1464":"fab fa-viadeo-square",
  "1465":"fas fa-vial",
  "1466":"fas fa-vials",
  "1467":"fab fa-viber",
  "1468":"fas fa-video",
  "1469":"fas fa-video-slash",
  "1470":"fas fa-vihara",
  "1471":"fab fa-vimeo",
  "1472":"fab fa-vimeo-square",
  "1473":"fab fa-vimeo-v",
  "1474":"fab fa-vine",
  "1475":"fab fa-vk",
  "1476":"fab fa-vnv",
  "1477":"fas fa-voicemail",
  "1478":"fas fa-volleyball-ball",
  "1479":"fas fa-volume-down",
  "1480":"fas fa-volume-mute",
  "1481":"fas fa-volume-off",
  "1482":"fas fa-volume-up",
  "1483":"fas fa-vote-yea",
  "1484":"fas fa-vr-cardboard",
  "1485":"fab fa-vuejs",
  "1486":"fas fa-walking",
  "1487":"fas fa-wallet",
  "1488":"fas fa-warehouse",
  "1489":"fas fa-water",
  "1490":"fas fa-wave-square",
  "1491":"fab fa-waze",
  "1492":"fab fa-weebly",
  "1493":"fab fa-weibo",
  "1494":"fas fa-weight",
  "1495":"fas fa-weight-hanging",
  "1496":"fab fa-weixin",
  "1497":"fab fa-whatsapp",
  "1498":"fab fa-whatsapp-square",
  "1499":"fas fa-wheelchair",
  "1500":"fab fa-whmcs",
  "1501":"fas fa-wifi",
  "1502":"fab fa-wikipedia-w",
  "1503":"fas fa-wind",
  "1504":"fas fa-window-close",
  "1505":"far fa-window-close",
  "1506":"fas fa-window-maximize",
  "1507":"far fa-window-maximize",
  "1508":"fas fa-window-minimize",
  "1509":"far fa-window-minimize",
  "1510":"fas fa-window-restore",
  "1511":"far fa-window-restore",
  "1512":"fab fa-windows",
  "1513":"fas fa-wine-bottle",
  "1514":"fas fa-wine-glass",
  "1515":"fas fa-wine-glass-alt",
  "1516":"fab fa-wix",
  "1517":"fab fa-wizards-of-the-coast",
  "1518":"fab fa-wolf-pack-battalion",
  "1519":"fas fa-won-sign",
  "1520":"fab fa-wordpress",
  "1521":"fab fa-wordpress-simple",
  "1522":"fab fa-wpbeginner",
  "1523":"fab fa-wpexplorer",
  "1524":"fab fa-wpforms",
  "1525":"fab fa-wpressr",
  "1526":"fas fa-wrench",
  "1527":"fas fa-x-ray",
  "1528":"fab fa-xbox",
  "1529":"fab fa-xing",
  "1530":"fab fa-xing-square",
  "1531":"fab fa-y-combinator",
  "1532":"fab fa-yahoo",
  "1533":"fab fa-yammer",
  "1534":"fab fa-yandex",
  "1535":"fab fa-yandex-international",
  "1536":"fab fa-yarn",
  "1537":"fab fa-yelp",
  "1538":"fas fa-yen-sign",
  "1539":"fas fa-yin-yang",
  "1540":"fab fa-yoast",
  "1541":"fab fa-youtube",
  "1542":"fab fa-youtube-square",
  "1543":"fab fa-zhihu"
}

================================================
FILE: index.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Vue 3 Pagebuilder</title>

    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
      integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z"
      crossorigin="anonymous"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css"
    />
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="editor/editor.css" />

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.2/vue.global.prod.min.js"
      integrity="sha512-YrmKYDNQKVmL5Y3xfdyNrp7atx+/XpIevYmFWoXMBitv2UitzwPwDzg/1H2UnBwelWgzDUd8Ex7L8bw61aK0jA=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    ></script>

    <!-- this serves the unbundled version -->
    <script src="main.mjs" type="module"></script>

    <!-- alternatively you can use the bundled version
     <script src="build/bundle.mjs" type="module"></script>
    -->

    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/@furcan/iconpicker@1.5.0/dist/iconpicker-1.5.0.css"
    />
    <script src="https://cdn.jsdelivr.net/npm/@furcan/iconpicker@1.5.0/dist/iconpicker-1.5.0.min.js"></script>
    <script src="https://cdn.rawgit.com/beautify-web/js-beautify/v1.13.6/js/lib/beautify-html.js"></script>

    <link rel="preconnect" href="https://fonts.gstatic.com" />
    <link
      href="https://fonts.googleapis.com/css2?family=Rubik:wght@300;600&family=Lobster&family=Playfair+Display&family=Raleway&family=Cutive+Mono&display=swap"
      rel="stylesheet"
    />

    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/github-fork-ribbon-css/0.2.3/gh-fork-ribbon.min.css"
    />

    <style>
      .github-fork-ribbon:before {
        background-color: #333;
      }
    </style>
  </head>

  <body>
    <a
      class="github-fork-ribbon"
      href="https://github.com/dashpilot/vue-pagebuilder"
      data-ribbon="Fork me on GitHub"
      title="Fork me on GitHub"
      >Fork me on GitHub</a
    >
    <main>
      <div id="page">
        <div id="header">
          <template v-for="item in entries">
            <template v-if="item.layout == 'header'">
              <wdgt-header v-bind:item="item"></wdgt-header>
            </template>
          </template>
        </div>

        <div id="content">
          <template v-for="item in entries">
            <template v-if="item.layout == 'post'">
              <wdgt-post v-bind:item="item"></wdgt-post>
            </template>

            <template v-if="item.layout == 'news'">
              <wdgt-news v-bind:item="item"></wdgt-news>
            </template>

            <template v-if="item.layout == 'newsleft'">
              <wdgt-newsleft v-bind:item="item"></wdgt-newsleft>
            </template>

            <template v-if="item.layout == 'featured'">
              <wdgt-featured v-bind:item="item"></wdgt-featured>
            </template>

            <template v-if="item.layout == 'features'">
              <wdgt-features v-bind:item="item"></wdgt-features>
            </template>
          </template>
        </div>
      </div>
      <page-editor
        v-if="editing"
        v-bind:layouts="layouts"
        v-bind:entries="entries"
      ></page-editor>
    </main>
  </body>
</html>


================================================
FILE: main.mjs
================================================
import Header from "./components/header/header.mjs";
import Post from "./components/post/post.mjs";
import News from "./components/news/news.mjs";
import NewsLeft from "./components/newsleft/newsleft.mjs";
import Featured from "./components/featured/featured.mjs";
import Features from "./components/features/features.mjs";
import Editor from "./editor/editor.mjs";

const { createApp } = Vue;
const App = createApp({
  data() {
    return {
      editing: true,
      layouts: ["featured", "post", "news", "newsleft", "features"],
      entries: [
        {
          id: "item-1",
          layout: "header",
          title: "Vue Pagebuilder",
          subtitle: "Lorem ipsum dolor site amet.",
          button_text: "Contact Us",
          button_link: "#",
          icon: "fas fa-bolt",
        },
        {
          id: "item-2",
          layout: "post",
          title: "Mauris eleifend ligula",
          body: " Vivamus in nisi commodo, auctor magna vel, viverra turpis. Quisque dapibus risus nec justo euismod, id fringilla dui lobortis. Mauris vitae semper arcu. Ut ac lorem felis.",
        },
        {
          id: "item-3",
          layout: "news",
          title: "Maecenas tincidunt sem quis rutrum",
          body: "Mauris in porttitor elit. Aenean elementum eleifend quam, in tristique eros auctor porta. Donec et est in tellus blandit feugiat id nec nunc.",
        },
        {
          id: "item-4",
          layout: "features",
          title: "Lorem Ipsum",
          body: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris eleifend ligula ut augue scelerisque venenatis.",
        },
      ],
    };
  },

  methods: {
    defaultVal(key, def) {
      if (key == "") {
        return def;
      } else {
        return key;
      }
    },
  },

  components: {
    "wdgt-post": Post,
    "wdgt-header": Header,
    "wdgt-news": News,
    "wdgt-newsleft": NewsLeft,
    "wdgt-featured": Featured,
    "wdgt-features": Features,
    "page-editor": Editor,
  },
});

window.addEventListener("load", () => {
  App.mount("main");
});


================================================
FILE: package.json
================================================
{
  "name": "vue-pagebuilder",
  "version": "1.0.1",
  "description": "A visual pagebuilder for Vue 3",
  "main": "main.js",
  "scripts": {
    "build": "rollup -c rollup.build.mjs",
    "serve": "rollup -c rollup.serve.mjs"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/dashpilot/vue-pagebuilder.git"
  },
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/dashpilot/vue-pagebuilder/issues"
  },
  "homepage": "https://github.com/dashpilot/vue-pagebuilder#readme",
  "devDependencies": {
    "rollup": "^3.7.5",
    "rollup-plugin-serve": "^1.1.1"
  }
}


================================================
FILE: rollup.build.mjs
================================================
export default {
  input: "main.mjs",
  output: {
    file: "build/bundle.mjs",
    format: "es",
  },
};


================================================
FILE: rollup.serve.mjs
================================================
import serve from "rollup-plugin-serve";

export default {
  input: "main.mjs",
  output: {
    file: "build/bundle.mjs",
    format: "es",
  },
  plugins: [
    serve({
      open: true, // opens browser
      verbose: true, // logs server activity to console
      contentBase: ["", "build"], // serve from root and build directories
      host: "localhost",
      port: 8000,
    }),
  ],
};


================================================
FILE: style.css
================================================
:root {
  --bg-color: #f7fafc;
  --fg-color: #000000;
  --font: "Rubik";
  --spacing: "-0.04em";
}

.container {
  padding-top: 20px;
  padding-bottom: 20px;
}

section h1,
section h2,
section h3,
section h4 {
  font-family: var(--font);
  letter-spacing: var(--spacing);
  font-weight: 600;
}

section h1,
section h2 {
  font-size: 45px;
  line-height: 45px;
}

section h3 {
  margin-top: 20px;
  font-size: 35px;
  line-height: 35px;
}

section h1 {
  margin-bottom: 10px;
}

section h2 {
  margin-bottom: 25px;
}

section p {
  font-family: "Rubik", sans-serif;
  font-weight: 300;
  font-size: 20px;
  line-height: 30px;
  color: #4f5c65;
}

section {
  padding: 25px;
  padding-top: 100px;
  padding-bottom: 100px;
}

#header:nth-child(odd) h1,
#header:nth-child(odd) h2,
#header:nth-child(odd) h3,
#header:nth-child(odd) p,
#header:nth-child(odd) .fas {
  color: var(--fg-color);
}

#content section:nth-child(even) h1,
#content section:nth-child(even) h2,
#content section:nth-child(even) h3,
#content section:nth-child(even) p,
#content section:nth-child(even) .fas {
  color: var(--fg-color);
}

#content section:nth-child(even) {
  background-color: var(--bg-color);
}

#header:nth-child(odd) {
  background-color: var(--bg-color);
}

.btn-secondary {
  font-family: "Rubik", sans-serif;
  border: 1px solid #000;
  font-size: 20px;
  padding: 8px 25px 8px 25px;
  margin-top: 25px;
  background-color: transparent;
}

.btn-secondary:hover {
  border: 1px solid #999;
  background-color: transparent;
}

#header:nth-child(odd) .btn-secondary {
  color: var(--fg-color);
  border-color: var(--fg-color);
}

#content:nth-child(odd) .btn-secondary {
  color: var(--fg-color);
  border-color: var(--fg-color);
}

.fa-big {
  font-size: 45px;
  margin-bottom: 15px;
}

.responsive-container {
  position: relative;
  overflow: hidden;
  width: 100%;
  padding-top: 56.25%;
  /* 16:9 Aspect Ratio (divide 9 by 16 = 0.5625) */
}

/* Then style the iframe to fit in the container div with full height and width */

.responsive-iframe {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  width: 100%;
  height: 100%;
}


================================================
FILE: test-inline.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Vue Pagebuilder</title>

    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
      integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z"
      crossorigin="anonymous"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css"
    />
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="editor/editor.css" />

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.2/vue.global.prod.min.js"
      integrity="sha512-YrmKYDNQKVmL5Y3xfdyNrp7atx+/XpIevYmFWoXMBitv2UitzwPwDzg/1H2UnBwelWgzDUd8Ex7L8bw61aK0jA=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    ></script>

    <link
      rel="stylesheet"
      href="https://vue-pagebuilder.vercel.app/editor/js/iconpicker/iconpicker-1.5.0.css"
    />
    <script src="https://vue-pagebuilder.vercel.app/editor/js/iconpicker/iconpicker-1.5.0.js"></script>

    <link rel="preconnect" href="https://fonts.gstatic.com" />
    <link
      href="https://fonts.googleapis.com/css2?family=Rubik:wght@300;600&family=Lobster&family=Playfair+Display&family=Raleway&family=Cutive+Mono&display=swap"
      rel="stylesheet"
    />
  </head>

  <body>
    <main id="app">
      <div id="content">
        <section v-for="item in entries">
          <div v-if="item.layout == 'featured'">
            <div
              :id="item.id"
              class="editable"
              data-fields="title=txt&amp;body=rte"
            >
              <div class="container">
                <div class="w-50 m-auto text-center">
                  <h2 v-text="item.title"></h2>
                  <p v-html="item.body"></p>
                </div>
              </div>
            </div>
          </div>
        </section>
      </div>

      <page-editor
        v-if="editing"
        v-bind:layouts="layouts"
        v-bind:entries="entries"
      ></page-editor>
    </main>

    <script type="module">
      import Editor from "./editor/editor.mjs";
      const app = Vue.createApp({
        data() {
          return {
            editing: true,
            layouts: ["featured"],
            entries: [
              {
                layout: "featured",
                id: "item-1",
                title: "A first item",
                body: "Lorem ipsum dolor site amet",
              },
              {
                layout: "featured",
                id: "item-2",
                title: "A second item",
                body: "Nam at tincidunt libero, ut iaculis augue.",
              },
            ],
          };
        },
        methods: {
          defaultVal(key, def) {
            if (key == "") {
              return def;
            } else {
              return key;
            }
          },
        },
        components: {
          "page-editor": Editor,
        },
      });
      app.mount("#app");
    </script>
  </body>
</html>


================================================
FILE: test.html
================================================
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Vue Pagebuilder</title>

    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"
      integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z"
      crossorigin="anonymous"
    />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/css/all.min.css"
    />
    <link rel="stylesheet" href="style.css" />
    <link rel="stylesheet" href="editor/editor.css" />

    <script
      src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.2/vue.global.prod.min.js"
      integrity="sha512-YrmKYDNQKVmL5Y3xfdyNrp7atx+/XpIevYmFWoXMBitv2UitzwPwDzg/1H2UnBwelWgzDUd8Ex7L8bw61aK0jA=="
      crossorigin="anonymous"
      referrerpolicy="no-referrer"
    ></script>
    <script src="https://unpkg.com/simple-color-picker/dist/simple-color-picker.umd.js"></script>
    <script
      src="https://vue-pagebuilder.vercel.app/main.mjs"
      type="module"
    ></script>
    <link
      rel="stylesheet"
      href="https://vue-pagebuilder.vercel.app/editor/js/iconpicker/iconpicker-1.5.0.css"
    />
    <script src="https://vue-pagebuilder.vercel.app/editor/js/iconpicker/iconpicker-1.5.0.js"></script>

    <link rel="preconnect" href="https://fonts.gstatic.com" />
    <link
      href="https://fonts.googleapis.com/css2?family=Rubik:wght@300;600&family=Lobster&family=Playfair+Display&family=Raleway&family=Cutive+Mono&display=swap"
      rel="stylesheet"
    />
  </head>

  <body>
    <main>
      <div id="content" v-for="item in entries">
        <wdgt-post v-bind:item="item" v-if="item.layout == 'post'"></wdgt-post>
        <wdgt-news v-bind:item="item" v-if="item.layout == 'news'"></wdgt-news>
        <wdgt-banner
          v-bind:item="item"
          v-if="item.layout == 'banner'"
        ></wdgt-banner>
        <wdgt-featured
          v-bind:item="item"
          v-if="item.layout == 'featured'"
        ></wdgt-featured>
        <wdgt-features
          v-bind:item="item"
          v-if="item.layout == 'features'"
        ></wdgt-features>
      </div>

      <page-editor
        v-if="editing"
        v-bind:layouts="layouts"
        v-bind:entries="entries"
      ></page-editor>
    </main>
  </body>
</html>
Download .txt
gitextract_ssjr_prk/

├── .gitignore
├── README.md
├── build/
│   └── bundle.mjs
├── components/
│   ├── featured/
│   │   └── featured.mjs
│   ├── features/
│   │   └── features.mjs
│   ├── header/
│   │   └── header.mjs
│   ├── helpers.mjs
│   ├── news/
│   │   └── news.mjs
│   ├── newsleft/
│   │   └── newsleft.mjs
│   └── post/
│       └── post.mjs
├── editor/
│   ├── components/
│   │   ├── add-content.mjs
│   │   ├── fa-picker.mjs
│   │   └── image-resize.mjs
│   ├── editor.css
│   ├── editor.mjs
│   └── js/
│       └── iconpicker/
│           ├── iconpicker-1.5.0.css
│           ├── iconpicker-1.5.0.js
│           └── iconpicker-1.5.0.json
├── index.html
├── main.mjs
├── package.json
├── rollup.build.mjs
├── rollup.serve.mjs
├── style.css
├── test-inline.html
└── test.html
Download .txt
SYMBOL INDEX (44 symbols across 12 files)

FILE: build/bundle.mjs
  method mounted (line 28) | mounted() {
  method mounted (line 53) | mounted() {
  method created (line 120) | created() {
  method mounted (line 123) | mounted() {
  method created (line 175) | created() {
  method mounted (line 178) | mounted() {
  method mounted (line 199) | mounted() {
  method created (line 230) | created() {
  method mounted (line 233) | mounted() {
  method mounted (line 256) | mounted() {
  method data (line 421) | data() {
  method swapStyleSheet (line 487) | swapStyleSheet(font) {
  method downloadFile (line 491) | downloadFile() {
  method mounted (line 532) | mounted() {
  function colorContrast (line 537) | function colorContrast(hex) {
  function dl (line 567) | function dl(filename, data) {
  method data (line 601) | data() {
  method mounted (line 609) | mounted() {
  method data (line 755) | data() {
  method mounted (line 799) | mounted() {
  method data (line 821) | data() {
  method defaultVal (line 858) | defaultVal(key, def) {

FILE: components/featured/featured.mjs
  method mounted (line 17) | mounted() {

FILE: components/features/features.mjs
  method created (line 29) | created() {
  method mounted (line 32) | mounted() {

FILE: components/header/header.mjs
  method mounted (line 28) | mounted() {

FILE: components/news/news.mjs
  method created (line 48) | created() {
  method mounted (line 51) | mounted() {

FILE: components/newsleft/newsleft.mjs
  method created (line 49) | created() {
  method mounted (line 52) | mounted() {

FILE: components/post/post.mjs
  method mounted (line 21) | mounted() {

FILE: editor/components/add-content.mjs
  method data (line 144) | data() {
  method swapStyleSheet (line 210) | swapStyleSheet(font) {
  method downloadFile (line 214) | downloadFile() {
  method mounted (line 255) | mounted() {
  function colorContrast (line 260) | function colorContrast(hex) {
  function dl (line 290) | function dl(filename, data) {

FILE: editor/components/fa-picker.mjs
  method mounted (line 19) | mounted() {

FILE: editor/components/image-resize.mjs
  method data (line 19) | data() {
  method mounted (line 27) | mounted() {

FILE: editor/editor.mjs
  method data (line 81) | data() {
  method mounted (line 125) | mounted() {

FILE: main.mjs
  method data (line 11) | data() {
  method defaultVal (line 48) | defaultVal(key, def) {
Condensed preview — 26 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (148K chars).
[
  {
    "path": ".gitignore",
    "chars": 29,
    "preview": ".DS_Store\n.env\nnode_modules\n\n"
  },
  {
    "path": "README.md",
    "chars": 698,
    "preview": "# vue-pagebuilder\n\nA visual pagebuilder for Vue 3.\n\nFeatures:\n\n- Add premade layout blocks to the page\n- Rearrange and d"
  },
  {
    "path": "build/bundle.mjs",
    "chars": 23718,
    "preview": "const html$8 = String.raw;\n\nconst template$9 = html$8`\n  <section\n    :id=\"item.id\"\n    class=\"editable text-center\"\n   "
  },
  {
    "path": "components/featured/featured.mjs",
    "chars": 422,
    "preview": "const html = String.raw;\n\nconst template = html`\n  <section :id=\"item.id\" class=\"editable\" data-fields=\"title=txt&amp;bo"
  },
  {
    "path": "components/features/features.mjs",
    "chars": 855,
    "preview": "import helpers from \"./../helpers.mjs\";\n\nconst template = `\n  <section\n    :id=\"item.id\"\n    class=\"editable\"\n    data-f"
  },
  {
    "path": "components/header/header.mjs",
    "chars": 642,
    "preview": "const html = String.raw;\n\nconst template = html`\n  <section\n    :id=\"item.id\"\n    class=\"editable text-center\"\n    data-"
  },
  {
    "path": "components/helpers.mjs",
    "chars": 361,
    "preview": "export default {\n  def: function (key, val) {\n    if (key) {\n      return key;\n    } else {\n      return val;\n    }\n  },"
  },
  {
    "path": "components/news/news.mjs",
    "chars": 1426,
    "preview": "import helpers from \"./../helpers.mjs\";\nconst html = String.raw;\n\nconst template = html`\n  <section\n    :id=\"item.id\"\n  "
  },
  {
    "path": "components/newsleft/newsleft.mjs",
    "chars": 1427,
    "preview": "import helpers from \"./../helpers.mjs\";\nconst html = String.raw;\n\nconst template = html`\n  <section\n    :id=\"item.id\"\n  "
  },
  {
    "path": "components/post/post.mjs",
    "chars": 522,
    "preview": "const html = String.raw;\n\nconst template = html`\n  <section :id=\"item.id\" class=\"editable\" data-fields=\"title=txt&amp;bo"
  },
  {
    "path": "editor/components/add-content.mjs",
    "chars": 9056,
    "preview": "const html = String.raw;\n\nconst template = html`\n  <transition name=\"slide-left\">\n    <div class=\"slidein-left\" id=\"adde"
  },
  {
    "path": "editor/components/fa-picker.mjs",
    "chars": 1375,
    "preview": "const html = String.raw;\nconst template = html`\n  <button\n    :id=\"'launchIconPicker-'+mykey\"\n    class=\"btn btn-outline"
  },
  {
    "path": "editor/components/image-resize.mjs",
    "chars": 2320,
    "preview": "const html = String.raw;\nconst template = html`\n  <input\n    type=\"file\"\n    id=\"fileInput\"\n    class=\"fileInput\"\n    ac"
  },
  {
    "path": "editor/editor.css",
    "chars": 3070,
    "preview": ".edit {\n  display: block;\n  width: 50px;\n  height: 50px;\n  background-image: url(img/cog.png);\n  background-size: cover;"
  },
  {
    "path": "editor/editor.mjs",
    "chars": 3716,
    "preview": "import Picker from \"./components/fa-picker.mjs\";\nimport Add from \"./components/add-content.mjs\";\nimport Image from \"./co"
  },
  {
    "path": "editor/js/iconpicker/iconpicker-1.5.0.css",
    "chars": 5367,
    "preview": "/*!\n* IconPicker ('https://github.com/furcan/IconPicker')\n* Version: 1.5.0 \n* Author: Furkan MT ('https://github.com/fur"
  },
  {
    "path": "editor/js/iconpicker/iconpicker-1.5.0.js",
    "chars": 20417,
    "preview": "/*!\n* IconPicker ('https://github.com/furcan/IconPicker')\n* Version: 1.5.0 \n* Author: Furkan MT ('https://github.com/fu"
  },
  {
    "path": "editor/js/iconpicker/iconpicker-1.5.0.json",
    "chars": 44324,
    "preview": "{\n  \"0\":\"fab fa-500px\",\n  \"1\":\"fab fa-accessible-icon\",\n  \"2\":\"fab fa-accusoft\",\n  \"3\":\"fab fa-acquisitions-incorporated"
  },
  {
    "path": "index.html",
    "chars": 3441,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Vue 3 Pagebuilder</title>\n\n    <link\n      rel=\""
  },
  {
    "path": "main.mjs",
    "chars": 2082,
    "preview": "import Header from \"./components/header/header.mjs\";\nimport Post from \"./components/post/post.mjs\";\nimport News from \"./"
  },
  {
    "path": "package.json",
    "chars": 614,
    "preview": "{\n  \"name\": \"vue-pagebuilder\",\n  \"version\": \"1.0.1\",\n  \"description\": \"A visual pagebuilder for Vue 3\",\n  \"main\": \"main."
  },
  {
    "path": "rollup.build.mjs",
    "chars": 106,
    "preview": "export default {\n  input: \"main.mjs\",\n  output: {\n    file: \"build/bundle.mjs\",\n    format: \"es\",\n  },\n};\n"
  },
  {
    "path": "rollup.serve.mjs",
    "chars": 395,
    "preview": "import serve from \"rollup-plugin-serve\";\n\nexport default {\n  input: \"main.mjs\",\n  output: {\n    file: \"build/bundle.mjs\""
  },
  {
    "path": "style.css",
    "chars": 2139,
    "preview": ":root {\n  --bg-color: #f7fafc;\n  --fg-color: #000000;\n  --font: \"Rubik\";\n  --spacing: \"-0.04em\";\n}\n\n.container {\n  paddi"
  },
  {
    "path": "test-inline.html",
    "chars": 3092,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Vue Pagebuilder</title>\n\n    <link\n      rel=\"st"
  },
  {
    "path": "test.html",
    "chars": 2333,
    "preview": "<!doctype html>\n<html>\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Vue Pagebuilder</title>\n\n    <link\n      rel=\"st"
  }
]

About this extraction

This page contains the full source code of the dashpilot/vue-pagebuilder GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 26 files (130.8 KB), approximately 39.4k tokens, and a symbol index with 44 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!