<section id="app" class="section">
  <div class="container">
    <div class="columns is-centerd">
      <div class="column">
        <h1 class="title has-text-centered">Bookmarklet Maker</h1>
      </div>
    </div>

    
    <div class="columns">
      <div class="column">
        <form class="box">
          <div class="field is-grouped">
            <a class="button is-link"  v-bind:href="outputCode">{{ title }}</a>
          </div>
          <div class="notification">
            上のボタンをブックマークバーまでドラッグしてください。
          </div>
          <div class="field">
            <div class="field-label">
              <label class="label">Title</label>
            </div>
            <div class="control">
              <input class="input" type="text"  v-model="title" />
            </div>
          </div>
          <div class="field">
            <div class="field-label is-normal">
              <label class="label">Script</label>
            </div>
            <div class="control">
              <textarea id="input-text" class="textarea" v-model="inputCode" placeholder="Input your script here." autocomplete="off"></textarea>
            </div>
          </div>
          <div class="field">
             <div class="field-label is-normal">
              <label class="label">bookmark URL</label>
            </div>
           <div class="control is-expanded">
              <textarea id="out-text" v-bind:class="[textareaClass, resultClass]" v-model="encodedOutputCode" readonly placeholder="Input your code here"></textarea>
            </div>
          </div>
        </form>
      </div>
    </div>
  </div>
</section>
h1.title {
  font-size: 1.5rem;
}

#app {
  min-height: 100vh;
  background: #10c1a2;
}

label.label {
  text-align: left;
}

const vue = new Vue({
  el: "#app",
  data: {
    title: '🔃Twitter',
    inputCode: `(() => {
  // もうタイマー呼び出しが定義済みならキャンセルして終了
  if (window.autoReloadId) {
    clearInterval(window.autoReloadId);
    delete window.autoReloadId;
    // 自動読み込み中であることを示す 🔃 をタイトルから削除
    document.title = document.title.replace("🔃", "");
    return;
  }

  // 後で参照するために一番上のツィートの id を保存
  let topItemIdSave = document.querySelector("li.stream-item").id;

  // 広告を隠す
  const hideAd = () =>
    Array.from(
      document.querySelectorAll("a.js-promoted-badge"),
      e =>
        (e.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.style.display =
          "none")
    );
  hideAd();

  window.autoReloadId = setInterval(() => {
    // 自動読み込み中であることを示すためタイトルに 🔃 を追加
    if (document.title.indexOf("🔃") < 0) {
      document.title = "🔃" + document.title;
    }
    // スクロール中ならばこれ以上何もしない
    if (document.scrollingElement.scrollTop !== 0) {
      return;
    }
    const topItemId = document.querySelector("li.stream-item").id;
    if (topItemIdSave === topItemIdSave) {
      // 「新しいツイートをn件を見る」が表示されていたらクリックする
      const e = document.querySelector(".new-tweets-bar");
      e && e.click();
    } else {
      topItemIdSave = topItemId;
      hideAd();
    }
  }, 500);
})();`,
    textareaClass: "textarea",
    isError: false,
    outputCode: "#",
    errorText: ""
  },
  computed: {
    resultClass() {
      return this.isError ? "is-danger" : "is-success";
    },
    encodedOutputCode() {
      return this.isError ? this.errorText : encodeURI(this.outputCode);
    }
  },
  watch: {
    inputCode: {
      immediate: true,
      handler: function() {
        const result = UglifyJS.minify(this.inputCode);
        if (result.error) {
          this.isError = true;
          this.errorText = result.error;
        } else {
          this.isError = false;
          this.outputCode = `javascript:${result.code}`;
        }
      }
    }
  },
  methods: {}
});
View Compiled

External CSS

  1. https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.1/css/bulma.min.css
  2. https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.min.js
  2. https://s3-us-west-2.amazonaws.com/s.cdpn.io/1388885/uglify-es-self-3.3.9.js