diff options
| author | tamaina <tamaina@hotmail.co.jp> | 2018-04-11 20:27:09 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-04-11 20:27:09 +0900 |
| commit | d43fe853c3605696e2e57e240845d0fc9c284f61 (patch) | |
| tree | 838914e262c0fca5737588a7bba64e2b9f3d8e5f /src/web/app/common | |
| parent | Update README.md (diff) | |
| parent | wip #1443 (diff) | |
| download | misskey-d43fe853c3605696e2e57e240845d0fc9c284f61.tar.gz misskey-d43fe853c3605696e2e57e240845d0fc9c284f61.tar.bz2 misskey-d43fe853c3605696e2e57e240845d0fc9c284f61.zip | |
Merge pull request #1 from syuilo/master
追従
Diffstat (limited to 'src/web/app/common')
62 files changed, 0 insertions, 4498 deletions
diff --git a/src/web/app/common/mios.ts b/src/web/app/common/mios.ts deleted file mode 100644 index 6ee42ea8a7..0000000000 --- a/src/web/app/common/mios.ts +++ /dev/null @@ -1,351 +0,0 @@ -import { EventEmitter } from 'eventemitter3'; -import * as riot from 'riot'; -import signout from './scripts/signout'; -import Progress from './scripts/loading'; -import HomeStreamManager from './scripts/streaming/home-stream-manager'; -import api from './scripts/api'; - -//#region environment variables -declare const _VERSION_: string; -declare const _LANG_: string; -declare const _API_URL_: string; -declare const _SW_PUBLICKEY_: string; -//#endregion - -/** - * Misskey Operating System - */ -export default class MiOS extends EventEmitter { - /** - * Misskeyの /meta で取得できるメタ情報 - */ - private meta: { - data: { [x: string]: any }; - chachedAt: Date; - }; - - private isMetaFetching = false; - - /** - * A signing user - */ - public i: { [x: string]: any }; - - /** - * Whether signed in - */ - public get isSignedin() { - return this.i != null; - } - - /** - * Whether is debug mode - */ - public get debug() { - return localStorage.getItem('debug') == 'true'; - } - - /** - * A connection manager of home stream - */ - public stream: HomeStreamManager; - - /** - * A registration of service worker - */ - private swRegistration: ServiceWorkerRegistration = null; - - /** - * Whether should register ServiceWorker - */ - private shouldRegisterSw: boolean; - - /** - * MiOSインスタンスを作成します - * @param shouldRegisterSw ServiceWorkerを登録するかどうか - */ - constructor(shouldRegisterSw = false) { - super(); - - this.shouldRegisterSw = shouldRegisterSw; - - //#region BIND - this.log = this.log.bind(this); - this.logInfo = this.logInfo.bind(this); - this.logWarn = this.logWarn.bind(this); - this.logError = this.logError.bind(this); - this.init = this.init.bind(this); - this.api = this.api.bind(this); - this.getMeta = this.getMeta.bind(this); - this.registerSw = this.registerSw.bind(this); - //#endregion - } - - public log(...args) { - if (!this.debug) return; - console.log.apply(null, args); - } - - public logInfo(...args) { - if (!this.debug) return; - console.info.apply(null, args); - } - - public logWarn(...args) { - if (!this.debug) return; - console.warn.apply(null, args); - } - - public logError(...args) { - if (!this.debug) return; - console.error.apply(null, args); - } - - /** - * Initialize MiOS (boot) - * @param callback A function that call when initialized - */ - public async init(callback) { - // ユーザーをフェッチしてコールバックする - const fetchme = (token, cb) => { - let me = null; - - // Return when not signed in - if (token == null) { - return done(); - } - - // Fetch user - fetch(`${_API_URL_}/i`, { - method: 'POST', - body: JSON.stringify({ - i: token - }) - }) - // When success - .then(res => { - // When failed to authenticate user - if (res.status !== 200) { - return signout(); - } - - // Parse response - res.json().then(i => { - me = i; - me.token = token; - done(); - }); - }) - // When failure - .catch(() => { - // Render the error screen - document.body.innerHTML = '<mk-error />'; - riot.mount('*'); - - Progress.done(); - }); - - function done() { - if (cb) cb(me); - } - }; - - // フェッチが完了したとき - const fetched = me => { - if (me) { - riot.observable(me); - - // この me オブジェクトを更新するメソッド - me.update = data => { - if (data) Object.assign(me, data); - me.trigger('updated'); - }; - - // ローカルストレージにキャッシュ - localStorage.setItem('me', JSON.stringify(me)); - - // 自分の情報が更新されたとき - me.on('updated', () => { - // キャッシュ更新 - localStorage.setItem('me', JSON.stringify(me)); - }); - } - - this.i = me; - - // Init home stream manager - this.stream = this.isSignedin - ? new HomeStreamManager(this.i) - : null; - - // Finish init - callback(); - - //#region Post - - // Init service worker - if (this.shouldRegisterSw) this.registerSw(); - - //#endregion - }; - - // Get cached account data - const cachedMe = JSON.parse(localStorage.getItem('me')); - - // キャッシュがあったとき - if (cachedMe) { - // とりあえずキャッシュされたデータでお茶を濁して(?)おいて、 - fetched(cachedMe); - - // 後から新鮮なデータをフェッチ - fetchme(cachedMe.token, freshData => { - Object.assign(cachedMe, freshData); - cachedMe.trigger('updated'); - cachedMe.trigger('refreshed'); - }); - } else { - // Get token from cookie - const i = (document.cookie.match(/i=(!\w+)/) || [null, null])[1]; - - fetchme(i, fetched); - } - } - - /** - * Register service worker - */ - private registerSw() { - // Check whether service worker and push manager supported - const isSwSupported = - ('serviceWorker' in navigator) && ('PushManager' in window); - - // Reject when browser not service worker supported - if (!isSwSupported) return; - - // Reject when not signed in to Misskey - if (!this.isSignedin) return; - - // When service worker activated - navigator.serviceWorker.ready.then(registration => { - this.log('[sw] ready: ', registration); - - this.swRegistration = registration; - - // Options of pushManager.subscribe - // SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters - const opts = { - // A boolean indicating that the returned push subscription - // will only be used for messages whose effect is made visible to the user. - userVisibleOnly: true, - - // A public key your push server will use to send - // messages to client apps via a push server. - applicationServerKey: urlBase64ToUint8Array(_SW_PUBLICKEY_) - }; - - // Subscribe push notification - this.swRegistration.pushManager.subscribe(opts).then(subscription => { - this.log('[sw] Subscribe OK:', subscription); - - function encode(buffer: ArrayBuffer) { - return btoa(String.fromCharCode.apply(null, new Uint8Array(buffer))); - } - - // Register - this.api('sw/register', { - endpoint: subscription.endpoint, - auth: encode(subscription.getKey('auth')), - publickey: encode(subscription.getKey('p256dh')) - }); - }) - // When subscribe failed - .catch(async (err: Error) => { - this.logError('[sw] Subscribe Error:', err); - - // 通知が許可されていなかったとき - if (err.name == 'NotAllowedError') { - this.logError('[sw] Subscribe failed due to notification not allowed'); - return; - } - - // 違うapplicationServerKey (または gcm_sender_id)のサブスクリプションが - // 既に存在していることが原因でエラーになった可能性があるので、 - // そのサブスクリプションを解除しておく - const subscription = await this.swRegistration.pushManager.getSubscription(); - if (subscription) subscription.unsubscribe(); - }); - }); - - // The path of service worker script - const sw = `/sw.${_VERSION_}.${_LANG_}.js`; - - // Register service worker - navigator.serviceWorker.register(sw).then(registration => { - // 登録成功 - this.logInfo('[sw] Registration successful with scope: ', registration.scope); - }).catch(err => { - // 登録失敗 :( - this.logError('[sw] Registration failed: ', err); - }); - } - - /** - * Misskey APIにリクエストします - * @param endpoint エンドポイント名 - * @param data パラメータ - */ - public api(endpoint: string, data?: { [x: string]: any }) { - return api(this.i, endpoint, data); - } - - /** - * Misskeyのメタ情報を取得します - * @param force キャッシュを無視するか否か - */ - public getMeta(force = false) { - return new Promise<{ [x: string]: any }>(async (res, rej) => { - if (this.isMetaFetching) { - this.once('_meta_fetched_', () => { - res(this.meta.data); - }); - return; - } - - const expire = 1000 * 60; // 1min - - // forceが有効, meta情報を保持していない or 期限切れ - if (force || this.meta == null || Date.now() - this.meta.chachedAt.getTime() > expire) { - this.isMetaFetching = true; - const meta = await this.api('meta'); - this.meta = { - data: meta, - chachedAt: new Date() - }; - this.isMetaFetching = false; - this.emit('_meta_fetched_'); - res(meta); - } else { - res(this.meta.data); - } - }); - } -} - -/** - * Convert the URL safe base64 string to a Uint8Array - * @param base64String base64 string - */ -function urlBase64ToUint8Array(base64String: string): Uint8Array { - const padding = '='.repeat((4 - base64String.length % 4) % 4); - const base64 = (base64String + padding) - .replace(/\-/g, '+') - .replace(/_/g, '/'); - - const rawData = window.atob(base64); - const outputArray = new Uint8Array(rawData.length); - - for (let i = 0; i < rawData.length; ++i) { - outputArray[i] = rawData.charCodeAt(i); - } - return outputArray; -} diff --git a/src/web/app/common/mixins.ts b/src/web/app/common/mixins.ts deleted file mode 100644 index e9c3625937..0000000000 --- a/src/web/app/common/mixins.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as riot from 'riot'; - -import MiOS from './mios'; -import ServerStreamManager from './scripts/streaming/server-stream-manager'; -import RequestsStreamManager from './scripts/streaming/requests-stream-manager'; -import MessagingIndexStreamManager from './scripts/streaming/messaging-index-stream-manager'; -import DriveStreamManager from './scripts/streaming/drive-stream-manager'; - -export default (mios: MiOS) => { - (riot as any).mixin('os', { - mios: mios - }); - - (riot as any).mixin('i', { - init: function() { - this.I = mios.i; - this.SIGNIN = mios.isSignedin; - - if (this.SIGNIN) { - this.on('mount', () => { - mios.i.on('updated', this.update); - }); - this.on('unmount', () => { - mios.i.off('updated', this.update); - }); - } - }, - me: mios.i - }); - - (riot as any).mixin('api', { - api: mios.api - }); - - (riot as any).mixin('stream', { stream: mios.stream }); - (riot as any).mixin('drive-stream', { driveStream: new DriveStreamManager(mios.i) }); - (riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() }); - (riot as any).mixin('requests-stream', { requestsStream: new RequestsStreamManager() }); - (riot as any).mixin('messaging-index-stream', { messagingIndexStream: new MessagingIndexStreamManager(mios.i) }); -}; diff --git a/src/web/app/common/scripts/api.ts b/src/web/app/common/scripts/api.ts deleted file mode 100644 index 2008e6f5ac..0000000000 --- a/src/web/app/common/scripts/api.ts +++ /dev/null @@ -1,47 +0,0 @@ -/** - * API Request - */ - -declare const _API_URL_: string; - -let spinner = null; -let pending = 0; - -/** - * Send a request to API - * @param {string|Object} i Credential - * @param {string} endpoint Endpoint - * @param {any} [data={}] Data - * @return {Promise<any>} Response - */ -export default (i, endpoint, data = {}): Promise<{ [x: string]: any }> => { - if (++pending === 1) { - spinner = document.createElement('div'); - spinner.setAttribute('id', 'wait'); - document.body.appendChild(spinner); - } - - // Append the credential - if (i != null) (data as any).i = typeof i === 'object' ? i.token : i; - - return new Promise((resolve, reject) => { - // Send request - fetch(endpoint.indexOf('://') > -1 ? endpoint : `${_API_URL_}/${endpoint}`, { - method: 'POST', - body: JSON.stringify(data), - credentials: endpoint === 'signin' ? 'include' : 'omit', - cache: 'no-cache' - }).then(res => { - if (--pending === 0) spinner.parentNode.removeChild(spinner); - if (res.status === 200) { - res.json().then(resolve); - } else if (res.status === 204) { - resolve(); - } else { - res.json().then(err => { - reject(err.error); - }); - } - }).catch(reject); - }); -}; diff --git a/src/web/app/common/scripts/bytes-to-size.ts b/src/web/app/common/scripts/bytes-to-size.ts deleted file mode 100644 index 1d2b1e7ce3..0000000000 --- a/src/web/app/common/scripts/bytes-to-size.ts +++ /dev/null @@ -1,6 +0,0 @@ -export default (bytes, digits = 0) => { - const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - if (bytes == 0) return '0Byte'; - const i = Math.floor(Math.log(bytes) / Math.log(1024)); - return (bytes / Math.pow(1024, i)).toFixed(digits).replace(/\.0+$/, '') + sizes[i]; -}; diff --git a/src/web/app/common/scripts/check-for-update.ts b/src/web/app/common/scripts/check-for-update.ts deleted file mode 100644 index 0b58c0a674..0000000000 --- a/src/web/app/common/scripts/check-for-update.ts +++ /dev/null @@ -1,24 +0,0 @@ -import MiOS from '../mios'; - -declare const _VERSION_: string; - -export default async function(mios: MiOS) { - const meta = await mios.getMeta(); - - if (meta.version != _VERSION_) { - localStorage.setItem('should-refresh', 'true'); - - // Clear cache (serive worker) - try { - navigator.serviceWorker.controller.postMessage('clear'); - - navigator.serviceWorker.getRegistrations().then(registrations => { - registrations.forEach(registration => registration.unregister()); - }); - } catch (e) { - console.error(e); - } - - alert('%i18n:common.update-available%'.replace('{newer}', meta.version).replace('{current}', _VERSION_)); - } -} diff --git a/src/web/app/common/scripts/compose-notification.ts b/src/web/app/common/scripts/compose-notification.ts deleted file mode 100644 index d0e0c2098d..0000000000 --- a/src/web/app/common/scripts/compose-notification.ts +++ /dev/null @@ -1,60 +0,0 @@ -import getPostSummary from '../../../../common/get-post-summary'; -import getReactionEmoji from '../../../../common/get-reaction-emoji'; - -type Notification = { - title: string; - body: string; - icon: string; - onclick?: any; -}; - -// TODO: i18n - -export default function(type, data): Notification { - switch (type) { - case 'drive_file_created': - return { - title: 'ファイルがアップロードされました', - body: data.name, - icon: data.url + '?thumbnail&size=64' - }; - - case 'mention': - return { - title: `${data.user.name}さんから:`, - body: getPostSummary(data), - icon: data.user.avatar_url + '?thumbnail&size=64' - }; - - case 'reply': - return { - title: `${data.user.name}さんから返信:`, - body: getPostSummary(data), - icon: data.user.avatar_url + '?thumbnail&size=64' - }; - - case 'quote': - return { - title: `${data.user.name}さんが引用:`, - body: getPostSummary(data), - icon: data.user.avatar_url + '?thumbnail&size=64' - }; - - case 'reaction': - return { - title: `${data.user.name}: ${getReactionEmoji(data.reaction)}:`, - body: getPostSummary(data.post), - icon: data.user.avatar_url + '?thumbnail&size=64' - }; - - case 'unread_messaging_message': - return { - title: `${data.user.name}さんからメッセージ:`, - body: data.text, // TODO: getMessagingMessageSummary(data), - icon: data.user.avatar_url + '?thumbnail&size=64' - }; - - default: - return null; - } -} diff --git a/src/web/app/common/scripts/contains.ts b/src/web/app/common/scripts/contains.ts deleted file mode 100644 index a5071b3f25..0000000000 --- a/src/web/app/common/scripts/contains.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default (parent, child) => { - let node = child.parentNode; - while (node) { - if (node == parent) return true; - node = node.parentNode; - } - return false; -}; diff --git a/src/web/app/common/scripts/copy-to-clipboard.ts b/src/web/app/common/scripts/copy-to-clipboard.ts deleted file mode 100644 index 3d2741f8d7..0000000000 --- a/src/web/app/common/scripts/copy-to-clipboard.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Clipboardに値をコピー(TODO: 文字列以外も対応) - */ -export default val => { - const form = document.createElement('textarea'); - form.textContent = val; - document.body.appendChild(form); - form.select(); - const result = document.execCommand('copy'); - document.body.removeChild(form); - - return result; -}; diff --git a/src/web/app/common/scripts/date-stringify.ts b/src/web/app/common/scripts/date-stringify.ts deleted file mode 100644 index e51de8833d..0000000000 --- a/src/web/app/common/scripts/date-stringify.ts +++ /dev/null @@ -1,13 +0,0 @@ -export default date => { - if (typeof date == 'string') date = new Date(date); - return ( - date.getFullYear() + '年' + - (date.getMonth() + 1) + '月' + - date.getDate() + '日' + - ' ' + - date.getHours() + '時' + - date.getMinutes() + '分' + - ' ' + - `(${['日', '月', '火', '水', '木', '金', '土'][date.getDay()]})` - ); -}; diff --git a/src/web/app/common/scripts/gcd.ts b/src/web/app/common/scripts/gcd.ts deleted file mode 100644 index 9a19f9da66..0000000000 --- a/src/web/app/common/scripts/gcd.ts +++ /dev/null @@ -1,2 +0,0 @@ -const gcd = (a, b) => !b ? a : gcd(b, a % b); -export default gcd; diff --git a/src/web/app/common/scripts/get-kao.ts b/src/web/app/common/scripts/get-kao.ts deleted file mode 100644 index 2168c5be88..0000000000 --- a/src/web/app/common/scripts/get-kao.ts +++ /dev/null @@ -1,5 +0,0 @@ -export default () => [ - '(=^・・^=)', - 'v(‘ω’)v', - '🐡( \'-\' 🐡 )フグパンチ!!!!' -][Math.floor(Math.random() * 3)]; diff --git a/src/web/app/common/scripts/get-median.ts b/src/web/app/common/scripts/get-median.ts deleted file mode 100644 index 91a415d5b2..0000000000 --- a/src/web/app/common/scripts/get-median.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * 中央値を求めます - * @param samples サンプル - */ -export default function(samples) { - if (!samples.length) return 0; - const numbers = samples.slice(0).sort((a, b) => a - b); - const middle = Math.floor(numbers.length / 2); - const isEven = numbers.length % 2 === 0; - return isEven ? (numbers[middle] + numbers[middle - 1]) / 2 : numbers[middle]; -} diff --git a/src/web/app/common/scripts/is-promise.ts b/src/web/app/common/scripts/is-promise.ts deleted file mode 100644 index 3b4cd70b49..0000000000 --- a/src/web/app/common/scripts/is-promise.ts +++ /dev/null @@ -1 +0,0 @@ -export default x => typeof x.then == 'function'; diff --git a/src/web/app/common/scripts/loading.ts b/src/web/app/common/scripts/loading.ts deleted file mode 100644 index c48e626648..0000000000 --- a/src/web/app/common/scripts/loading.ts +++ /dev/null @@ -1,21 +0,0 @@ -const NProgress = require('nprogress'); -NProgress.configure({ - trickleSpeed: 500, - showSpinner: false -}); - -const root = document.getElementsByTagName('html')[0]; - -export default { - start: () => { - root.classList.add('progress'); - NProgress.start(); - }, - done: () => { - root.classList.remove('progress'); - NProgress.done(); - }, - set: val => { - NProgress.set(val); - } -}; diff --git a/src/web/app/common/scripts/signout.ts b/src/web/app/common/scripts/signout.ts deleted file mode 100644 index 2923196549..0000000000 --- a/src/web/app/common/scripts/signout.ts +++ /dev/null @@ -1,7 +0,0 @@ -declare const _HOST_: string; - -export default () => { - localStorage.removeItem('me'); - document.cookie = `i=; domain=.${_HOST_}; expires=Thu, 01 Jan 1970 00:00:01 GMT;`; - location.href = '/'; -}; diff --git a/src/web/app/common/scripts/streaming/channel-stream.ts b/src/web/app/common/scripts/streaming/channel-stream.ts deleted file mode 100644 index 434b108b9e..0000000000 --- a/src/web/app/common/scripts/streaming/channel-stream.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Stream from './stream'; - -/** - * Channel stream connection - */ -export default class Connection extends Stream { - constructor(channelId) { - super('channel', { - channel: channelId - }); - } -} diff --git a/src/web/app/common/scripts/streaming/drive-stream-manager.ts b/src/web/app/common/scripts/streaming/drive-stream-manager.ts deleted file mode 100644 index 8acdd7cbba..0000000000 --- a/src/web/app/common/scripts/streaming/drive-stream-manager.ts +++ /dev/null @@ -1,20 +0,0 @@ -import StreamManager from './stream-manager'; -import Connection from './drive-stream'; - -export default class DriveStreamManager extends StreamManager<Connection> { - private me; - - constructor(me) { - super(); - - this.me = me; - } - - public getConnection() { - if (this.connection == null) { - this.connection = new Connection(this.me); - } - - return this.connection; - } -} diff --git a/src/web/app/common/scripts/streaming/drive-stream.ts b/src/web/app/common/scripts/streaming/drive-stream.ts deleted file mode 100644 index 0da3f12554..0000000000 --- a/src/web/app/common/scripts/streaming/drive-stream.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Stream from './stream'; - -/** - * Drive stream connection - */ -export default class Connection extends Stream { - constructor(me) { - super('drive', { - i: me.token - }); - } -} diff --git a/src/web/app/common/scripts/streaming/home-stream-manager.ts b/src/web/app/common/scripts/streaming/home-stream-manager.ts deleted file mode 100644 index ad1dc870eb..0000000000 --- a/src/web/app/common/scripts/streaming/home-stream-manager.ts +++ /dev/null @@ -1,20 +0,0 @@ -import StreamManager from './stream-manager'; -import Connection from './home-stream'; - -export default class HomeStreamManager extends StreamManager<Connection> { - private me; - - constructor(me) { - super(); - - this.me = me; - } - - public getConnection() { - if (this.connection == null) { - this.connection = new Connection(this.me); - } - - return this.connection; - } -} diff --git a/src/web/app/common/scripts/streaming/home-stream.ts b/src/web/app/common/scripts/streaming/home-stream.ts deleted file mode 100644 index 11ad754ef0..0000000000 --- a/src/web/app/common/scripts/streaming/home-stream.ts +++ /dev/null @@ -1,28 +0,0 @@ -import Stream from './stream'; -import signout from '../signout'; - -/** - * Home stream connection - */ -export default class Connection extends Stream { - constructor(me) { - super('', { - i: me.token - }); - - // 最終利用日時を更新するため定期的にaliveメッセージを送信 - setInterval(() => { - this.send({ type: 'alive' }); - }, 1000 * 60); - - // 自分の情報が更新されたとき - this.on('i_updated', me.update); - - // トークンが再生成されたとき - // このままではAPIが利用できないので強制的にサインアウトさせる - this.on('my_token_regenerated', () => { - alert('%i18n:common.my-token-regenerated%'); - signout(); - }); - } -} diff --git a/src/web/app/common/scripts/streaming/messaging-index-stream-manager.ts b/src/web/app/common/scripts/streaming/messaging-index-stream-manager.ts deleted file mode 100644 index 0f08b01481..0000000000 --- a/src/web/app/common/scripts/streaming/messaging-index-stream-manager.ts +++ /dev/null @@ -1,20 +0,0 @@ -import StreamManager from './stream-manager'; -import Connection from './messaging-index-stream'; - -export default class MessagingIndexStreamManager extends StreamManager<Connection> { - private me; - - constructor(me) { - super(); - - this.me = me; - } - - public getConnection() { - if (this.connection == null) { - this.connection = new Connection(this.me); - } - - return this.connection; - } -} diff --git a/src/web/app/common/scripts/streaming/messaging-index-stream.ts b/src/web/app/common/scripts/streaming/messaging-index-stream.ts deleted file mode 100644 index 8015c840b4..0000000000 --- a/src/web/app/common/scripts/streaming/messaging-index-stream.ts +++ /dev/null @@ -1,12 +0,0 @@ -import Stream from './stream'; - -/** - * Messaging index stream connection - */ -export default class Connection extends Stream { - constructor(me) { - super('messaging-index', { - i: me.token - }); - } -} diff --git a/src/web/app/common/scripts/streaming/messaging-stream.ts b/src/web/app/common/scripts/streaming/messaging-stream.ts deleted file mode 100644 index 68dfc5ec09..0000000000 --- a/src/web/app/common/scripts/streaming/messaging-stream.ts +++ /dev/null @@ -1,19 +0,0 @@ -import Stream from './stream'; - -/** - * Messaging stream connection - */ -export default class Connection extends Stream { - constructor(me, otherparty) { - super('messaging', { - i: me.token, - otherparty - }); - - (this as any).on('_connected_', () => { - this.send({ - i: me.token - }); - }); - } -} diff --git a/src/web/app/common/scripts/streaming/requests-stream-manager.ts b/src/web/app/common/scripts/streaming/requests-stream-manager.ts deleted file mode 100644 index 44db913e78..0000000000 --- a/src/web/app/common/scripts/streaming/requests-stream-manager.ts +++ /dev/null @@ -1,12 +0,0 @@ -import StreamManager from './stream-manager'; -import Connection from './requests-stream'; - -export default class RequestsStreamManager extends StreamManager<Connection> { - public getConnection() { - if (this.connection == null) { - this.connection = new Connection(); - } - - return this.connection; - } -} diff --git a/src/web/app/common/scripts/streaming/requests-stream.ts b/src/web/app/common/scripts/streaming/requests-stream.ts deleted file mode 100644 index 22ecea6c07..0000000000 --- a/src/web/app/common/scripts/streaming/requests-stream.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Stream from './stream'; - -/** - * Requests stream connection - */ -export default class Connection extends Stream { - constructor() { - super('requests'); - } -} diff --git a/src/web/app/common/scripts/streaming/server-stream-manager.ts b/src/web/app/common/scripts/streaming/server-stream-manager.ts deleted file mode 100644 index a170daebb9..0000000000 --- a/src/web/app/common/scripts/streaming/server-stream-manager.ts +++ /dev/null @@ -1,12 +0,0 @@ -import StreamManager from './stream-manager'; -import Connection from './server-stream'; - -export default class ServerStreamManager extends StreamManager<Connection> { - public getConnection() { - if (this.connection == null) { - this.connection = new Connection(); - } - - return this.connection; - } -} diff --git a/src/web/app/common/scripts/streaming/server-stream.ts b/src/web/app/common/scripts/streaming/server-stream.ts deleted file mode 100644 index b9e0684465..0000000000 --- a/src/web/app/common/scripts/streaming/server-stream.ts +++ /dev/null @@ -1,10 +0,0 @@ -import Stream from './stream'; - -/** - * Server stream connection - */ -export default class Connection extends Stream { - constructor() { - super('server'); - } -} diff --git a/src/web/app/common/scripts/streaming/stream-manager.ts b/src/web/app/common/scripts/streaming/stream-manager.ts deleted file mode 100644 index 5bb0dc701c..0000000000 --- a/src/web/app/common/scripts/streaming/stream-manager.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { EventEmitter } from 'eventemitter3'; -import * as uuid from 'uuid'; -import Connection from './stream'; - -/** - * ストリーム接続を管理するクラス - * 複数の場所から同じストリームを利用する際、接続をまとめたりする - */ -export default abstract class StreamManager<T extends Connection> extends EventEmitter { - private _connection: T = null; - - private disposeTimerId: any; - - /** - * コネクションを必要としているユーザー - */ - private users = []; - - protected set connection(connection: T) { - this._connection = connection; - - if (this._connection == null) { - this.emit('disconnected'); - } else { - this.emit('connected', this._connection); - } - } - - protected get connection() { - return this._connection; - } - - /** - * コネクションを持っているか否か - */ - public get hasConnection() { - return this._connection != null; - } - - /** - * コネクションを要求します - */ - public abstract getConnection(): T; - - /** - * 現在接続しているコネクションを取得します - */ - public borrow() { - return this._connection; - } - - /** - * コネクションを要求するためのユーザーIDを発行します - */ - public use() { - // タイマー解除 - if (this.disposeTimerId) { - clearTimeout(this.disposeTimerId); - this.disposeTimerId = null; - } - - // ユーザーID生成 - const userId = uuid(); - - this.users.push(userId); - - return userId; - } - - /** - * コネクションを利用し終わってもう必要ないことを通知します - * @param userId use で発行したユーザーID - */ - public dispose(userId) { - this.users = this.users.filter(id => id != userId); - - // 誰もコネクションの利用者がいなくなったら - if (this.users.length == 0) { - // また直ぐに再利用される可能性があるので、一定時間待ち、 - // 新たな利用者が現れなければコネクションを切断する - this.disposeTimerId = setTimeout(() => { - this.disposeTimerId = null; - - this.connection.close(); - this.connection = null; - }, 3000); - } - } -} diff --git a/src/web/app/common/scripts/streaming/stream.ts b/src/web/app/common/scripts/streaming/stream.ts deleted file mode 100644 index 770d77510f..0000000000 --- a/src/web/app/common/scripts/streaming/stream.ts +++ /dev/null @@ -1,96 +0,0 @@ -declare const _API_URL_: string; - -import { EventEmitter } from 'eventemitter3'; -import * as ReconnectingWebsocket from 'reconnecting-websocket'; - -/** - * Misskey stream connection - */ -export default class Connection extends EventEmitter { - private state: string; - private buffer: any[]; - private socket: ReconnectingWebsocket; - - constructor(endpoint, params?) { - super(); - - //#region BIND - this.onOpen = this.onOpen.bind(this); - this.onClose = this.onClose.bind(this); - this.onMessage = this.onMessage.bind(this); - this.send = this.send.bind(this); - this.close = this.close.bind(this); - //#endregion - - this.state = 'initializing'; - this.buffer = []; - - const host = _API_URL_.replace('http', 'ws'); - const query = params - ? Object.keys(params) - .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) - .join('&') - : null; - - this.socket = new ReconnectingWebsocket(`${host}/${endpoint}${query ? '?' + query : ''}`); - this.socket.addEventListener('open', this.onOpen); - this.socket.addEventListener('close', this.onClose); - this.socket.addEventListener('message', this.onMessage); - } - - /** - * Callback of when open connection - */ - private onOpen() { - this.state = 'connected'; - this.emit('_connected_'); - - // バッファーを処理 - const _buffer = [].concat(this.buffer); // Shallow copy - this.buffer = []; // Clear buffer - _buffer.forEach(message => { - this.send(message); // Resend each buffered messages - }); - } - - /** - * Callback of when close connection - */ - private onClose() { - this.state = 'reconnecting'; - this.emit('_closed_'); - } - - /** - * Callback of when received a message from connection - */ - private onMessage(message) { - try { - const msg = JSON.parse(message.data); - if (msg.type) this.emit(msg.type, msg.body); - } catch (e) { - // noop - } - } - - /** - * Send a message to connection - */ - public send(message) { - // まだ接続が確立されていなかったらバッファリングして次に接続した時に送信する - if (this.state != 'connected') { - this.buffer.push(message); - return; - } - - this.socket.send(JSON.stringify(message)); - } - - /** - * Close this connection - */ - public close() { - this.socket.removeEventListener('open', this.onOpen); - this.socket.removeEventListener('message', this.onMessage); - } -} diff --git a/src/web/app/common/scripts/text-compiler.ts b/src/web/app/common/scripts/text-compiler.ts deleted file mode 100644 index e0ea47df26..0000000000 --- a/src/web/app/common/scripts/text-compiler.ts +++ /dev/null @@ -1,48 +0,0 @@ -declare const _URL_: string; - -import * as riot from 'riot'; -import * as pictograph from 'pictograph'; - -const escape = text => - text - .replace(/>/g, '>') - .replace(/</g, '<'); - -export default (tokens, shouldBreak) => { - if (shouldBreak == null) { - shouldBreak = true; - } - - const me = (riot as any).mixin('i').me; - - let text = tokens.map(token => { - switch (token.type) { - case 'text': - return escape(token.content) - .replace(/(\r\n|\n|\r)/g, shouldBreak ? '<br>' : ' '); - case 'bold': - return `<strong>${escape(token.bold)}</strong>`; - case 'url': - return `<mk-url href="${escape(token.content)}" target="_blank"></mk-url>`; - case 'link': - return `<a class="link" href="${escape(token.url)}" target="_blank" title="${escape(token.url)}">${escape(token.title)}</a>`; - case 'mention': - return `<a href="${_URL_ + '/' + escape(token.username)}" target="_blank" data-user-preview="${token.content}" ${me && me.username == token.username ? 'data-is-me' : ''}>${token.content}</a>`; - case 'hashtag': // TODO - return `<a>${escape(token.content)}</a>`; - case 'code': - return `<pre><code>${token.html}</code></pre>`; - case 'inline-code': - return `<code>${token.html}</code>`; - case 'emoji': - return pictograph.dic[token.emoji] || token.content; - } - }).join(''); - - // Remove needless whitespaces - text = text - .replace(/ <code>/g, '<code>').replace(/<\/code> /g, '</code>') - .replace(/<br><code><pre>/g, '<code><pre>').replace(/<\/code><\/pre><br>/g, '</code></pre>'); - - return text; -}; diff --git a/src/web/app/common/tags/activity-table.tag b/src/web/app/common/tags/activity-table.tag deleted file mode 100644 index 1d26d1788a..0000000000 --- a/src/web/app/common/tags/activity-table.tag +++ /dev/null @@ -1,57 +0,0 @@ -<mk-activity-table> - <svg if={ data } ref="canvas" viewBox="0 0 53 7" preserveAspectRatio="none"> - <rect each={ data } width="1" height="1" - riot-x={ x } riot-y={ date.weekday } - rx="1" ry="1" - fill={ color } - style="transform: scale({ v });"/> - <rect class="today" width="1" height="1" - riot-x={ data[data.length - 1].x } riot-y={ data[data.length - 1].date.weekday } - rx="1" ry="1" - fill="none" - stroke-width="0.1" - stroke="#f73520"/> - </svg> - <style> - :scope - display block - max-width 600px - margin 0 auto - - > svg - display block - - > rect - transform-origin center - - </style> - <script> - this.mixin('api'); - - this.user = this.opts.user; - - this.on('mount', () => { - this.api('aggregation/users/activity', { - user_id: this.user.id - }).then(data => { - data.forEach(d => d.total = d.posts + d.replies + d.reposts); - this.peak = Math.max.apply(null, data.map(d => d.total)) / 2; - let x = 0; - data.reverse().forEach(d => { - d.x = x; - d.date.weekday = (new Date(d.date.year, d.date.month - 1, d.date.day)).getDay(); - - d.v = d.total / this.peak; - if (d.v > 1) d.v = 1; - const ch = d.date.weekday == 0 || d.date.weekday == 6 ? 275 : 170; - const cs = d.v * 100; - const cl = 15 + ((1 - d.v) * 80); - d.color = `hsl(${ch}, ${cs}%, ${cl}%)`; - - if (d.date.weekday == 6) x++; - }); - this.update({ data }); - }); - }); - </script> -</mk-activity-table> diff --git a/src/web/app/common/tags/authorized-apps.tag b/src/web/app/common/tags/authorized-apps.tag deleted file mode 100644 index 0594032de6..0000000000 --- a/src/web/app/common/tags/authorized-apps.tag +++ /dev/null @@ -1,35 +0,0 @@ -<mk-authorized-apps> - <div class="none ui info" if={ !fetching && apps.length == 0 }> - <p>%fa:info-circle%%i18n:common.tags.mk-authorized-apps.no-apps%</p> - </div> - <div class="apps" if={ apps.length != 0 }> - <div each={ app in apps }> - <p><b>{ app.name }</b></p> - <p>{ app.description }</p> - </div> - </div> - <style> - :scope - display block - - > .apps - > div - padding 16px 0 0 0 - border-bottom solid 1px #eee - - </style> - <script> - this.mixin('api'); - - this.apps = []; - this.fetching = true; - - this.on('mount', () => { - this.api('i/authorized_apps').then(apps => { - this.apps = apps; - this.fetching = false; - this.update(); - }); - }); - </script> -</mk-authorized-apps> diff --git a/src/web/app/common/tags/copyright.tag b/src/web/app/common/tags/copyright.tag deleted file mode 100644 index 9c3f1f648b..0000000000 --- a/src/web/app/common/tags/copyright.tag +++ /dev/null @@ -1,7 +0,0 @@ -<mk-copyright> - <span>(c) syuilo 2014-2017</span> - <style> - :scope - display block - </style> -</mk-copyright> diff --git a/src/web/app/common/tags/ellipsis.tag b/src/web/app/common/tags/ellipsis.tag deleted file mode 100644 index 97ef745d02..0000000000 --- a/src/web/app/common/tags/ellipsis.tag +++ /dev/null @@ -1,24 +0,0 @@ -<mk-ellipsis><span>.</span><span>.</span><span>.</span> - <style> - :scope - display inline - - > span - animation ellipsis 1.4s infinite ease-in-out both - - &:nth-child(1) - animation-delay 0s - - &:nth-child(2) - animation-delay 0.16s - - &:nth-child(3) - animation-delay 0.32s - - @keyframes ellipsis - 0%, 80%, 100% - opacity 1 - 40% - opacity 0 - </style> -</mk-ellipsis> diff --git a/src/web/app/common/tags/error.tag b/src/web/app/common/tags/error.tag deleted file mode 100644 index a5b8d14898..0000000000 --- a/src/web/app/common/tags/error.tag +++ /dev/null @@ -1,215 +0,0 @@ -<mk-error> - <img src="data:image/jpeg;base64,%base64:/assets/error.jpg%" alt=""/> - <h1>%i18n:common.tags.mk-error.title%</h1> - <p class="text">{ - '%i18n:common.tags.mk-error.description%'.substr(0, '%i18n:common.tags.mk-error.description%'.indexOf('{')) - }<a onclick={ reload }>{ - '%i18n:common.tags.mk-error.description%'.match(/\{(.+?)\}/)[1] - }</a>{ - '%i18n:common.tags.mk-error.description%'.substr('%i18n:common.tags.mk-error.description%'.indexOf('}') + 1) - }</p> - <button if={ !troubleshooting } onclick={ troubleshoot }>%i18n:common.tags.mk-error.troubleshoot%</button> - <mk-troubleshooter if={ troubleshooting }/> - <p class="thanks">%i18n:common.tags.mk-error.thanks%</p> - <style> - :scope - display block - width 100% - padding 32px 18px - text-align center - - > img - display block - height 200px - margin 0 auto - pointer-events none - user-select none - - > h1 - display block - margin 1.25em auto 0.65em auto - font-size 1.5em - color #555 - - > .text - display block - margin 0 auto - max-width 600px - font-size 1em - color #666 - - > button - display block - margin 1em auto 0 auto - padding 8px 10px - color $theme-color-foreground - background $theme-color - - &:focus - outline solid 3px rgba($theme-color, 0.3) - - &:hover - background lighten($theme-color, 10%) - - &:active - background darken($theme-color, 10%) - - > mk-troubleshooter - margin 1em auto 0 auto - - > .thanks - display block - margin 2em auto 0 auto - padding 2em 0 0 0 - max-width 600px - font-size 0.9em - font-style oblique - color #aaa - border-top solid 1px #eee - - @media (max-width 500px) - padding 24px 18px - font-size 80% - - > img - height 150px - - </style> - <script> - this.troubleshooting = false; - - this.on('mount', () => { - document.title = 'Oops!'; - document.documentElement.style.background = '#f8f8f8'; - }); - - this.reload = () => { - location.reload(); - }; - - this.troubleshoot = () => { - this.update({ - troubleshooting: true - }); - }; - </script> -</mk-error> - -<mk-troubleshooter> - <h1>%fa:wrench%%i18n:common.tags.mk-error.troubleshooter.title%</h1> - <div> - <p data-wip={ network == null }><virtual if={ network != null }><virtual if={ network }>%fa:check%</virtual><virtual if={ !network }>%fa:times%</virtual></virtual>{ network == null ? '%i18n:common.tags.mk-error.troubleshooter.checking-network%' : '%i18n:common.tags.mk-error.troubleshooter.network%' }<mk-ellipsis if={ network == null }/></p> - <p if={ network == true } data-wip={ internet == null }><virtual if={ internet != null }><virtual if={ internet }>%fa:check%</virtual><virtual if={ !internet }>%fa:times%</virtual></virtual>{ internet == null ? '%i18n:common.tags.mk-error.troubleshooter.checking-internet%' : '%i18n:common.tags.mk-error.troubleshooter.internet%' }<mk-ellipsis if={ internet == null }/></p> - <p if={ internet == true } data-wip={ server == null }><virtual if={ server != null }><virtual if={ server }>%fa:check%</virtual><virtual if={ !server }>%fa:times%</virtual></virtual>{ server == null ? '%i18n:common.tags.mk-error.troubleshooter.checking-server%' : '%i18n:common.tags.mk-error.troubleshooter.server%' }<mk-ellipsis if={ server == null }/></p> - </div> - <p if={ !end }>%i18n:common.tags.mk-error.troubleshooter.finding%<mk-ellipsis/></p> - <p if={ network === false }><b>%fa:exclamation-triangle%%i18n:common.tags.mk-error.troubleshooter.no-network%</b><br>%i18n:common.tags.mk-error.troubleshooter.no-network-desc%</p> - <p if={ internet === false }><b>%fa:exclamation-triangle%%i18n:common.tags.mk-error.troubleshooter.no-internet%</b><br>%i18n:common.tags.mk-error.troubleshooter.no-internet-desc%</p> - <p if={ server === false }><b>%fa:exclamation-triangle%%i18n:common.tags.mk-error.troubleshooter.no-server%</b><br>%i18n:common.tags.mk-error.troubleshooter.no-server-desc%</p> - <p if={ server === true } class="success"><b>%fa:info-circle%%i18n:common.tags.mk-error.troubleshooter.success%</b><br>%i18n:common.tags.mk-error.troubleshooter.success-desc%</p> - - <style> - :scope - display block - width 100% - max-width 500px - text-align left - background #fff - border-radius 8px - border solid 1px #ddd - - > h1 - margin 0 - padding 0.6em 1.2em - font-size 1em - color #444 - border-bottom solid 1px #eee - - > [data-fa] - margin-right 0.25em - - > div - overflow hidden - padding 0.6em 1.2em - - > p - margin 0.5em 0 - font-size 0.9em - color #444 - - &[data-wip] - color #888 - - > [data-fa] - margin-right 0.25em - - &.times - color #e03524 - - &.check - color #84c32f - - > p - margin 0 - padding 0.6em 1.2em - font-size 1em - color #444 - border-top solid 1px #eee - - > b - > [data-fa] - margin-right 0.25em - - &.success - > b - color #39adad - - &:not(.success) - > b - color #ad4339 - - </style> - <script> - this.on('mount', () => { - this.update({ - network: navigator.onLine - }); - - if (!this.network) { - this.update({ - end: true - }); - return; - } - - // Check internet connection - fetch('https://google.com?rand=' + Math.random(), { - mode: 'no-cors' - }).then(() => { - this.update({ - internet: true - }); - - // Check misskey server is available - fetch(`${_API_URL_}/meta`).then(() => { - this.update({ - end: true, - server: true - }); - }) - .catch(() => { - this.update({ - end: true, - server: false - }); - }); - }) - .catch(() => { - this.update({ - end: true, - internet: false - }); - }); - }); - </script> -</mk-troubleshooter> diff --git a/src/web/app/common/tags/file-type-icon.tag b/src/web/app/common/tags/file-type-icon.tag deleted file mode 100644 index dba2ae44d6..0000000000 --- a/src/web/app/common/tags/file-type-icon.tag +++ /dev/null @@ -1,10 +0,0 @@ -<mk-file-type-icon> - <virtual if={ kind == 'image' }>%fa:file-image%</virtual> - <style> - :scope - display inline - </style> - <script> - this.kind = this.opts.type.split('/')[0]; - </script> -</mk-file-type-icon> diff --git a/src/web/app/common/tags/forkit.tag b/src/web/app/common/tags/forkit.tag deleted file mode 100644 index 55d5731081..0000000000 --- a/src/web/app/common/tags/forkit.tag +++ /dev/null @@ -1,40 +0,0 @@ -<mk-forkit><a href="https://github.com/syuilo/misskey" target="_blank" title="%i18n:common.tags.mk-forkit.open-github-link%" aria-label="%i18n:common.tags.mk-forkit.open-github-link%"> - <svg width="80" height="80" viewBox="0 0 250 250" aria-hidden="aria-hidden"> - <path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path> - <path class="octo-arm" d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor"></path> - <path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor"></path> - </svg></a> - <style> - :scope - display block - position absolute - top 0 - right 0 - - > a - display block - - > svg - display block - //fill #151513 - //color #fff - fill $theme-color - color $theme-color-foreground - - .octo-arm - transform-origin 130px 106px - - &:hover - .octo-arm - animation octocat-wave 560ms ease-in-out - - @keyframes octocat-wave - 0%, 100% - transform rotate(0) - 20%, 60% - transform rotate(-25deg) - 40%, 80% - transform rotate(10deg) - - </style> -</mk-forkit> diff --git a/src/web/app/common/tags/index.ts b/src/web/app/common/tags/index.ts deleted file mode 100644 index 2f4e1181d4..0000000000 --- a/src/web/app/common/tags/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -require('./error.tag'); -require('./url.tag'); -require('./url-preview.tag'); -require('./time.tag'); -require('./file-type-icon.tag'); -require('./uploader.tag'); -require('./ellipsis.tag'); -require('./raw.tag'); -require('./number.tag'); -require('./special-message.tag'); -require('./signin.tag'); -require('./signup.tag'); -require('./forkit.tag'); -require('./introduction.tag'); -require('./copyright.tag'); -require('./signin-history.tag'); -require('./twitter-setting.tag'); -require('./authorized-apps.tag'); -require('./poll.tag'); -require('./poll-editor.tag'); -require('./messaging/room.tag'); -require('./messaging/message.tag'); -require('./messaging/index.tag'); -require('./messaging/form.tag'); -require('./stream-indicator.tag'); -require('./activity-table.tag'); -require('./reaction-picker.tag'); -require('./reactions-viewer.tag'); -require('./reaction-icon.tag'); -require('./post-menu.tag'); -require('./nav-links.tag'); diff --git a/src/web/app/common/tags/introduction.tag b/src/web/app/common/tags/introduction.tag deleted file mode 100644 index 3256688d10..0000000000 --- a/src/web/app/common/tags/introduction.tag +++ /dev/null @@ -1,25 +0,0 @@ -<mk-introduction> - <article> - <h1>Misskeyとは?</h1> - <p><ruby>Misskey<rt>みすきー</rt></ruby>は、<a href="http://syuilo.com" target="_blank">syuilo</a>が2014年くらいから<a href="https://github.com/syuilo/misskey" target="_blank">オープンソースで</a>開発・運営を行っている、ミニブログベースのSNSです。</p> - <p>無料で誰でも利用でき、広告も掲載していません。</p> - <p><a href={ _ABOUT_URL_ } target="_blank">もっと知りたい方はこちら</a></p> - </article> - <style> - :scope - display block - - h1 - margin 0 - text-align center - font-size 1.2em - - p - margin 16px 0 - - &:last-child - margin 0 - text-align center - - </style> -</mk-introduction> diff --git a/src/web/app/common/tags/messaging/form.tag b/src/web/app/common/tags/messaging/form.tag deleted file mode 100644 index 7b133a71c4..0000000000 --- a/src/web/app/common/tags/messaging/form.tag +++ /dev/null @@ -1,175 +0,0 @@ -<mk-messaging-form> - <textarea ref="text" onkeypress={ onkeypress } onpaste={ onpaste } placeholder="%i18n:common.input-message-here%"></textarea> - <div class="files"></div> - <mk-uploader ref="uploader"/> - <button class="send" onclick={ send } disabled={ sending } title="%i18n:common.send%"> - <virtual if={ !sending }>%fa:paper-plane%</virtual><virtual if={ sending }>%fa:spinner .spin%</virtual> - </button> - <button class="attach-from-local" type="button" title="%i18n:common.tags.mk-messaging-form.attach-from-local%"> - %fa:upload% - </button> - <button class="attach-from-drive" type="button" title="%i18n:common.tags.mk-messaging-form.attach-from-drive%"> - %fa:R folder-open% - </button> - <input name="file" type="file" accept="image/*"/> - <style> - :scope - display block - - > textarea - cursor auto - display block - width 100% - min-width 100% - max-width 100% - height 64px - margin 0 - padding 8px - font-size 1em - color #000 - outline none - border none - border-top solid 1px #eee - border-radius 0 - box-shadow none - background transparent - - > .send - position absolute - bottom 0 - right 0 - margin 0 - padding 10px 14px - line-height 1em - font-size 1em - color #aaa - transition color 0.1s ease - - &:hover - color $theme-color - - &:active - color darken($theme-color, 10%) - transition color 0s ease - - .files - display block - margin 0 - padding 0 8px - list-style none - - &:after - content '' - display block - clear both - - > li - display block - float left - margin 4px - padding 0 - width 64px - height 64px - background-color #eee - background-repeat no-repeat - background-position center center - background-size cover - cursor move - - &:hover - > .remove - display block - - > .remove - display none - position absolute - right -6px - top -6px - margin 0 - padding 0 - background transparent - outline none - border none - border-radius 0 - box-shadow none - cursor pointer - - .attach-from-local - .attach-from-drive - margin 0 - padding 10px 14px - line-height 1em - font-size 1em - font-weight normal - text-decoration none - color #aaa - transition color 0.1s ease - - &:hover - color $theme-color - - &:active - color darken($theme-color, 10%) - transition color 0s ease - - input[type=file] - display none - - </style> - <script> - this.mixin('api'); - - this.onpaste = e => { - const data = e.clipboardData; - const items = data.items; - for (const item of items) { - if (item.kind == 'file') { - this.upload(item.getAsFile()); - } - } - }; - - this.onkeypress = e => { - if ((e.which == 10 || e.which == 13) && e.ctrlKey) { - this.send(); - } - }; - - this.selectFile = () => { - this.refs.file.click(); - }; - - this.selectFileFromDrive = () => { - const browser = document.body.appendChild(document.createElement('mk-select-file-from-drive-window')); - const event = riot.observable(); - riot.mount(browser, { - multiple: true, - event: event - }); - event.one('selected', files => { - files.forEach(this.addFile); - }); - }; - - this.send = () => { - this.sending = true; - this.api('messaging/messages/create', { - user_id: this.opts.user.id, - text: this.refs.text.value - }).then(message => { - this.clear(); - }).catch(err => { - console.error(err); - }).then(() => { - this.sending = false; - this.update(); - }); - }; - - this.clear = () => { - this.refs.text.value = ''; - this.files = []; - this.update(); - }; - </script> -</mk-messaging-form> diff --git a/src/web/app/common/tags/messaging/index.tag b/src/web/app/common/tags/messaging/index.tag deleted file mode 100644 index d26cec6cdf..0000000000 --- a/src/web/app/common/tags/messaging/index.tag +++ /dev/null @@ -1,456 +0,0 @@ -<mk-messaging data-compact={ opts.compact }> - <div class="search" if={ !opts.compact }> - <div class="form"> - <label for="search-input">%fa:search%</label> - <input ref="search" type="search" oninput={ search } onkeydown={ onSearchKeydown } placeholder="%i18n:common.tags.mk-messaging.search-user%"/> - </div> - <div class="result"> - <ol class="users" if={ searchResult.length > 0 } ref="searchResult"> - <li each={ user, i in searchResult } onkeydown={ parent.onSearchResultKeydown.bind(null, i) } onclick={ user._click } tabindex="-1"> - <img class="avatar" src={ user.avatar_url + '?thumbnail&size=32' } alt=""/> - <span class="name">{ user.name }</span> - <span class="username">@{ user.username }</span> - </li> - </ol> - </div> - </div> - <div class="history" if={ history.length > 0 }> - <virtual each={ history }> - <a class="user" data-is-me={ is_me } data-is-read={ is_read } onclick={ _click }> - <div> - <img class="avatar" src={ (is_me ? recipient.avatar_url : user.avatar_url) + '?thumbnail&size=64' } alt=""/> - <header> - <span class="name">{ is_me ? recipient.name : user.name }</span> - <span class="username">{ '@' + (is_me ? recipient.username : user.username ) }</span> - <mk-time time={ created_at }/> - </header> - <div class="body"> - <p class="text"><span class="me" if={ is_me }>%i18n:common.tags.mk-messaging.you%:</span>{ text }</p> - </div> - </div> - </a> - </virtual> - </div> - <p class="no-history" if={ !fetching && history.length == 0 }>%i18n:common.tags.mk-messaging.no-history%</p> - <p class="fetching" if={ fetching }>%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p> - <style> - :scope - display block - - &[data-compact] - font-size 0.8em - - > .history - > a - &:last-child - border-bottom none - - &:not([data-is-me]):not([data-is-read]) - > div - background-image none - border-left solid 4px #3aa2dc - - > div - padding 16px - - > header - > mk-time - font-size 1em - - > .avatar - width 42px - height 42px - margin 0 12px 0 0 - - > .search - display block - position -webkit-sticky - position sticky - top 0 - left 0 - z-index 1 - width 100% - background #fff - box-shadow 0 0px 2px rgba(0, 0, 0, 0.2) - - > .form - padding 8px - background #f7f7f7 - - > label - display block - position absolute - top 0 - left 8px - z-index 1 - height 100% - width 38px - pointer-events none - - > [data-fa] - display block - position absolute - top 0 - right 0 - bottom 0 - left 0 - width 1em - height 1em - margin auto - color #555 - - > input - margin 0 - padding 0 0 0 38px - width 100% - font-size 1em - line-height 38px - color #000 - outline none - border solid 1px #eee - border-radius 5px - box-shadow none - transition color 0.5s ease, border 0.5s ease - - &:hover - border solid 1px #ddd - transition border 0.2s ease - - &:focus - color darken($theme-color, 20%) - border solid 1px $theme-color - transition color 0, border 0 - - > .result - display block - top 0 - left 0 - z-index 2 - width 100% - margin 0 - padding 0 - background #fff - - > .users - margin 0 - padding 0 - list-style none - - > li - display inline-block - z-index 1 - width 100% - padding 8px 32px - vertical-align top - white-space nowrap - overflow hidden - color rgba(0, 0, 0, 0.8) - text-decoration none - transition none - cursor pointer - - &:hover - &:focus - color #fff - background $theme-color - - .name - color #fff - - .username - color #fff - - &:active - color #fff - background darken($theme-color, 10%) - - .name - color #fff - - .username - color #fff - - .avatar - vertical-align middle - min-width 32px - min-height 32px - max-width 32px - max-height 32px - margin 0 8px 0 0 - border-radius 6px - - .name - margin 0 8px 0 0 - /*font-weight bold*/ - font-weight normal - color rgba(0, 0, 0, 0.8) - - .username - font-weight normal - color rgba(0, 0, 0, 0.3) - - > .history - - > a - display block - text-decoration none - background #fff - border-bottom solid 1px #eee - - * - pointer-events none - user-select none - - &:hover - background #fafafa - - > .avatar - filter saturate(200%) - - &:active - background #eee - - &[data-is-read] - &[data-is-me] - opacity 0.8 - - &:not([data-is-me]):not([data-is-read]) - > div - background-image url("/assets/unread.svg") - background-repeat no-repeat - background-position 0 center - - &:after - content "" - display block - clear both - - > div - max-width 500px - margin 0 auto - padding 20px 30px - - &:after - content "" - display block - clear both - - > header - margin-bottom 2px - white-space nowrap - overflow hidden - - > .name - text-align left - display inline - margin 0 - padding 0 - font-size 1em - color rgba(0, 0, 0, 0.9) - font-weight bold - transition all 0.1s ease - - > .username - text-align left - margin 0 0 0 8px - color rgba(0, 0, 0, 0.5) - - > mk-time - position absolute - top 0 - right 0 - display inline - color rgba(0, 0, 0, 0.5) - font-size 80% - - > .avatar - float left - width 54px - height 54px - margin 0 16px 0 0 - border-radius 8px - transition all 0.1s ease - - > .body - - > .text - display block - margin 0 0 0 0 - padding 0 - overflow hidden - overflow-wrap break-word - font-size 1.1em - color rgba(0, 0, 0, 0.8) - - .me - color rgba(0, 0, 0, 0.4) - - > .image - display block - max-width 100% - max-height 512px - - > .no-history - margin 0 - padding 2em 1em - text-align center - color #999 - font-weight 500 - - > .fetching - margin 0 - padding 16px - text-align center - color #aaa - - > [data-fa] - margin-right 4px - - // TODO: element base media query - @media (max-width 400px) - > .search - > .result - > .users - > li - padding 8px 16px - - > .history - > a - &:not([data-is-me]):not([data-is-read]) - > div - background-image none - border-left solid 4px #3aa2dc - - > div - padding 16px - font-size 14px - - > .avatar - margin 0 12px 0 0 - - </style> - <script> - this.mixin('i'); - this.mixin('api'); - - this.mixin('messaging-index-stream'); - this.connection = this.messagingIndexStream.getConnection(); - this.connectionId = this.messagingIndexStream.use(); - - this.searchResult = []; - this.history = []; - this.fetching = true; - - this.registerMessage = message => { - message.is_me = message.user_id == this.I.id; - message._click = () => { - this.trigger('navigate-user', message.is_me ? message.recipient : message.user); - }; - }; - - this.on('mount', () => { - this.connection.on('message', this.onMessage); - this.connection.on('read', this.onRead); - - this.api('messaging/history').then(history => { - this.fetching = false; - history.forEach(message => { - this.registerMessage(message); - }); - this.history = history; - this.update(); - }); - }); - - this.on('unmount', () => { - this.connection.off('message', this.onMessage); - this.connection.off('read', this.onRead); - this.messagingIndexStream.dispose(this.connectionId); - }); - - this.onMessage = message => { - this.history = this.history.filter(m => !( - (m.recipient_id == message.recipient_id && m.user_id == message.user_id) || - (m.recipient_id == message.user_id && m.user_id == message.recipient_id))); - - this.registerMessage(message); - - this.history.unshift(message); - this.update(); - }; - - this.onRead = ids => { - ids.forEach(id => { - const found = this.history.find(m => m.id == id); - if (found) found.is_read = true; - }); - - this.update(); - }; - - this.search = () => { - const q = this.refs.search.value; - if (q == '') { - this.searchResult = []; - return; - } - this.api('users/search', { - query: q, - max: 5 - }).then(users => { - users.forEach(user => { - user._click = () => { - this.trigger('navigate-user', user); - this.searchResult = []; - }; - }); - this.update({ - searchResult: users - }); - }); - }; - - this.onSearchKeydown = e => { - switch (e.which) { - case 9: // [TAB] - case 40: // [↓] - e.preventDefault(); - e.stopPropagation(); - this.refs.searchResult.childNodes[0].focus(); - break; - } - }; - - this.onSearchResultKeydown = (i, e) => { - const cancel = () => { - e.preventDefault(); - e.stopPropagation(); - }; - switch (true) { - case e.which == 10: // [ENTER] - case e.which == 13: // [ENTER] - cancel(); - this.searchResult[i]._click(); - break; - - case e.which == 27: // [ESC] - cancel(); - this.refs.search.focus(); - break; - - case e.which == 9 && e.shiftKey: // [TAB] + [Shift] - case e.which == 38: // [↑] - cancel(); - (this.refs.searchResult.childNodes[i].previousElementSibling || this.refs.searchResult.childNodes[this.searchResult.length - 1]).focus(); - break; - - case e.which == 9: // [TAB] - case e.which == 40: // [↓] - cancel(); - (this.refs.searchResult.childNodes[i].nextElementSibling || this.refs.searchResult.childNodes[0]).focus(); - break; - } - }; - - </script> -</mk-messaging> diff --git a/src/web/app/common/tags/messaging/message.tag b/src/web/app/common/tags/messaging/message.tag deleted file mode 100644 index 354022d7df..0000000000 --- a/src/web/app/common/tags/messaging/message.tag +++ /dev/null @@ -1,238 +0,0 @@ -<mk-messaging-message data-is-me={ message.is_me }> - <a class="avatar-anchor" href={ '/' + message.user.username } title={ message.user.username } target="_blank"> - <img class="avatar" src={ message.user.avatar_url + '?thumbnail&size=80' } alt=""/> - </a> - <div class="content-container"> - <div class="balloon"> - <p class="read" if={ message.is_me && message.is_read }>%i18n:common.tags.mk-messaging-message.is-read%</p> - <button class="delete-button" if={ message.is_me } title="%i18n:common.delete%"><img src="/assets/desktop/messaging/delete.png" alt="Delete"/></button> - <div class="content" if={ !message.is_deleted }> - <div ref="text"></div> - <div class="image" if={ message.file }><img src={ message.file.url } alt="image" title={ message.file.name }/></div> - </div> - <div class="content" if={ message.is_deleted }> - <p class="is-deleted">%i18n:common.tags.mk-messaging-message.deleted%</p> - </div> - </div> - <footer> - <mk-time time={ message.created_at }/><virtual if={ message.is_edited }>%fa:pencil-alt%</virtual> - </footer> - </div> - <style> - :scope - $me-balloon-color = #23A7B6 - - display block - padding 10px 12px 10px 12px - background-color transparent - - &:after - content "" - display block - clear both - - > .avatar-anchor - display block - - > .avatar - display block - min-width 54px - min-height 54px - max-width 54px - max-height 54px - margin 0 - border-radius 8px - transition all 0.1s ease - - > .content-container - display block - margin 0 12px - padding 0 - max-width calc(100% - 78px) - - > .balloon - display block - float inherit - margin 0 - padding 0 - max-width 100% - min-height 38px - border-radius 16px - - &:before - content "" - pointer-events none - display block - position absolute - top 12px - - &:hover - > .delete-button - display block - - > .delete-button - display none - position absolute - z-index 1 - top -4px - right -4px - margin 0 - padding 0 - cursor pointer - outline none - border none - border-radius 0 - box-shadow none - background transparent - - > img - vertical-align bottom - width 16px - height 16px - cursor pointer - - > .read - user-select none - display block - position absolute - z-index 1 - bottom -4px - left -12px - margin 0 - color rgba(0, 0, 0, 0.5) - font-size 11px - - > .content - - > .is-deleted - display block - margin 0 - padding 0 - overflow hidden - overflow-wrap break-word - font-size 1em - color rgba(0, 0, 0, 0.5) - - > [ref='text'] - display block - margin 0 - padding 8px 16px - overflow hidden - overflow-wrap break-word - font-size 1em - color rgba(0, 0, 0, 0.8) - - &, * - user-select text - cursor auto - - & + .file - &.image - > img - border-radius 0 0 16px 16px - - > .file - &.image - > img - display block - max-width 100% - max-height 512px - border-radius 16px - - > footer - display block - clear both - margin 0 - padding 2px - font-size 10px - color rgba(0, 0, 0, 0.4) - - > [data-fa] - margin-left 4px - - &:not([data-is-me='true']) - > .avatar-anchor - float left - - > .content-container - float left - - > .balloon - background #eee - - &:before - left -14px - border-top solid 8px transparent - border-right solid 8px #eee - border-bottom solid 8px transparent - border-left solid 8px transparent - - > footer - text-align left - - &[data-is-me='true'] - > .avatar-anchor - float right - - > .content-container - float right - - > .balloon - background $me-balloon-color - - &:before - right -14px - left auto - border-top solid 8px transparent - border-right solid 8px transparent - border-bottom solid 8px transparent - border-left solid 8px $me-balloon-color - - > .content - - > p.is-deleted - color rgba(255, 255, 255, 0.5) - - > [ref='text'] - &, * - color #fff !important - - > footer - text-align right - - &[data-is-deleted='true'] - > .content-container - opacity 0.5 - - </style> - <script> - import compile from '../../../common/scripts/text-compiler'; - - this.mixin('i'); - - this.message = this.opts.message; - this.message.is_me = this.message.user.id == this.I.id; - - this.on('mount', () => { - if (this.message.text) { - const tokens = this.message.ast; - - this.refs.text.innerHTML = compile(tokens); - - Array.from(this.refs.text.children).forEach(e => { - if (e.tagName == 'MK-URL') riot.mount(e); - }); - - // URLをプレビュー - tokens - .filter(t => t.type == 'link') - .map(t => { - const el = this.refs.text.appendChild(document.createElement('mk-url-preview')); - riot.mount(el, { - url: t.content - }); - }); - } - }); - </script> -</mk-messaging-message> diff --git a/src/web/app/common/tags/messaging/room.tag b/src/web/app/common/tags/messaging/room.tag deleted file mode 100644 index a149e1de22..0000000000 --- a/src/web/app/common/tags/messaging/room.tag +++ /dev/null @@ -1,319 +0,0 @@ -<mk-messaging-room> - <div class="stream"> - <p class="init" if={ init }>%fa:spinner .spin%%i18n:common.loading%</p> - <p class="empty" if={ !init && messages.length == 0 }>%fa:info-circle%%i18n:common.tags.mk-messaging-room.empty%</p> - <p class="no-history" if={ !init && messages.length > 0 && !moreMessagesIsInStock }>%fa:flag%%i18n:common.tags.mk-messaging-room.no-history%</p> - <button class="more { fetching: fetchingMoreMessages }" if={ moreMessagesIsInStock } onclick={ fetchMoreMessages } disabled={ fetchingMoreMessages }> - <virtual if={ fetchingMoreMessages }>%fa:spinner .pulse .fw%</virtual>{ fetchingMoreMessages ? '%i18n:common.loading%' : '%i18n:common.tags.mk-messaging-room.more%' } - </button> - <virtual each={ message, i in messages }> - <mk-messaging-message message={ message }/> - <p class="date" if={ i != messages.length - 1 && message._date != messages[i + 1]._date }><span>{ messages[i + 1]._datetext }</span></p> - </virtual> - </div> - <footer> - <div ref="notifications"></div> - <div class="grippie" title="%i18n:common.tags.mk-messaging-room.resize-form%"></div> - <mk-messaging-form user={ user }/> - </footer> - <style> - :scope - display block - - > .stream - max-width 600px - margin 0 auto - - > .init - width 100% - margin 0 - padding 16px 8px 8px 8px - text-align center - font-size 0.8em - color rgba(0, 0, 0, 0.4) - - [data-fa] - margin-right 4px - - > .empty - width 100% - margin 0 - padding 16px 8px 8px 8px - text-align center - font-size 0.8em - color rgba(0, 0, 0, 0.4) - - [data-fa] - margin-right 4px - - > .no-history - display block - margin 0 - padding 16px - text-align center - font-size 0.8em - color rgba(0, 0, 0, 0.4) - - [data-fa] - margin-right 4px - - > .more - display block - margin 16px auto - padding 0 12px - line-height 24px - color #fff - background rgba(0, 0, 0, 0.3) - border-radius 12px - - &:hover - background rgba(0, 0, 0, 0.4) - - &:active - background rgba(0, 0, 0, 0.5) - - &.fetching - cursor wait - - > [data-fa] - margin-right 4px - - > .message - // something - - > .date - display block - margin 8px 0 - text-align center - - &:before - content '' - display block - position absolute - height 1px - width 90% - top 16px - left 0 - right 0 - margin 0 auto - background rgba(0, 0, 0, 0.1) - - > span - display inline-block - margin 0 - padding 0 16px - //font-weight bold - line-height 32px - color rgba(0, 0, 0, 0.3) - background #fff - - > footer - position -webkit-sticky - position sticky - z-index 2 - bottom 0 - width 100% - max-width 600px - margin 0 auto - padding 0 - background rgba(255, 255, 255, 0.95) - background-clip content-box - - > [ref='notifications'] - position absolute - top -48px - width 100% - padding 8px 0 - text-align center - - &:empty - display none - - > p - display inline-block - margin 0 - padding 0 12px 0 28px - cursor pointer - line-height 32px - font-size 12px - color $theme-color-foreground - background $theme-color - border-radius 16px - transition opacity 1s ease - - > [data-fa] - position absolute - top 0 - left 10px - line-height 32px - font-size 16px - - > .grippie - height 10px - margin-top -10px - background transparent - cursor ns-resize - - &:hover - //background rgba(0, 0, 0, 0.1) - - &:active - //background rgba(0, 0, 0, 0.2) - - </style> - <script> - import MessagingStreamConnection from '../../scripts/streaming/messaging-stream'; - - this.mixin('i'); - this.mixin('api'); - - this.user = this.opts.user; - this.init = true; - this.sending = false; - this.messages = []; - this.isNaked = this.opts.isNaked; - - this.connection = new MessagingStreamConnection(this.I, this.user.id); - - this.on('mount', () => { - this.connection.on('message', this.onMessage); - this.connection.on('read', this.onRead); - - document.addEventListener('visibilitychange', this.onVisibilitychange); - - this.fetchMessages().then(() => { - this.init = false; - this.update(); - this.scrollToBottom(); - }); - }); - - this.on('unmount', () => { - this.connection.off('message', this.onMessage); - this.connection.off('read', this.onRead); - this.connection.close(); - - document.removeEventListener('visibilitychange', this.onVisibilitychange); - }); - - this.on('update', () => { - this.messages.forEach(message => { - const date = (new Date(message.created_at)).getDate(); - const month = (new Date(message.created_at)).getMonth() + 1; - message._date = date; - message._datetext = month + '月 ' + date + '日'; - }); - }); - - this.onMessage = (message) => { - const isBottom = this.isBottom(); - - this.messages.push(message); - if (message.user_id != this.I.id && !document.hidden) { - this.connection.send({ - type: 'read', - id: message.id - }); - } - this.update(); - - if (isBottom) { - // Scroll to bottom - this.scrollToBottom(); - } else if (message.user_id != this.I.id) { - // Notify - this.notify('%i18n:common.tags.mk-messaging-room.new-message%'); - } - }; - - this.onRead = ids => { - if (!Array.isArray(ids)) ids = [ids]; - ids.forEach(id => { - if (this.messages.some(x => x.id == id)) { - const exist = this.messages.map(x => x.id).indexOf(id); - this.messages[exist].is_read = true; - this.update(); - } - }); - }; - - this.fetchMoreMessages = () => { - this.update({ - fetchingMoreMessages: true - }); - this.fetchMessages().then(() => { - this.update({ - fetchingMoreMessages: false - }); - }); - }; - - this.fetchMessages = () => new Promise((resolve, reject) => { - const max = this.moreMessagesIsInStock ? 20 : 10; - - this.api('messaging/messages', { - user_id: this.user.id, - limit: max + 1, - max_id: this.moreMessagesIsInStock ? this.messages[0].id : undefined - }).then(messages => { - if (messages.length == max + 1) { - this.moreMessagesIsInStock = true; - messages.pop(); - } else { - this.moreMessagesIsInStock = false; - } - - this.messages.unshift.apply(this.messages, messages.reverse()); - this.update(); - - resolve(); - }); - }); - - this.isBottom = () => { - const asobi = 32; - const current = this.isNaked - ? window.scrollY + window.innerHeight - : this.root.scrollTop + this.root.offsetHeight; - const max = this.isNaked - ? document.body.offsetHeight - : this.root.scrollHeight; - return current > (max - asobi); - }; - - this.scrollToBottom = () => { - if (this.isNaked) { - window.scroll(0, document.body.offsetHeight); - } else { - this.root.scrollTop = this.root.scrollHeight; - } - }; - - this.notify = message => { - const n = document.createElement('p'); - n.innerHTML = '%fa:arrow-circle-down%' + message; - n.onclick = () => { - this.scrollToBottom(); - n.parentNode.removeChild(n); - }; - this.refs.notifications.appendChild(n); - - setTimeout(() => { - n.style.opacity = 0; - setTimeout(() => n.parentNode.removeChild(n), 1000); - }, 4000); - }; - - this.onVisibilitychange = () => { - if (document.hidden) return; - this.messages.forEach(message => { - if (message.user_id !== this.I.id && !message.is_read) { - this.connection.send({ - type: 'read', - id: message.id - }); - } - }); - }; - </script> -</mk-messaging-room> diff --git a/src/web/app/common/tags/nav-links.tag b/src/web/app/common/tags/nav-links.tag deleted file mode 100644 index 71f0453db0..0000000000 --- a/src/web/app/common/tags/nav-links.tag +++ /dev/null @@ -1,7 +0,0 @@ -<mk-nav-links> - <a href={ _ABOUT_URL_ }>%i18n:common.tags.mk-nav-links.about%</a><i>・</i><a href={ _STATS_URL_ }>%i18n:common.tags.mk-nav-links.stats%</a><i>・</i><a href={ _STATUS_URL_ }>%i18n:common.tags.mk-nav-links.status%</a><i>・</i><a href="http://zawazawa.jp/misskey/">%i18n:common.tags.mk-nav-links.wiki%</a><i>・</i><a href="https://github.com/syuilo/misskey/blob/master/DONORS.md">%i18n:common.tags.mk-nav-links.donors%</a><i>・</i><a href="https://github.com/syuilo/misskey">%i18n:common.tags.mk-nav-links.repository%</a><i>・</i><a href={ _DEV_URL_ }>%i18n:common.tags.mk-nav-links.develop%</a><i>・</i><a href="https://twitter.com/misskey_xyz" target="_blank">Follow us on %fa:B twitter%</a> - <style> - :scope - display inline - </style> -</mk-nav-links> diff --git a/src/web/app/common/tags/number.tag b/src/web/app/common/tags/number.tag deleted file mode 100644 index 7afb8b3983..0000000000 --- a/src/web/app/common/tags/number.tag +++ /dev/null @@ -1,16 +0,0 @@ -<mk-number> - <style> - :scope - display inline - </style> - <script> - this.on('mount', () => { - let value = this.opts.value; - const max = this.opts.max; - - if (max != null && value > max) value = max; - - this.root.innerHTML = value.toLocaleString(); - }); - </script> -</mk-number> diff --git a/src/web/app/common/tags/poll-editor.tag b/src/web/app/common/tags/poll-editor.tag deleted file mode 100644 index e79209e9b4..0000000000 --- a/src/web/app/common/tags/poll-editor.tag +++ /dev/null @@ -1,121 +0,0 @@ -<mk-poll-editor> - <p class="caution" if={ choices.length < 2 }> - %fa:exclamation-triangle%%i18n:common.tags.mk-poll-editor.no-only-one-choice% - </p> - <ul ref="choices"> - <li each={ choice, i in choices }> - <input value={ choice } oninput={ oninput.bind(null, i) } placeholder={ '%i18n:common.tags.mk-poll-editor.choice-n%'.replace('{}', i + 1) }> - <button onclick={ remove.bind(null, i) } title="%i18n:common.tags.mk-poll-editor.remove%"> - %fa:times% - </button> - </li> - </ul> - <button class="add" if={ choices.length < 10 } onclick={ add }>%i18n:common.tags.mk-poll-editor.add%</button> - <button class="destroy" onclick={ destroy } title="%i18n:common.tags.mk-poll-editor.destroy%"> - %fa:times% - </button> - <style> - :scope - display block - padding 8px - - > .caution - margin 0 0 8px 0 - font-size 0.8em - color #f00 - - > [data-fa] - margin-right 4px - - > ul - display block - margin 0 - padding 0 - list-style none - - > li - display block - margin 8px 0 - padding 0 - width 100% - - &:first-child - margin-top 0 - - &:last-child - margin-bottom 0 - - > input - padding 6px - border solid 1px rgba($theme-color, 0.1) - border-radius 4px - - &:hover - border-color rgba($theme-color, 0.2) - - &:focus - border-color rgba($theme-color, 0.5) - - > button - padding 4px 8px - color rgba($theme-color, 0.4) - - &:hover - color rgba($theme-color, 0.6) - - &:active - color darken($theme-color, 30%) - - > .add - margin 8px 0 0 0 - vertical-align top - color $theme-color - - > .destroy - position absolute - top 0 - right 0 - padding 4px 8px - color rgba($theme-color, 0.4) - - &:hover - color rgba($theme-color, 0.6) - - &:active - color darken($theme-color, 30%) - - </style> - <script> - this.choices = ['', '']; - - this.oninput = (i, e) => { - this.choices[i] = e.target.value; - }; - - this.add = () => { - this.choices.push(''); - this.update(); - this.refs.choices.childNodes[this.choices.length - 1].childNodes[0].focus(); - }; - - this.remove = (i) => { - this.choices = this.choices.filter((_, _i) => _i != i); - this.update(); - }; - - this.destroy = () => { - this.opts.ondestroy(); - }; - - this.get = () => { - return { - choices: this.choices.filter(choice => choice != '') - } - }; - - this.set = data => { - if (data.choices.length == 0) return; - this.choices = data.choices; - }; - </script> -</mk-poll-editor> diff --git a/src/web/app/common/tags/poll.tag b/src/web/app/common/tags/poll.tag deleted file mode 100644 index 32542418aa..0000000000 --- a/src/web/app/common/tags/poll.tag +++ /dev/null @@ -1,109 +0,0 @@ -<mk-poll data-is-voted={ isVoted }> - <ul> - <li each={ poll.choices } onclick={ vote.bind(null, id) } class={ voted: voted } title={ !parent.isVoted ? '%i18n:common.tags.mk-poll.vote-to%'.replace('{}', text) : '' }> - <div class="backdrop" style={ 'width:' + (parent.result ? (votes / parent.total * 100) : 0) + '%' }></div> - <span> - <virtual if={ is_voted }>%fa:check%</virtual> - { text } - <span class="votes" if={ parent.result }>({ '%i18n:common.tags.mk-poll.vote-count%'.replace('{}', votes) })</span> - </span> - </li> - </ul> - <p if={ total > 0 }> - <span>{ '%i18n:common.tags.mk-poll.total-users%'.replace('{}', total) }</span> - ・ - <a if={ !isVoted } onclick={ toggleResult }>{ result ? '%i18n:common.tags.mk-poll.vote%' : '%i18n:common.tags.mk-poll.show-result%' }</a> - <span if={ isVoted }>%i18n:common.tags.mk-poll.voted%</span> - </p> - <style> - :scope - display block - - > ul - display block - margin 0 - padding 0 - list-style none - - > li - display block - margin 4px 0 - padding 4px 8px - width 100% - border solid 1px #eee - border-radius 4px - overflow hidden - cursor pointer - - &:hover - background rgba(0, 0, 0, 0.05) - - &:active - background rgba(0, 0, 0, 0.1) - - > .backdrop - position absolute - top 0 - left 0 - height 100% - background $theme-color - transition width 1s ease - - > .votes - margin-left 4px - - > p - a - color inherit - - &[data-is-voted] - > ul > li - cursor default - - &:hover - background transparent - - &:active - background transparent - - </style> - <script> - this.mixin('api'); - - this.init = post => { - this.post = post; - this.poll = this.post.poll; - this.total = this.poll.choices.reduce((a, b) => a + b.votes, 0); - this.isVoted = this.poll.choices.some(c => c.is_voted); - this.result = this.isVoted; - this.update(); - }; - - this.init(this.opts.post); - - this.toggleResult = () => { - this.result = !this.result; - }; - - this.vote = id => { - if (this.poll.choices.some(c => c.is_voted)) return; - this.api('posts/polls/vote', { - post_id: this.post.id, - choice: id - }).then(() => { - this.poll.choices.forEach(c => { - if (c.id == id) { - c.votes++; - c.is_voted = true; - } - }); - this.update({ - poll: this.poll, - isVoted: true, - result: true, - total: this.total + 1 - }); - }); - }; - </script> -</mk-poll> diff --git a/src/web/app/common/tags/post-menu.tag b/src/web/app/common/tags/post-menu.tag deleted file mode 100644 index be4468a214..0000000000 --- a/src/web/app/common/tags/post-menu.tag +++ /dev/null @@ -1,157 +0,0 @@ -<mk-post-menu> - <div class="backdrop" ref="backdrop" onclick={ close }></div> - <div class="popover { compact: opts.compact }" ref="popover"> - <button if={ post.user_id === I.id } onclick={ pin }>%i18n:common.tags.mk-post-menu.pin%</button> - <div if={ I.is_pro && !post.is_category_verified }> - <select ref="categorySelect"> - <option value="">%i18n:common.tags.mk-post-menu.select%</option> - <option value="music">%i18n:common.post_categories.music%</option> - <option value="game">%i18n:common.post_categories.game%</option> - <option value="anime">%i18n:common.post_categories.anime%</option> - <option value="it">%i18n:common.post_categories.it%</option> - <option value="gadgets">%i18n:common.post_categories.gadgets%</option> - <option value="photography">%i18n:common.post_categories.photography%</option> - </select> - <button onclick={ categorize }>%i18n:common.tags.mk-post-menu.categorize%</button> - </div> - </div> - <style> - $border-color = rgba(27, 31, 35, 0.15) - - :scope - display block - position initial - - > .backdrop - position fixed - top 0 - left 0 - z-index 10000 - width 100% - height 100% - background rgba(0, 0, 0, 0.1) - opacity 0 - - > .popover - position absolute - z-index 10001 - background #fff - border 1px solid $border-color - border-radius 4px - box-shadow 0 3px 12px rgba(27, 31, 35, 0.15) - transform scale(0.5) - opacity 0 - - $balloon-size = 16px - - &:not(.compact) - margin-top $balloon-size - transform-origin center -($balloon-size) - - &:before - content "" - display block - position absolute - top -($balloon-size * 2) - left s('calc(50% - %s)', $balloon-size) - border-top solid $balloon-size transparent - border-left solid $balloon-size transparent - border-right solid $balloon-size transparent - border-bottom solid $balloon-size $border-color - - &:after - content "" - display block - position absolute - top -($balloon-size * 2) + 1.5px - left s('calc(50% - %s)', $balloon-size) - border-top solid $balloon-size transparent - border-left solid $balloon-size transparent - border-right solid $balloon-size transparent - border-bottom solid $balloon-size #fff - - > button - display block - - </style> - <script> - import anime from 'animejs'; - - this.mixin('i'); - this.mixin('api'); - - this.post = this.opts.post; - this.source = this.opts.source; - - this.on('mount', () => { - const rect = this.source.getBoundingClientRect(); - const width = this.refs.popover.offsetWidth; - const height = this.refs.popover.offsetHeight; - if (this.opts.compact) { - const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2); - const y = rect.top + window.pageYOffset + (this.source.offsetHeight / 2); - this.refs.popover.style.left = (x - (width / 2)) + 'px'; - this.refs.popover.style.top = (y - (height / 2)) + 'px'; - } else { - const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2); - const y = rect.top + window.pageYOffset + this.source.offsetHeight; - this.refs.popover.style.left = (x - (width / 2)) + 'px'; - this.refs.popover.style.top = y + 'px'; - } - - anime({ - targets: this.refs.backdrop, - opacity: 1, - duration: 100, - easing: 'linear' - }); - - anime({ - targets: this.refs.popover, - opacity: 1, - scale: [0.5, 1], - duration: 500 - }); - }); - - this.pin = () => { - this.api('i/pin', { - post_id: this.post.id - }).then(() => { - if (this.opts.cb) this.opts.cb('pinned', '%i18n:common.tags.mk-post-menu.pinned%'); - this.unmount(); - }); - }; - - this.categorize = () => { - const category = this.refs.categorySelect.options[this.refs.categorySelect.selectedIndex].value; - this.api('posts/categorize', { - post_id: this.post.id, - category: category - }).then(() => { - if (this.opts.cb) this.opts.cb('categorized', '%i18n:common.tags.mk-post-menu.categorized%'); - this.unmount(); - }); - }; - - this.close = () => { - this.refs.backdrop.style.pointerEvents = 'none'; - anime({ - targets: this.refs.backdrop, - opacity: 0, - duration: 200, - easing: 'linear' - }); - - this.refs.popover.style.pointerEvents = 'none'; - anime({ - targets: this.refs.popover, - opacity: 0, - scale: 0.5, - duration: 200, - easing: 'easeInBack', - complete: () => this.unmount() - }); - }; - </script> -</mk-post-menu> diff --git a/src/web/app/common/tags/raw.tag b/src/web/app/common/tags/raw.tag deleted file mode 100644 index adc6de5a3b..0000000000 --- a/src/web/app/common/tags/raw.tag +++ /dev/null @@ -1,13 +0,0 @@ -<mk-raw> - <style> - :scope - display inline - </style> - <script> - this.root.innerHTML = this.opts.content; - - this.on('updated', () => { - this.root.innerHTML = this.opts.content; - }); - </script> -</mk-raw> diff --git a/src/web/app/common/tags/reaction-icon.tag b/src/web/app/common/tags/reaction-icon.tag deleted file mode 100644 index 0127293917..0000000000 --- a/src/web/app/common/tags/reaction-icon.tag +++ /dev/null @@ -1,21 +0,0 @@ -<mk-reaction-icon> - <virtual if={ opts.reaction == 'like' }><img src="/assets/reactions/like.png" alt="%i18n:common.reactions.like%"></virtual> - <virtual if={ opts.reaction == 'love' }><img src="/assets/reactions/love.png" alt="%i18n:common.reactions.love%"></virtual> - <virtual if={ opts.reaction == 'laugh' }><img src="/assets/reactions/laugh.png" alt="%i18n:common.reactions.laugh%"></virtual> - <virtual if={ opts.reaction == 'hmm' }><img src="/assets/reactions/hmm.png" alt="%i18n:common.reactions.hmm%"></virtual> - <virtual if={ opts.reaction == 'surprise' }><img src="/assets/reactions/surprise.png" alt="%i18n:common.reactions.surprise%"></virtual> - <virtual if={ opts.reaction == 'congrats' }><img src="/assets/reactions/congrats.png" alt="%i18n:common.reactions.congrats%"></virtual> - <virtual if={ opts.reaction == 'angry' }><img src="/assets/reactions/angry.png" alt="%i18n:common.reactions.angry%"></virtual> - <virtual if={ opts.reaction == 'confused' }><img src="/assets/reactions/confused.png" alt="%i18n:common.reactions.confused%"></virtual> - <virtual if={ opts.reaction == 'pudding' }><img src="/assets/reactions/pudding.png" alt="%i18n:common.reactions.pudding%"></virtual> - - <style> - :scope - display inline - - img - vertical-align middle - width 1em - height 1em - </style> -</mk-reaction-icon> diff --git a/src/web/app/common/tags/reaction-picker.tag b/src/web/app/common/tags/reaction-picker.tag deleted file mode 100644 index 458d16ec71..0000000000 --- a/src/web/app/common/tags/reaction-picker.tag +++ /dev/null @@ -1,184 +0,0 @@ -<mk-reaction-picker> - <div class="backdrop" ref="backdrop" onclick={ close }></div> - <div class="popover { compact: opts.compact }" ref="popover"> - <p if={ !opts.compact }>{ title }</p> - <div> - <button onclick={ react.bind(null, 'like') } onmouseover={ onmouseover } onmouseout={ onmouseout } tabindex="1" title="%i18n:common.reactions.like%"><mk-reaction-icon reaction='like'/></button> - <button onclick={ react.bind(null, 'love') } onmouseover={ onmouseover } onmouseout={ onmouseout } tabindex="2" title="%i18n:common.reactions.love%"><mk-reaction-icon reaction='love'/></button> - <button onclick={ react.bind(null, 'laugh') } onmouseover={ onmouseover } onmouseout={ onmouseout } tabindex="3" title="%i18n:common.reactions.laugh%"><mk-reaction-icon reaction='laugh'/></button> - <button onclick={ react.bind(null, 'hmm') } onmouseover={ onmouseover } onmouseout={ onmouseout } tabindex="4" title="%i18n:common.reactions.hmm%"><mk-reaction-icon reaction='hmm'/></button> - <button onclick={ react.bind(null, 'surprise') } onmouseover={ onmouseover } onmouseout={ onmouseout } tabindex="5" title="%i18n:common.reactions.surprise%"><mk-reaction-icon reaction='surprise'/></button> - <button onclick={ react.bind(null, 'congrats') } onmouseover={ onmouseover } onmouseout={ onmouseout } tabindex="6" title="%i18n:common.reactions.congrats%"><mk-reaction-icon reaction='congrats'/></button> - <button onclick={ react.bind(null, 'angry') } onmouseover={ onmouseover } onmouseout={ onmouseout } tabindex="4" title="%i18n:common.reactions.angry%"><mk-reaction-icon reaction='angry'/></button> - <button onclick={ react.bind(null, 'confused') } onmouseover={ onmouseover } onmouseout={ onmouseout } tabindex="5" title="%i18n:common.reactions.confused%"><mk-reaction-icon reaction='confused'/></button> - <button onclick={ react.bind(null, 'pudding') } onmouseover={ onmouseover } onmouseout={ onmouseout } tabindex="6" title="%i18n:common.reactions.pudding%"><mk-reaction-icon reaction='pudding'/></button> - </div> - </div> - <style> - $border-color = rgba(27, 31, 35, 0.15) - - :scope - display block - position initial - - > .backdrop - position fixed - top 0 - left 0 - z-index 10000 - width 100% - height 100% - background rgba(0, 0, 0, 0.1) - opacity 0 - - > .popover - position absolute - z-index 10001 - background #fff - border 1px solid $border-color - border-radius 4px - box-shadow 0 3px 12px rgba(27, 31, 35, 0.15) - transform scale(0.5) - opacity 0 - - $balloon-size = 16px - - &:not(.compact) - margin-top $balloon-size - transform-origin center -($balloon-size) - - &:before - content "" - display block - position absolute - top -($balloon-size * 2) - left s('calc(50% - %s)', $balloon-size) - border-top solid $balloon-size transparent - border-left solid $balloon-size transparent - border-right solid $balloon-size transparent - border-bottom solid $balloon-size $border-color - - &:after - content "" - display block - position absolute - top -($balloon-size * 2) + 1.5px - left s('calc(50% - %s)', $balloon-size) - border-top solid $balloon-size transparent - border-left solid $balloon-size transparent - border-right solid $balloon-size transparent - border-bottom solid $balloon-size #fff - - > p - display block - margin 0 - padding 8px 10px - font-size 14px - color #586069 - border-bottom solid 1px #e1e4e8 - - > div - padding 4px - width 240px - text-align center - - > button - width 40px - height 40px - font-size 24px - border-radius 2px - - &:hover - background #eee - - &:active - background $theme-color - box-shadow inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15) - - </style> - <script> - import anime from 'animejs'; - - this.mixin('api'); - - this.post = this.opts.post; - this.source = this.opts.source; - - const placeholder = '%i18n:common.tags.mk-reaction-picker.choose-reaction%'; - - this.title = placeholder; - - this.onmouseover = e => { - this.update({ - title: e.target.title - }); - }; - - this.onmouseout = () => { - this.update({ - title: placeholder - }); - }; - - this.on('mount', () => { - const rect = this.source.getBoundingClientRect(); - const width = this.refs.popover.offsetWidth; - const height = this.refs.popover.offsetHeight; - if (this.opts.compact) { - const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2); - const y = rect.top + window.pageYOffset + (this.source.offsetHeight / 2); - this.refs.popover.style.left = (x - (width / 2)) + 'px'; - this.refs.popover.style.top = (y - (height / 2)) + 'px'; - } else { - const x = rect.left + window.pageXOffset + (this.source.offsetWidth / 2); - const y = rect.top + window.pageYOffset + this.source.offsetHeight; - this.refs.popover.style.left = (x - (width / 2)) + 'px'; - this.refs.popover.style.top = y + 'px'; - } - - anime({ - targets: this.refs.backdrop, - opacity: 1, - duration: 100, - easing: 'linear' - }); - - anime({ - targets: this.refs.popover, - opacity: 1, - scale: [0.5, 1], - duration: 500 - }); - }); - - this.react = reaction => { - this.api('posts/reactions/create', { - post_id: this.post.id, - reaction: reaction - }).then(() => { - if (this.opts.cb) this.opts.cb(); - this.unmount(); - }); - }; - - this.close = () => { - this.refs.backdrop.style.pointerEvents = 'none'; - anime({ - targets: this.refs.backdrop, - opacity: 0, - duration: 200, - easing: 'linear' - }); - - this.refs.popover.style.pointerEvents = 'none'; - anime({ - targets: this.refs.popover, - opacity: 0, - scale: 0.5, - duration: 200, - easing: 'easeInBack', - complete: () => this.unmount() - }); - }; - </script> -</mk-reaction-picker> diff --git a/src/web/app/common/tags/reactions-viewer.tag b/src/web/app/common/tags/reactions-viewer.tag deleted file mode 100644 index 50fb023f70..0000000000 --- a/src/web/app/common/tags/reactions-viewer.tag +++ /dev/null @@ -1,46 +0,0 @@ -<mk-reactions-viewer> - <virtual if={ reactions }> - <span if={ reactions.like }><mk-reaction-icon reaction='like'/><span>{ reactions.like }</span></span> - <span if={ reactions.love }><mk-reaction-icon reaction='love'/><span>{ reactions.love }</span></span> - <span if={ reactions.laugh }><mk-reaction-icon reaction='laugh'/><span>{ reactions.laugh }</span></span> - <span if={ reactions.hmm }><mk-reaction-icon reaction='hmm'/><span>{ reactions.hmm }</span></span> - <span if={ reactions.surprise }><mk-reaction-icon reaction='surprise'/><span>{ reactions.surprise }</span></span> - <span if={ reactions.congrats }><mk-reaction-icon reaction='congrats'/><span>{ reactions.congrats }</span></span> - <span if={ reactions.angry }><mk-reaction-icon reaction='angry'/><span>{ reactions.angry }</span></span> - <span if={ reactions.confused }><mk-reaction-icon reaction='confused'/><span>{ reactions.confused }</span></span> - <span if={ reactions.pudding }><mk-reaction-icon reaction='pudding'/><span>{ reactions.pudding }</span></span> - </virtual> - <style> - :scope - display block - border-top dashed 1px #eee - border-bottom dashed 1px #eee - margin 4px 0 - - &:empty - display none - - > span - margin-right 8px - - > mk-reaction-icon - font-size 1.4em - - > span - margin-left 4px - font-size 1.2em - color #444 - - </style> - <script> - this.post = this.opts.post; - - this.on('mount', () => { - this.update(); - }); - - this.on('update', () => { - this.reactions = this.post.reaction_counts; - }); - </script> -</mk-reactions-viewer> diff --git a/src/web/app/common/tags/signin-history.tag b/src/web/app/common/tags/signin-history.tag deleted file mode 100644 index cdd58c4c67..0000000000 --- a/src/web/app/common/tags/signin-history.tag +++ /dev/null @@ -1,116 +0,0 @@ -<mk-signin-history> - <div class="records" if={ history.length != 0 }> - <mk-signin-record each={ rec in history } rec={ rec }/> - </div> - <style> - :scope - display block - - </style> - <script> - this.mixin('i'); - this.mixin('api'); - - this.mixin('stream'); - this.connection = this.stream.getConnection(); - this.connectionId = this.stream.use(); - - this.history = []; - this.fetching = true; - - this.on('mount', () => { - this.api('i/signin_history').then(history => { - this.update({ - fetching: false, - history: history - }); - }); - - this.connection.on('signin', this.onSignin); - }); - - this.on('unmount', () => { - this.connection.off('signin', this.onSignin); - this.stream.dispose(this.connectionId); - }); - - this.onSignin = signin => { - this.history.unshift(signin); - this.update(); - }; - </script> -</mk-signin-history> - -<mk-signin-record> - <header onclick={ toggle }> - <virtual if={ rec.success }>%fa:check%</virtual> - <virtual if={ !rec.success }>%fa:times%</virtual> - <span class="ip">{ rec.ip }</span> - <mk-time time={ rec.created_at }/> - </header> - <pre ref="headers" class="json" show={ show }>{ JSON.stringify(rec.headers, null, 2) }</pre> - - <style> - :scope - display block - border-bottom solid 1px #eee - - > header - display flex - padding 8px 0 - line-height 32px - cursor pointer - - > [data-fa] - margin-right 8px - text-align left - - &.check - color #0fda82 - - &.times - color #ff3100 - - > .ip - display inline-block - text-align left - padding 8px - line-height 16px - font-family monospace - font-size 14px - color #444 - background #f8f8f8 - border-radius 4px - - > mk-time - margin-left auto - text-align right - color #777 - - > pre - overflow auto - margin 0 0 16px 0 - max-height 100px - white-space pre-wrap - word-break break-all - color #4a535a - - </style> - - <script> - import hljs from 'highlight.js'; - - this.rec = this.opts.rec; - this.show = false; - - this.on('mount', () => { - hljs.highlightBlock(this.refs.headers); - }); - - this.toggle = () => { - this.update({ - show: !this.show - }); - }; - </script> -</mk-signin-record> diff --git a/src/web/app/common/tags/signin.tag b/src/web/app/common/tags/signin.tag deleted file mode 100644 index f5a2be94ed..0000000000 --- a/src/web/app/common/tags/signin.tag +++ /dev/null @@ -1,155 +0,0 @@ -<mk-signin> - <form class={ signing: signing } onsubmit={ onsubmit }> - <label class="user-name"> - <input ref="username" type="text" pattern="^[a-zA-Z0-9-]+$" placeholder="%i18n:common.tags.mk-signin.username%" autofocus="autofocus" required="required" oninput={ oninput }/>%fa:at% - </label> - <label class="password"> - <input ref="password" type="password" placeholder="%i18n:common.tags.mk-signin.password%" required="required"/>%fa:lock% - </label> - <label class="token" if={ user && user.two_factor_enabled }> - <input ref="token" type="number" placeholder="%i18n:common.tags.mk-signin.token%" required="required"/>%fa:lock% - </label> - <button type="submit" disabled={ signing }>{ signing ? '%i18n:common.tags.mk-signin.signing-in%' : '%i18n:common.tags.mk-signin.signin%' }</button> - </form> - <style> - :scope - display block - - > form - display block - z-index 2 - - &.signing - &, * - cursor wait !important - - label - display block - margin 12px 0 - - [data-fa] - display block - pointer-events none - position absolute - bottom 0 - top 0 - left 0 - z-index 1 - margin auto - padding 0 16px - height 1em - color #898786 - - input[type=text] - input[type=password] - input[type=number] - user-select text - display inline-block - cursor auto - padding 0 0 0 38px - margin 0 - width 100% - line-height 44px - font-size 1em - color rgba(0, 0, 0, 0.7) - background #fff - outline none - border solid 1px #eee - border-radius 4px - - &:hover - background rgba(255, 255, 255, 0.7) - border-color #ddd - - & + i - color #797776 - - &:focus - background #fff - border-color #ccc - - & + i - color #797776 - - [type=submit] - cursor pointer - padding 16px - margin -6px 0 0 0 - width 100% - font-size 1.2em - color rgba(0, 0, 0, 0.5) - outline none - border none - border-radius 0 - background transparent - transition all .5s ease - - &:hover - color $theme-color - transition all .2s ease - - &:focus - color $theme-color - transition all .2s ease - - &:active - color darken($theme-color, 30%) - transition all .2s ease - - &:disabled - opacity 0.7 - - </style> - <script> - this.mixin('api'); - - this.user = null; - this.signing = false; - - this.oninput = () => { - this.api('users/show', { - username: this.refs.username.value - }).then(user => { - this.user = user; - this.trigger('user', user); - this.update(); - }); - }; - - this.onsubmit = e => { - e.preventDefault(); - - if (this.refs.username.value == '') { - this.refs.username.focus(); - return false; - } - if (this.refs.password.value == '') { - this.refs.password.focus(); - return false; - } - if (this.user && this.user.two_factor_enabled && this.refs.token.value == '') { - this.refs.token.focus(); - return false; - } - - this.update({ - signing: true - }); - - this.api('signin', { - username: this.refs.username.value, - password: this.refs.password.value, - token: this.user && this.user.two_factor_enabled ? this.refs.token.value : undefined - }).then(() => { - location.reload(); - }).catch(() => { - alert('something happened'); - this.update({ - signing: false - }); - }); - - return false; - }; - </script> -</mk-signin> diff --git a/src/web/app/common/tags/signup.tag b/src/web/app/common/tags/signup.tag deleted file mode 100644 index 4816fe66db..0000000000 --- a/src/web/app/common/tags/signup.tag +++ /dev/null @@ -1,305 +0,0 @@ -<mk-signup> - <form onsubmit={ onsubmit } autocomplete="off"> - <label class="username"> - <p class="caption">%fa:at%%i18n:common.tags.mk-signup.username%</p> - <input ref="username" type="text" pattern="^[a-zA-Z0-9-]{3,20}$" placeholder="a~z、A~Z、0~9、-" autocomplete="off" required="required" onkeyup={ onChangeUsername }/> - <p class="profile-page-url-preview" if={ refs.username.value != '' && username-state != 'invalidFormat' && username-state != 'minRange' && username-state != 'maxRange' }>{ _URL_ + '/' + refs.username.value }</p> - <p class="info" if={ usernameState == 'wait' } style="color:#999">%fa:spinner .pulse .fw%%i18n:common.tags.mk-signup.checking%</p> - <p class="info" if={ usernameState == 'ok' } style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.available%</p> - <p class="info" if={ usernameState == 'unavailable' } style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.unavailable%</p> - <p class="info" if={ usernameState == 'error' } style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.error%</p> - <p class="info" if={ usernameState == 'invalid-format' } style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.invalid-format%</p> - <p class="info" if={ usernameState == 'min-range' } style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.too-short%</p> - <p class="info" if={ usernameState == 'max-range' } style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.too-long%</p> - </label> - <label class="password"> - <p class="caption">%fa:lock%%i18n:common.tags.mk-signup.password%</p> - <input ref="password" type="password" placeholder="%i18n:common.tags.mk-signup.password-placeholder%" autocomplete="off" required="required" onkeyup={ onChangePassword }/> - <div class="meter" if={ passwordStrength != '' } data-strength={ passwordStrength }> - <div class="value" ref="passwordMetar"></div> - </div> - <p class="info" if={ passwordStrength == 'low' } style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.weak-password%</p> - <p class="info" if={ passwordStrength == 'medium' } style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.normal-password%</p> - <p class="info" if={ passwordStrength == 'high' } style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.strong-password%</p> - </label> - <label class="retype-password"> - <p class="caption">%fa:lock%%i18n:common.tags.mk-signup.password%(%i18n:common.tags.mk-signup.retype%)</p> - <input ref="passwordRetype" type="password" placeholder="%i18n:common.tags.mk-signup.retype-placeholder%" autocomplete="off" required="required" onkeyup={ onChangePasswordRetype }/> - <p class="info" if={ passwordRetypeState == 'match' } style="color:#3CB7B5">%fa:check .fw%%i18n:common.tags.mk-signup.password-matched%</p> - <p class="info" if={ passwordRetypeState == 'not-match' } style="color:#FF1161">%fa:exclamation-triangle .fw%%i18n:common.tags.mk-signup.password-not-matched%</p> - </label> - <label class="recaptcha"> - <p class="caption"><virtual if={ recaptchaed }>%fa:toggle-on%</virtual><virtual if={ !recaptchaed }>%fa:toggle-off%</virtual>%i18n:common.tags.mk-signup.recaptcha%</p> - <div if={ recaptcha } class="g-recaptcha" data-callback="onRecaptchaed" data-expired-callback="onRecaptchaExpired" data-sitekey={ recaptcha.site_key }></div> - </label> - <label class="agree-tou"> - <input name="agree-tou" type="checkbox" autocomplete="off" required="required"/> - <p><a href="https://github.com/syuilo/misskey/blob/master/src/docs/tou.md" target="_blank">利用規約</a>に同意する</p> - </label> - <button onclick={ onsubmit }>%i18n:common.tags.mk-signup.create%</button> - </form> - <style> - :scope - display block - min-width 302px - overflow hidden - - > form - - label - display block - margin 16px 0 - - > .caption - margin 0 0 4px 0 - color #828888 - font-size 0.95em - - > [data-fa] - margin-right 0.25em - color #96adac - - > .info - display block - margin 4px 0 - font-size 0.8em - - > [data-fa] - margin-right 0.3em - - &.username - .profile-page-url-preview - display block - margin 4px 8px 0 4px - font-size 0.8em - color #888 - - &:empty - display none - - &:not(:empty) + .info - margin-top 0 - - &.password - .meter - display block - margin-top 8px - width 100% - height 8px - - &[data-strength=''] - display none - - &[data-strength='low'] - > .value - background #d73612 - - &[data-strength='medium'] - > .value - background #d7ca12 - - &[data-strength='high'] - > .value - background #61bb22 - - > .value - display block - width 0% - height 100% - background transparent - border-radius 4px - transition all 0.1s ease - - [type=text], [type=password] - user-select text - display inline-block - cursor auto - padding 0 12px - margin 0 - width 100% - line-height 44px - font-size 1em - color #333 !important - background #fff !important - outline none - border solid 1px rgba(0, 0, 0, 0.1) - border-radius 4px - box-shadow 0 0 0 114514px #fff inset - transition all .3s ease - - &:hover - border-color rgba(0, 0, 0, 0.2) - transition all .1s ease - - &:focus - color $theme-color !important - border-color $theme-color - box-shadow 0 0 0 1024px #fff inset, 0 0 0 4px rgba($theme-color, 10%) - transition all 0s ease - - &:disabled - opacity 0.5 - - .agree-tou - padding 4px - border-radius 4px - - &:hover - background #f4f4f4 - - &:active - background #eee - - &, * - cursor pointer - - p - display inline - color #555 - - button - margin 0 0 32px 0 - padding 16px - width 100% - font-size 1em - color #fff - background $theme-color - border-radius 3px - - &:hover - background lighten($theme-color, 5%) - - &:active - background darken($theme-color, 5%) - - </style> - <script> - this.mixin('api'); - const getPasswordStrength = require('syuilo-password-strength'); - - this.usernameState = null; - this.passwordStrength = ''; - this.passwordRetypeState = null; - this.recaptchaed = false; - - window.onRecaptchaed = () => { - this.recaptchaed = true; - this.update(); - }; - - window.onRecaptchaExpired = () => { - this.recaptchaed = false; - this.update(); - }; - - this.on('mount', () => { - this.update({ - recaptcha: { - site_key: _RECAPTCHA_SITEKEY_ - } - }); - - const head = document.getElementsByTagName('head')[0]; - const script = document.createElement('script'); - script.setAttribute('src', 'https://www.google.com/recaptcha/api.js'); - head.appendChild(script); - }); - - this.onChangeUsername = () => { - const username = this.refs.username.value; - - if (username == '') { - this.update({ - usernameState: null - }); - return; - } - - const err = - !username.match(/^[a-zA-Z0-9\-]+$/) ? 'invalid-format' : - username.length < 3 ? 'min-range' : - username.length > 20 ? 'max-range' : - null; - - if (err) { - this.update({ - usernameState: err - }); - return; - } - - this.update({ - usernameState: 'wait' - }); - - this.api('username/available', { - username: username - }).then(result => { - this.update({ - usernameState: result.available ? 'ok' : 'unavailable' - }); - }).catch(err => { - this.update({ - usernameState: 'error' - }); - }); - }; - - this.onChangePassword = () => { - const password = this.refs.password.value; - - if (password == '') { - this.passwordStrength = ''; - return; - } - - const strength = getPasswordStrength(password); - this.passwordStrength = strength > 0.7 ? 'high' : strength > 0.3 ? 'medium' : 'low'; - this.update(); - this.refs.passwordMetar.style.width = `${strength * 100}%`; - }; - - this.onChangePasswordRetype = () => { - const password = this.refs.password.value; - const retypedPassword = this.refs.passwordRetype.value; - - if (retypedPassword == '') { - this.passwordRetypeState = null; - return; - } - - this.passwordRetypeState = password == retypedPassword ? 'match' : 'not-match'; - }; - - this.onsubmit = e => { - e.preventDefault(); - - const username = this.refs.username.value; - const password = this.refs.password.value; - - const locker = document.body.appendChild(document.createElement('mk-locker')); - - this.api('signup', { - username: username, - password: password, - 'g-recaptcha-response': grecaptcha.getResponse() - }).then(() => { - this.api('signin', { - username: username, - password: password - }).then(() => { - location.href = '/'; - }); - }).catch(() => { - alert('%i18n:common.tags.mk-signup.some-error%'); - - grecaptcha.reset(); - this.recaptchaed = false; - - locker.parentNode.removeChild(locker); - }); - - return false; - }; - </script> -</mk-signup> diff --git a/src/web/app/common/tags/special-message.tag b/src/web/app/common/tags/special-message.tag deleted file mode 100644 index 6643b1324a..0000000000 --- a/src/web/app/common/tags/special-message.tag +++ /dev/null @@ -1,27 +0,0 @@ -<mk-special-message> - <p if={ m == 1 && d == 1 }>%i18n:common.tags.mk-special-message.new-year%</p> - <p if={ m == 12 && d == 25 }>%i18n:common.tags.mk-special-message.christmas%</p> - <style> - :scope - display block - - &:empty - display none - - > p - margin 0 - padding 4px - text-align center - font-size 14px - font-weight bold - text-transform uppercase - color #fff - background #ff1036 - - </style> - <script> - const now = new Date(); - this.d = now.getDate(); - this.m = now.getMonth() + 1; - </script> -</mk-special-message> diff --git a/src/web/app/common/tags/stream-indicator.tag b/src/web/app/common/tags/stream-indicator.tag deleted file mode 100644 index 0eb6196b6d..0000000000 --- a/src/web/app/common/tags/stream-indicator.tag +++ /dev/null @@ -1,78 +0,0 @@ -<mk-stream-indicator> - <p if={ connection.state == 'initializing' }> - %fa:spinner .pulse% - <span>%i18n:common.tags.mk-stream-indicator.connecting%<mk-ellipsis/></span> - </p> - <p if={ connection.state == 'reconnecting' }> - %fa:spinner .pulse% - <span>%i18n:common.tags.mk-stream-indicator.reconnecting%<mk-ellipsis/></span> - </p> - <p if={ connection.state == 'connected' }> - %fa:check% - <span>%i18n:common.tags.mk-stream-indicator.connected%</span> - </p> - <style> - :scope - display block - pointer-events none - position fixed - z-index 16384 - bottom 8px - right 8px - margin 0 - padding 6px 12px - font-size 0.9em - color #fff - background rgba(0, 0, 0, 0.8) - border-radius 4px - - > p - display block - margin 0 - - > [data-fa] - margin-right 0.25em - - </style> - <script> - import anime from 'animejs'; - - this.mixin('i'); - - this.mixin('stream'); - this.connection = this.stream.getConnection(); - this.connectionId = this.stream.use(); - - this.on('before-mount', () => { - if (this.connection.state == 'connected') { - this.root.style.opacity = 0; - } - - this.connection.on('_connected_', () => { - this.update(); - setTimeout(() => { - anime({ - targets: this.root, - opacity: 0, - easing: 'linear', - duration: 200 - }); - }, 1000); - }); - - this.connection.on('_closed_', () => { - this.update(); - anime({ - targets: this.root, - opacity: 1, - easing: 'linear', - duration: 100 - }); - }); - }); - - this.on('unmount', () => { - this.stream.dispose(this.connectionId); - }); - </script> -</mk-stream-indicator> diff --git a/src/web/app/common/tags/time.tag b/src/web/app/common/tags/time.tag deleted file mode 100644 index b0d7d24533..0000000000 --- a/src/web/app/common/tags/time.tag +++ /dev/null @@ -1,50 +0,0 @@ -<mk-time> - <time datetime={ opts.time }> - <span if={ mode == 'relative' }>{ relative }</span> - <span if={ mode == 'absolute' }>{ absolute }</span> - <span if={ mode == 'detail' }>{ absolute } ({ relative })</span> - </time> - <script> - this.time = new Date(this.opts.time); - this.mode = this.opts.mode || 'relative'; - this.tickid = null; - - this.absolute = - this.time.getFullYear() + '年' + - (this.time.getMonth() + 1) + '月' + - this.time.getDate() + '日' + - ' ' + - this.time.getHours() + '時' + - this.time.getMinutes() + '分'; - - this.on('mount', () => { - if (this.mode == 'relative' || this.mode == 'detail') { - this.tick(); - this.tickid = setInterval(this.tick, 1000); - } - }); - - this.on('unmount', () => { - if (this.mode === 'relative' || this.mode === 'detail') { - clearInterval(this.tickid); - } - }); - - this.tick = () => { - const now = new Date(); - const ago = (now - this.time) / 1000/*ms*/; - this.relative = - ago >= 31536000 ? '%i18n:common.time.years_ago%' .replace('{}', ~~(ago / 31536000)) : - ago >= 2592000 ? '%i18n:common.time.months_ago%' .replace('{}', ~~(ago / 2592000)) : - ago >= 604800 ? '%i18n:common.time.weeks_ago%' .replace('{}', ~~(ago / 604800)) : - ago >= 86400 ? '%i18n:common.time.days_ago%' .replace('{}', ~~(ago / 86400)) : - ago >= 3600 ? '%i18n:common.time.hours_ago%' .replace('{}', ~~(ago / 3600)) : - ago >= 60 ? '%i18n:common.time.minutes_ago%'.replace('{}', ~~(ago / 60)) : - ago >= 10 ? '%i18n:common.time.seconds_ago%'.replace('{}', ~~(ago % 60)) : - ago >= 0 ? '%i18n:common.time.just_now%' : - ago < 0 ? '%i18n:common.time.future%' : - '%i18n:common.time.unknown%'; - this.update(); - }; - </script> -</mk-time> diff --git a/src/web/app/common/tags/twitter-setting.tag b/src/web/app/common/tags/twitter-setting.tag deleted file mode 100644 index 3b70505ba2..0000000000 --- a/src/web/app/common/tags/twitter-setting.tag +++ /dev/null @@ -1,62 +0,0 @@ -<mk-twitter-setting> - <p>%i18n:common.tags.mk-twitter-setting.description%<a href={ _ABOUT_URL_ + '/link-to-twitter' } target="_blank">%i18n:common.tags.mk-twitter-setting.detail%</a></p> - <p class="account" if={ I.twitter } title={ 'Twitter ID: ' + I.twitter.user_id }>%i18n:common.tags.mk-twitter-setting.connected-to%: <a href={ 'https://twitter.com/' + I.twitter.screen_name } target="_blank">@{ I.twitter.screen_name }</a></p> - <p> - <a href={ _API_URL_ + '/connect/twitter' } target="_blank" onclick={ connect }>{ I.twitter ? '%i18n:common.tags.mk-twitter-setting.reconnect%' : '%i18n:common.tags.mk-twitter-setting.connect%' }</a> - <span if={ I.twitter }> or </span> - <a href={ _API_URL_ + '/disconnect/twitter' } target="_blank" if={ I.twitter } onclick={ disconnect }>%i18n:common.tags.mk-twitter-setting.disconnect%</a> - </p> - <p class="id" if={ I.twitter }>Twitter ID: { I.twitter.user_id }</p> - <style> - :scope - display block - color #4a535a - - .account - border solid 1px #e1e8ed - border-radius 4px - padding 16px - - a - font-weight bold - color inherit - - .id - color #8899a6 - </style> - <script> - this.mixin('i'); - - this.form = null; - - this.on('mount', () => { - this.I.on('updated', this.onMeUpdated); - }); - - this.on('unmount', () => { - this.I.off('updated', this.onMeUpdated); - }); - - this.onMeUpdated = () => { - if (this.I.twitter) { - if (this.form) this.form.close(); - } - }; - - this.connect = e => { - e.preventDefault(); - this.form = window.open(_API_URL_ + '/connect/twitter', - 'twitter_connect_window', - 'height=570,width=520'); - return false; - }; - - this.disconnect = e => { - e.preventDefault(); - window.open(_API_URL_ + '/disconnect/twitter', - 'twitter_disconnect_window', - 'height=570,width=520'); - return false; - }; - </script> -</mk-twitter-setting> diff --git a/src/web/app/common/tags/uploader.tag b/src/web/app/common/tags/uploader.tag deleted file mode 100644 index a95004b46d..0000000000 --- a/src/web/app/common/tags/uploader.tag +++ /dev/null @@ -1,199 +0,0 @@ -<mk-uploader> - <ol if={ uploads.length > 0 }> - <li each={ uploads }> - <div class="img" style="background-image: url({ img })"></div> - <p class="name">%fa:spinner .pulse%{ name }</p> - <p class="status"><span class="initing" if={ progress == undefined }>%i18n:common.tags.mk-uploader.waiting%<mk-ellipsis/></span><span class="kb" if={ progress != undefined }>{ String(Math.floor(progress.value / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }<i>KB</i> / { String(Math.floor(progress.max / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }<i>KB</i></span><span class="percentage" if={ progress != undefined }>{ Math.floor((progress.value / progress.max) * 100) }</span></p> - <progress if={ progress != undefined && progress.value != progress.max } value={ progress.value } max={ progress.max }></progress> - <div class="progress initing" if={ progress == undefined }></div> - <div class="progress waiting" if={ progress != undefined && progress.value == progress.max }></div> - </li> - </ol> - <style> - :scope - display block - overflow auto - - &:empty - display none - - > ol - display block - margin 0 - padding 0 - list-style none - - > li - display block - margin 8px 0 0 0 - padding 0 - height 36px - box-shadow 0 -1px 0 rgba($theme-color, 0.1) - border-top solid 8px transparent - - &:first-child - margin 0 - box-shadow none - border-top none - - > .img - display block - position absolute - top 0 - left 0 - width 36px - height 36px - background-size cover - background-position center center - - > .name - display block - position absolute - top 0 - left 44px - margin 0 - padding 0 - max-width 256px - font-size 0.8em - color rgba($theme-color, 0.7) - white-space nowrap - text-overflow ellipsis - overflow hidden - - > [data-fa] - margin-right 4px - - > .status - display block - position absolute - top 0 - right 0 - margin 0 - padding 0 - font-size 0.8em - - > .initing - color rgba($theme-color, 0.5) - - > .kb - color rgba($theme-color, 0.5) - - > .percentage - display inline-block - width 48px - text-align right - - color rgba($theme-color, 0.7) - - &:after - content '%' - - > progress - display block - position absolute - bottom 0 - right 0 - margin 0 - width calc(100% - 44px) - height 8px - background transparent - border none - border-radius 4px - overflow hidden - - &::-webkit-progress-value - background $theme-color - - &::-webkit-progress-bar - background rgba($theme-color, 0.1) - - > .progress - display block - position absolute - bottom 0 - right 0 - margin 0 - width calc(100% - 44px) - height 8px - border none - border-radius 4px - background linear-gradient( - 45deg, - lighten($theme-color, 30%) 25%, - $theme-color 25%, - $theme-color 50%, - lighten($theme-color, 30%) 50%, - lighten($theme-color, 30%) 75%, - $theme-color 75%, - $theme-color - ) - background-size 32px 32px - animation bg 1.5s linear infinite - - &.initing - opacity 0.3 - - @keyframes bg - from {background-position: 0 0;} - to {background-position: -64px 32px;} - - </style> - <script> - this.mixin('i'); - - this.uploads = []; - - this.upload = (file, folder) => { - if (folder && typeof folder == 'object') folder = folder.id; - - const id = Math.random(); - - const ctx = { - id: id, - name: file.name || 'untitled', - progress: undefined - }; - - this.uploads.push(ctx); - this.trigger('change-uploads', this.uploads); - this.update(); - - const reader = new FileReader(); - reader.onload = e => { - ctx.img = e.target.result; - this.update(); - }; - reader.readAsDataURL(file); - - const data = new FormData(); - data.append('i', this.I.token); - data.append('file', file); - - if (folder) data.append('folder_id', folder); - - const xhr = new XMLHttpRequest(); - xhr.open('POST', _API_URL_ + '/drive/files/create', true); - xhr.onload = e => { - const driveFile = JSON.parse(e.target.response); - - this.trigger('uploaded', driveFile); - - this.uploads = this.uploads.filter(x => x.id != id); - this.trigger('change-uploads', this.uploads); - - this.update(); - }; - - xhr.upload.onprogress = e => { - if (e.lengthComputable) { - if (ctx.progress == undefined) ctx.progress = {}; - ctx.progress.max = e.total; - ctx.progress.value = e.loaded; - this.update(); - } - }; - - xhr.send(data); - }; - </script> -</mk-uploader> diff --git a/src/web/app/common/tags/url-preview.tag b/src/web/app/common/tags/url-preview.tag deleted file mode 100644 index 7dbdd8fea2..0000000000 --- a/src/web/app/common/tags/url-preview.tag +++ /dev/null @@ -1,117 +0,0 @@ -<mk-url-preview> - <a href={ url } target="_blank" title={ url } if={ !loading }> - <div class="thumbnail" if={ thumbnail } style={ 'background-image: url(' + thumbnail + ')' }></div> - <article> - <header> - <h1>{ title }</h1> - </header> - <p>{ description }</p> - <footer> - <img class="icon" if={ icon } src={ icon }/> - <p>{ sitename }</p> - </footer> - </article> - </a> - <style> - :scope - display block - font-size 16px - - > a - display block - border solid 1px #eee - border-radius 4px - overflow hidden - - &:hover - text-decoration none - border-color #ddd - - > article > header > h1 - text-decoration underline - - > .thumbnail - position absolute - width 100px - height 100% - background-position center - background-size cover - - & + article - left 100px - width calc(100% - 100px) - - > article - padding 16px - - > header - margin-bottom 8px - - > h1 - margin 0 - font-size 1em - color #555 - - > p - margin 0 - color #777 - font-size 0.8em - - > footer - margin-top 8px - height 16px - - > img - display inline-block - width 16px - height 16px - margin-right 4px - vertical-align top - - > p - display inline-block - margin 0 - color #666 - font-size 0.8em - line-height 16px - vertical-align top - - @media (max-width 500px) - font-size 8px - - > a - border none - - > .thumbnail - width 70px - - & + article - left 70px - width calc(100% - 70px) - - > article - padding 8px - - </style> - <script> - this.mixin('api'); - - this.url = this.opts.url; - this.loading = true; - - this.on('mount', () => { - fetch('/api:url?url=' + this.url).then(res => { - res.json().then(info => { - this.title = info.title; - this.description = info.description; - this.thumbnail = info.thumbnail; - this.icon = info.icon; - this.sitename = info.sitename; - - this.loading = false; - this.update(); - }); - }); - }); - </script> -</mk-url-preview> diff --git a/src/web/app/common/tags/url.tag b/src/web/app/common/tags/url.tag deleted file mode 100644 index 2690afc5da..0000000000 --- a/src/web/app/common/tags/url.tag +++ /dev/null @@ -1,54 +0,0 @@ -<mk-url> - <a href={ url } target={ opts.target }> - <span class="schema">{ schema }//</span> - <span class="hostname">{ hostname }</span> - <span class="port" if={ port != '' }>:{ port }</span> - <span class="pathname" if={ pathname != '' }>{ pathname }</span> - <span class="query">{ query }</span> - <span class="hash">{ hash }</span> - %fa:external-link-square-alt% - </a> - <style> - :scope - word-break break-all - - > a - > [data-fa] - padding-left 2px - font-size .9em - font-weight 400 - font-style normal - - > .schema - opacity 0.5 - - > .hostname - font-weight bold - - > .pathname - opacity 0.8 - - > .query - opacity 0.5 - - > .hash - font-style italic - - </style> - <script> - this.url = this.opts.href; - - this.on('before-mount', () => { - const url = new URL(this.url); - - this.schema = url.protocol; - this.hostname = url.hostname; - this.port = url.port; - this.pathname = url.pathname; - this.query = url.search; - this.hash = url.hash; - - this.update(); - }); - </script> -</mk-url> |