mirror of
https://git.joinsharkey.org/Sharkey/Sharkey.git
synced 2024-12-23 19:43:08 +02:00
Merge branch 'master' into l10n_master
This commit is contained in:
commit
0d0c45a4cf
55 changed files with 575 additions and 1526 deletions
11
.travis.yml
11
.travis.yml
|
@ -7,7 +7,7 @@ notifications:
|
||||||
language: node_js
|
language: node_js
|
||||||
|
|
||||||
node_js:
|
node_js:
|
||||||
- 9.8.0
|
- 10.1.0
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- CXX=g++-4.8 NODE_ENV=production
|
- CXX=g++-4.8 NODE_ENV=production
|
||||||
|
@ -22,19 +22,14 @@ addons:
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
# パッケージをキャッシュすると本来は動かないはずなのに動いてしまう
|
- node_modules
|
||||||
# 場合があり危険なのでキャッシュはしない:
|
|
||||||
#- node_modules
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
- mongodb
|
- mongodb
|
||||||
- redis-server
|
- redis-server
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
# Travisはproduction環境なので(10行目により)、
|
- npm install
|
||||||
# npm install しただけでは devDependencies はインストールされないので、
|
|
||||||
# --only=dev オプションを付けてそれらもインストールされるようにする:
|
|
||||||
- npm install --only=dev
|
|
||||||
|
|
||||||
# 設定ファイルを配置
|
# 設定ファイルを配置
|
||||||
- cp ./.travis/default.yml ./.config
|
- cp ./.travis/default.yml ./.config
|
||||||
|
|
41
appveyor.yml
Normal file
41
appveyor.yml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# appveyor file
|
||||||
|
# http://www.appveyor.com/docs/appveyor-yml
|
||||||
|
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- nodejs_version: 10.1.0
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- node_modules
|
||||||
|
|
||||||
|
build: off
|
||||||
|
|
||||||
|
install:
|
||||||
|
# Update Node.js
|
||||||
|
# 標準で入っている Node.js を更新します (2014/11/13 時点では、v0.10.32 が標準)
|
||||||
|
- ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version)
|
||||||
|
- node --version
|
||||||
|
|
||||||
|
# Update NPM
|
||||||
|
- npm install -g npm
|
||||||
|
- npm --version
|
||||||
|
|
||||||
|
# Update node-gyp
|
||||||
|
# 必須! node-gyp のバージョンを上げないと、ネイティブモジュールのコンパイルに失敗します
|
||||||
|
- npm install -g node-gyp
|
||||||
|
|
||||||
|
- npm install
|
||||||
|
|
||||||
|
init:
|
||||||
|
# git clone の際の改行を変換しないようにします
|
||||||
|
- git config --global core.autocrlf false
|
||||||
|
|
||||||
|
before_test:
|
||||||
|
# 設定ファイルを配置
|
||||||
|
- cp ./.travis/default.yml ./.config
|
||||||
|
- cp ./.travis/test.yml ./.config
|
||||||
|
|
||||||
|
- npm run build
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- npm test
|
|
@ -20,6 +20,7 @@ import * as replace from 'gulp-replace';
|
||||||
import * as htmlmin from 'gulp-htmlmin';
|
import * as htmlmin from 'gulp-htmlmin';
|
||||||
const uglifyes = require('uglify-es');
|
const uglifyes = require('uglify-es');
|
||||||
|
|
||||||
|
import locales from './locales';
|
||||||
import { fa } from './src/build/fa';
|
import { fa } from './src/build/fa';
|
||||||
const client = require('./built/client/meta.json');
|
const client = require('./built/client/meta.json');
|
||||||
import config from './src/config';
|
import config from './src/config';
|
||||||
|
@ -122,6 +123,7 @@ gulp.task('build:client:script', () =>
|
||||||
.pipe(replace('VERSION', JSON.stringify(client.version)))
|
.pipe(replace('VERSION', JSON.stringify(client.version)))
|
||||||
.pipe(replace('API', JSON.stringify(config.api_url)))
|
.pipe(replace('API', JSON.stringify(config.api_url)))
|
||||||
.pipe(replace('ENV', JSON.stringify(env)))
|
.pipe(replace('ENV', JSON.stringify(env)))
|
||||||
|
.pipe(replace('LANGS', JSON.stringify(Object.keys(locales))))
|
||||||
.pipe(isProduction ? uglify({
|
.pipe(isProduction ? uglify({
|
||||||
toplevel: true
|
toplevel: true
|
||||||
} as any) : gutil.noop())
|
} as any) : gutil.noop())
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
meta:
|
meta:
|
||||||
lang: "日本語"
|
lang: "English"
|
||||||
divider: ""
|
divider: " "
|
||||||
common:
|
common:
|
||||||
misskey: "Share everything with others using Misskey."
|
misskey: "Share everything with others using Misskey."
|
||||||
time:
|
time:
|
||||||
|
|
|
@ -11,6 +11,7 @@ const loadLang = lang => yaml.safeLoad(
|
||||||
const native = loadLang('ja');
|
const native = loadLang('ja');
|
||||||
|
|
||||||
const langs = {
|
const langs = {
|
||||||
|
'de': loadLang('de'),
|
||||||
'en': loadLang('en'),
|
'en': loadLang('en'),
|
||||||
'fr': loadLang('fr'),
|
'fr': loadLang('fr'),
|
||||||
'ja': native,
|
'ja': native,
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
meta:
|
||||||
|
lang: "日本語"
|
||||||
|
divider: ""
|
||||||
|
|
||||||
common:
|
common:
|
||||||
misskey: "Misskeyで皆と共有しよう。"
|
misskey: "Misskeyで皆と共有しよう。"
|
||||||
|
|
||||||
|
@ -253,6 +257,32 @@ desktop/views/components/drive.vue:
|
||||||
upload: "ファイルをアップロード"
|
upload: "ファイルをアップロード"
|
||||||
url-upload: "URLからアップロード"
|
url-upload: "URLからアップロード"
|
||||||
|
|
||||||
|
desktop/views/components/home.vue:
|
||||||
|
done: "完了"
|
||||||
|
add-widget: "ウィジェットを追加:"
|
||||||
|
profile: "プロフィール"
|
||||||
|
calendar: "カレンダー"
|
||||||
|
timemachine: "カレンダー(タイムマシン)"
|
||||||
|
activity: "アクティビティ"
|
||||||
|
rss: "RSSリーダー"
|
||||||
|
trends: "トレンド"
|
||||||
|
photostream: "フォトストリーム"
|
||||||
|
slideshow: "スライドショー"
|
||||||
|
version: "バージョン"
|
||||||
|
broadcast: "ブロードキャスト"
|
||||||
|
notifications: "通知"
|
||||||
|
users: "おすすめユーザー"
|
||||||
|
polls: "投票"
|
||||||
|
post-form: "投稿フォーム"
|
||||||
|
messaging: "メッセージ"
|
||||||
|
channel: "チャンネル"
|
||||||
|
access-log: "アクセスログ"
|
||||||
|
server: "サーバー情報"
|
||||||
|
donation: "寄付のお願い"
|
||||||
|
nav: "ナビゲーション"
|
||||||
|
tips: "ヒント"
|
||||||
|
add: "追加"
|
||||||
|
|
||||||
desktop/views/components/messaging-window.vue:
|
desktop/views/components/messaging-window.vue:
|
||||||
title: "メッセージ"
|
title: "メッセージ"
|
||||||
|
|
||||||
|
@ -312,6 +342,7 @@ desktop/views/components/settings.vue:
|
||||||
mute: "ミュート"
|
mute: "ミュート"
|
||||||
drive: "ドライブ"
|
drive: "ドライブ"
|
||||||
security: "セキュリティ"
|
security: "セキュリティ"
|
||||||
|
signin: "サインイン履歴"
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
2fa: "二段階認証"
|
2fa: "二段階認証"
|
||||||
other: "その他"
|
other: "その他"
|
||||||
|
@ -341,6 +372,7 @@ desktop/views/components/settings.api.vue:
|
||||||
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
caution: "アカウントを不正利用される可能性があるため、このトークンは第三者に教えないでください(アプリなどにも入力しないでください)。"
|
||||||
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
regeneration-of-token: "万が一このトークンが漏れたりその可能性がある場合はトークンを再生成できます。"
|
||||||
regenerate-token: "トークンを再生成"
|
regenerate-token: "トークンを再生成"
|
||||||
|
token: "Token:"
|
||||||
enter-password: "パスワードを入力してください"
|
enter-password: "パスワードを入力してください"
|
||||||
|
|
||||||
desktop/views/components/settings.app.vue:
|
desktop/views/components/settings.app.vue:
|
||||||
|
@ -396,6 +428,20 @@ desktop/views/components/ui.header.post.vue:
|
||||||
desktop/views/components/ui.header.search.vue:
|
desktop/views/components/ui.header.search.vue:
|
||||||
placeholder: "検索"
|
placeholder: "検索"
|
||||||
|
|
||||||
|
desktop/views/components/user-lists-window.vue:
|
||||||
|
create-list: "リストを作成"
|
||||||
|
|
||||||
|
desktop/views/components/user-preview.vue:
|
||||||
|
notes: "投稿"
|
||||||
|
following: "フォロー"
|
||||||
|
followers: "フォロワー"
|
||||||
|
|
||||||
|
desktop/views/components/users-list.vue:
|
||||||
|
all: "すべて"
|
||||||
|
iknow: "知り合い"
|
||||||
|
load-more: "もっと"
|
||||||
|
fetching: "読み込んでいます"
|
||||||
|
|
||||||
desktop/views/pages/note.vue:
|
desktop/views/pages/note.vue:
|
||||||
prev: "前の投稿"
|
prev: "前の投稿"
|
||||||
next: "次の投稿"
|
next: "次の投稿"
|
||||||
|
@ -510,6 +556,9 @@ mobile/views/components/notifications.vue:
|
||||||
|
|
||||||
mobile/views/components/post-form.vue:
|
mobile/views/components/post-form.vue:
|
||||||
submit: "投稿"
|
submit: "投稿"
|
||||||
|
reply: "返信"
|
||||||
|
renote: "Renote"
|
||||||
|
renote-placeholder: "この投稿を引用... (オプション)"
|
||||||
reply-placeholder: "この投稿への返信..."
|
reply-placeholder: "この投稿への返信..."
|
||||||
note-placeholder: "いまどうしてる?"
|
note-placeholder: "いまどうしてる?"
|
||||||
|
|
||||||
|
|
75
package.json
75
package.json
|
@ -1,8 +1,8 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <i@syuilo.com>",
|
"author": "syuilo <i@syuilo.com>",
|
||||||
"version": "2.6.2",
|
"version": "2.10.0",
|
||||||
"clientVersion": "1.0.5260",
|
"clientVersion": "1.0.5406",
|
||||||
"codename": "nighthike",
|
"codename": "nighthike",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
@ -31,13 +31,11 @@
|
||||||
"@prezzemolo/rap": "0.1.2",
|
"@prezzemolo/rap": "0.1.2",
|
||||||
"@prezzemolo/zip": "0.0.3",
|
"@prezzemolo/zip": "0.0.3",
|
||||||
"@types/bcryptjs": "2.4.1",
|
"@types/bcryptjs": "2.4.1",
|
||||||
"@types/chai": "4.1.3",
|
|
||||||
"@types/chai-http": "3.0.4",
|
|
||||||
"@types/debug": "0.0.30",
|
"@types/debug": "0.0.30",
|
||||||
"@types/deep-equal": "1.0.1",
|
"@types/deep-equal": "1.0.1",
|
||||||
"@types/elasticsearch": "5.0.22",
|
"@types/elasticsearch": "5.0.23",
|
||||||
"@types/eventemitter3": "2.0.2",
|
"@types/eventemitter3": "2.0.2",
|
||||||
"@types/gm": "1.17.33",
|
"@types/gm": "1.18.0",
|
||||||
"@types/gulp": "3.8.36",
|
"@types/gulp": "3.8.36",
|
||||||
"@types/gulp-htmlmin": "1.3.32",
|
"@types/gulp-htmlmin": "1.3.32",
|
||||||
"@types/gulp-mocha": "0.0.32",
|
"@types/gulp-mocha": "0.0.32",
|
||||||
|
@ -58,18 +56,18 @@
|
||||||
"@types/koa-multer": "1.0.0",
|
"@types/koa-multer": "1.0.0",
|
||||||
"@types/koa-router": "7.0.28",
|
"@types/koa-router": "7.0.28",
|
||||||
"@types/koa-send": "4.1.1",
|
"@types/koa-send": "4.1.1",
|
||||||
"@types/koa-views": "^2.0.3",
|
"@types/koa-views": "2.0.3",
|
||||||
"@types/koa__cors": "2.2.2",
|
"@types/koa__cors": "2.2.2",
|
||||||
"@types/kue": "0.11.8",
|
"@types/kue": "0.11.8",
|
||||||
"@types/license-checker": "15.0.0",
|
"@types/license-checker": "15.0.0",
|
||||||
"@types/mkdirp": "0.5.2",
|
"@types/mkdirp": "0.5.2",
|
||||||
"@types/mocha": "5.2.0",
|
"@types/mocha": "5.2.0",
|
||||||
"@types/mongodb": "3.0.15",
|
"@types/mongodb": "3.0.18",
|
||||||
"@types/monk": "6.0.0",
|
"@types/monk": "6.0.0",
|
||||||
"@types/ms": "0.7.30",
|
"@types/ms": "0.7.30",
|
||||||
"@types/node": "9.6.6",
|
"@types/node": "10.1.0",
|
||||||
"@types/nopt": "3.0.29",
|
"@types/nopt": "3.0.29",
|
||||||
"@types/parse5": "^3.0.0",
|
"@types/parse5": "3.0.0",
|
||||||
"@types/pug": "2.0.4",
|
"@types/pug": "2.0.4",
|
||||||
"@types/qrcode": "0.8.1",
|
"@types/qrcode": "0.8.1",
|
||||||
"@types/ratelimiter": "2.1.28",
|
"@types/ratelimiter": "2.1.28",
|
||||||
|
@ -78,22 +76,20 @@
|
||||||
"@types/request-promise-native": "1.0.14",
|
"@types/request-promise-native": "1.0.14",
|
||||||
"@types/rimraf": "2.0.2",
|
"@types/rimraf": "2.0.2",
|
||||||
"@types/seedrandom": "2.4.27",
|
"@types/seedrandom": "2.4.27",
|
||||||
"@types/single-line-log": "^1.1.0",
|
"@types/single-line-log": "1.1.0",
|
||||||
"@types/speakeasy": "2.0.2",
|
"@types/speakeasy": "2.0.2",
|
||||||
"@types/tmp": "0.0.33",
|
"@types/tmp": "0.0.33",
|
||||||
"@types/uuid": "3.4.3",
|
"@types/uuid": "3.4.3",
|
||||||
"@types/webpack": "4.1.4",
|
"@types/webpack": "4.1.7",
|
||||||
"@types/webpack-stream": "3.2.10",
|
"@types/webpack-stream": "3.2.10",
|
||||||
"@types/websocket": "0.0.38",
|
"@types/websocket": "0.0.39",
|
||||||
"@types/ws": "4.0.2",
|
"@types/ws": "5.1.1",
|
||||||
"animejs": "2.2.0",
|
"animejs": "2.2.0",
|
||||||
"autosize": "4.0.1",
|
"autosize": "4.0.2",
|
||||||
"autwh": "0.1.0",
|
"autwh": "0.1.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"bootstrap-vue": "2.0.0-rc.6",
|
"bootstrap-vue": "2.0.0-rc.6",
|
||||||
"cafy": "8.0.0",
|
"cafy": "8.0.0",
|
||||||
"chai": "4.1.2",
|
|
||||||
"chai-http": "4.0.0",
|
|
||||||
"chalk": "2.4.1",
|
"chalk": "2.4.1",
|
||||||
"crc-32": "1.2.0",
|
"crc-32": "1.2.0",
|
||||||
"css-loader": "0.28.11",
|
"css-loader": "0.28.11",
|
||||||
|
@ -101,9 +97,9 @@
|
||||||
"deep-equal": "1.0.1",
|
"deep-equal": "1.0.1",
|
||||||
"deepcopy": "0.6.3",
|
"deepcopy": "0.6.3",
|
||||||
"diskusage": "0.2.4",
|
"diskusage": "0.2.4",
|
||||||
"dompurify": "1.0.3",
|
"dompurify": "1.0.4",
|
||||||
"elasticsearch": "14.2.2",
|
"elasticsearch": "14.2.2",
|
||||||
"element-ui": "2.3.6",
|
"element-ui": "2.3.8",
|
||||||
"emojilib": "2.2.12",
|
"emojilib": "2.2.12",
|
||||||
"escape-regexp": "0.0.1",
|
"escape-regexp": "0.0.1",
|
||||||
"eslint": "4.19.1",
|
"eslint": "4.19.1",
|
||||||
|
@ -111,7 +107,7 @@
|
||||||
"eventemitter3": "3.1.0",
|
"eventemitter3": "3.1.0",
|
||||||
"exif-js": "2.3.0",
|
"exif-js": "2.3.0",
|
||||||
"file-loader": "1.1.11",
|
"file-loader": "1.1.11",
|
||||||
"file-type": "7.6.0",
|
"file-type": "8.0.0",
|
||||||
"fuckadblock": "3.2.1",
|
"fuckadblock": "3.2.1",
|
||||||
"gm": "1.23.1",
|
"gm": "1.23.1",
|
||||||
"gulp": "3.9.1",
|
"gulp": "3.9.1",
|
||||||
|
@ -120,15 +116,15 @@
|
||||||
"gulp-imagemin": "4.1.0",
|
"gulp-imagemin": "4.1.0",
|
||||||
"gulp-mocha": "5.0.0",
|
"gulp-mocha": "5.0.0",
|
||||||
"gulp-pug": "4.0.1",
|
"gulp-pug": "4.0.1",
|
||||||
"gulp-rename": "1.2.2",
|
"gulp-rename": "1.2.3",
|
||||||
"gulp-replace": "0.6.1",
|
"gulp-replace": "1.0.0",
|
||||||
"gulp-sourcemaps": "2.6.4",
|
"gulp-sourcemaps": "2.6.4",
|
||||||
"gulp-stylus": "2.7.0",
|
"gulp-stylus": "2.7.0",
|
||||||
"gulp-tslint": "8.1.3",
|
"gulp-tslint": "8.1.3",
|
||||||
"gulp-typescript": "4.0.2",
|
"gulp-typescript": "4.0.2",
|
||||||
"gulp-uglify": "3.0.0",
|
"gulp-uglify": "3.0.0",
|
||||||
"gulp-util": "3.0.8",
|
"gulp-util": "3.0.8",
|
||||||
"hard-source-webpack-plugin": "0.6.4",
|
"hard-source-webpack-plugin": "0.6.7",
|
||||||
"highlight.js": "9.12.0",
|
"highlight.js": "9.12.0",
|
||||||
"html-minifier": "3.5.15",
|
"html-minifier": "3.5.15",
|
||||||
"http-signature": "1.2.0",
|
"http-signature": "1.2.0",
|
||||||
|
@ -136,7 +132,7 @@
|
||||||
"is-root": "2.0.0",
|
"is-root": "2.0.0",
|
||||||
"is-url": "1.2.4",
|
"is-url": "1.2.4",
|
||||||
"js-yaml": "3.11.0",
|
"js-yaml": "3.11.0",
|
||||||
"jsdom": "11.9.0",
|
"jsdom": "11.10.0",
|
||||||
"koa": "2.5.1",
|
"koa": "2.5.1",
|
||||||
"koa-bodyparser": "4.2.0",
|
"koa-bodyparser": "4.2.0",
|
||||||
"koa-compress": "3.0.0",
|
"koa-compress": "3.0.0",
|
||||||
|
@ -148,16 +144,16 @@
|
||||||
"koa-router": "7.4.0",
|
"koa-router": "7.4.0",
|
||||||
"koa-send": "4.1.3",
|
"koa-send": "4.1.3",
|
||||||
"koa-slow": "2.1.0",
|
"koa-slow": "2.1.0",
|
||||||
"koa-views": "^6.1.4",
|
"koa-views": "6.1.4",
|
||||||
"kue": "0.11.6",
|
"kue": "0.11.6",
|
||||||
"license-checker": "18.0.0",
|
"license-checker": "19.0.0",
|
||||||
"loader-utils": "1.1.0",
|
"loader-utils": "1.1.0",
|
||||||
"mecab-async": "0.1.2",
|
"mecab-async": "0.1.2",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"mocha": "5.1.1",
|
"mocha": "5.1.1",
|
||||||
"moji": "0.5.1",
|
"moji": "0.5.1",
|
||||||
"mongodb": "3.0.7",
|
"mongodb": "3.0.8",
|
||||||
"monk": "6.0.5",
|
"monk": "6.0.6",
|
||||||
"ms": "2.1.1",
|
"ms": "2.1.1",
|
||||||
"nan": "2.10.0",
|
"nan": "2.10.0",
|
||||||
"node-sass": "4.9.0",
|
"node-sass": "4.9.0",
|
||||||
|
@ -167,10 +163,10 @@
|
||||||
"object-assign-deep": "0.4.0",
|
"object-assign-deep": "0.4.0",
|
||||||
"on-build-webpack": "0.1.0",
|
"on-build-webpack": "0.1.0",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
"parse5": "^4.0.0",
|
"parse5": "4.0.0",
|
||||||
"progress-bar-webpack-plugin": "1.11.0",
|
"progress-bar-webpack-plugin": "1.11.0",
|
||||||
"prominence": "0.2.0",
|
"prominence": "0.2.0",
|
||||||
"promise-sequential": "^1.1.1",
|
"promise-sequential": "1.1.1",
|
||||||
"pug": "2.0.3",
|
"pug": "2.0.3",
|
||||||
"punycode": "2.1.0",
|
"punycode": "2.1.0",
|
||||||
"qrcode": "1.2.0",
|
"qrcode": "1.2.0",
|
||||||
|
@ -178,14 +174,14 @@
|
||||||
"recaptcha-promise": "0.1.3",
|
"recaptcha-promise": "0.1.3",
|
||||||
"reconnecting-websocket": "3.2.2",
|
"reconnecting-websocket": "3.2.2",
|
||||||
"redis": "2.8.0",
|
"redis": "2.8.0",
|
||||||
"request": "2.85.0",
|
"request": "2.86.0",
|
||||||
"request-promise-native": "1.0.5",
|
"request-promise-native": "1.0.5",
|
||||||
"rimraf": "2.6.2",
|
"rimraf": "2.6.2",
|
||||||
"rndstr": "1.0.0",
|
"rndstr": "1.0.0",
|
||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"sass-loader": "7.0.1",
|
"sass-loader": "7.0.1",
|
||||||
"seedrandom": "2.4.3",
|
"seedrandom": "2.4.3",
|
||||||
"single-line-log": "^1.1.2",
|
"single-line-log": "1.1.2",
|
||||||
"speakeasy": "2.0.0",
|
"speakeasy": "2.0.0",
|
||||||
"style-loader": "0.21.0",
|
"style-loader": "0.21.0",
|
||||||
"stylus": "0.54.5",
|
"stylus": "0.54.5",
|
||||||
|
@ -196,9 +192,9 @@
|
||||||
"tcp-port-used": "0.1.2",
|
"tcp-port-used": "0.1.2",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"tmp": "0.0.33",
|
"tmp": "0.0.33",
|
||||||
"ts-loader": "4.2.0",
|
"ts-loader": "4.3.0",
|
||||||
"ts-node": "6.0.1",
|
"ts-node": "6.0.3",
|
||||||
"tslint": "5.9.1",
|
"tslint": "5.10.0",
|
||||||
"typescript": "2.8.3",
|
"typescript": "2.8.3",
|
||||||
"typescript-eslint-parser": "15.0.0",
|
"typescript-eslint-parser": "15.0.0",
|
||||||
"uglify-es": "3.3.9",
|
"uglify-es": "3.3.9",
|
||||||
|
@ -209,16 +205,15 @@
|
||||||
"vue-cropperjs": "2.2.0",
|
"vue-cropperjs": "2.2.0",
|
||||||
"vue-js-modal": "1.3.13",
|
"vue-js-modal": "1.3.13",
|
||||||
"vue-json-tree-view": "2.1.4",
|
"vue-json-tree-view": "2.1.4",
|
||||||
"vue-loader": "15.0.3",
|
"vue-loader": "15.0.11",
|
||||||
"vue-router": "3.0.1",
|
"vue-router": "3.0.1",
|
||||||
"vue-template-compiler": "2.5.16",
|
"vue-template-compiler": "2.5.16",
|
||||||
"vuedraggable": "2.16.0",
|
"vuedraggable": "2.16.0",
|
||||||
"vuex": "3.0.1",
|
"vuex": "3.0.1",
|
||||||
"web-push": "3.3.0",
|
"web-push": "3.3.1",
|
||||||
"webfinger.js": "2.6.6",
|
"webfinger.js": "2.6.6",
|
||||||
"webpack": "4.6.0",
|
"webpack": "4.8.3",
|
||||||
"webpack-cli": "2.0.15",
|
"webpack-cli": "2.1.3",
|
||||||
"webpack-replace-loader": "1.3.0",
|
|
||||||
"websocket": "1.0.26",
|
"websocket": "1.0.26",
|
||||||
"ws": "5.1.1",
|
"ws": "5.1.1",
|
||||||
"xev": "2.0.0"
|
"xev": "2.0.0"
|
||||||
|
|
|
@ -7,10 +7,7 @@ import * as regular from '@fortawesome/fontawesome-free-regular';
|
||||||
import * as solid from '@fortawesome/fontawesome-free-solid';
|
import * as solid from '@fortawesome/fontawesome-free-solid';
|
||||||
import * as brands from '@fortawesome/fontawesome-free-brands';
|
import * as brands from '@fortawesome/fontawesome-free-brands';
|
||||||
|
|
||||||
// Add icons
|
fontawesome.library.add(regular, solid, brands);
|
||||||
fontawesome.library.add(regular);
|
|
||||||
fontawesome.library.add(solid);
|
|
||||||
fontawesome.library.add(brands);
|
|
||||||
|
|
||||||
export const pattern = /%fa:(.+?)%/g;
|
export const pattern = /%fa:(.+?)%/g;
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
// Detect the user language
|
// Detect the user language
|
||||||
// Note: The default language is Japanese
|
// Note: The default language is Japanese
|
||||||
let lang = navigator.language.split('-')[0];
|
let lang = navigator.language.split('-')[0];
|
||||||
if (!/^(en|ja)$/.test(lang)) lang = 'ja';
|
if (!LANGS.includes(lang)) lang = 'en';
|
||||||
if (localStorage.getItem('lang')) lang = localStorage.getItem('lang');
|
if (localStorage.getItem('lang')) lang = localStorage.getItem('lang');
|
||||||
|
|
||||||
// Detect the user agent
|
// Detect the user agent
|
||||||
|
|
16
src/client/app/common/scripts/can-hide-text.ts
Normal file
16
src/client/app/common/scripts/can-hide-text.ts
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
export default function(note) {
|
||||||
|
if (note.text == null) return true;
|
||||||
|
|
||||||
|
let txt = note.text;
|
||||||
|
|
||||||
|
if (note.media) {
|
||||||
|
note.media.forEach(file => {
|
||||||
|
txt = txt.replace(file.url, '');
|
||||||
|
if (file.src) txt = txt.replace(file.src, '');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (txt == '') return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -48,6 +48,17 @@ export class HomeStream extends Stream {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.on('mobile_home_updated', x => {
|
||||||
|
if (x.home) {
|
||||||
|
os.store.commit('settings/setMobileHome', x.home);
|
||||||
|
} else {
|
||||||
|
os.store.commit('settings/setMobileHomeWidget', {
|
||||||
|
id: x.id,
|
||||||
|
data: x.data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// トークンが再生成されたとき
|
// トークンが再生成されたとき
|
||||||
// このままではMisskeyが利用できないので強制的にサインアウトさせる
|
// このままではMisskeyが利用できないので強制的にサインアウトさせる
|
||||||
this.on('my_token_regenerated', () => {
|
this.on('my_token_regenerated', () => {
|
||||||
|
|
19
src/client/app/common/views/components/acct.vue
Normal file
19
src/client/app/common/views/components/acct.vue
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<template>
|
||||||
|
<span class="mk-acct">
|
||||||
|
<span class="name">@{{ user.username }}</span>
|
||||||
|
<span class="host" v-if="user.host">@{{ user.host }}</span>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
export default Vue.extend({
|
||||||
|
props: ['user']
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.mk-acct
|
||||||
|
> .host
|
||||||
|
opacity 0.5
|
||||||
|
</style>
|
|
@ -23,7 +23,7 @@ export default Vue.extend({
|
||||||
computed: {
|
computed: {
|
||||||
style(): any {
|
style(): any {
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.user.avatarColor ? `rgb(${ this.user.avatarColor.join(',') })` : null,
|
backgroundColor: this.user.avatarColor && this.user.avatarColor.length == 3 ? `rgb(${ this.user.avatarColor.join(',') })` : null,
|
||||||
backgroundImage: `url(${ this.user.avatarUrl }?thumbnail)`,
|
backgroundImage: `url(${ this.user.avatarUrl }?thumbnail)`,
|
||||||
borderRadius: (this as any).clientSettings.circleIcons ? '100%' : null
|
borderRadius: (this as any).clientSettings.circleIcons ? '100%' : null
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,6 +3,7 @@ import Vue from 'vue';
|
||||||
import signin from './signin.vue';
|
import signin from './signin.vue';
|
||||||
import signup from './signup.vue';
|
import signup from './signup.vue';
|
||||||
import forkit from './forkit.vue';
|
import forkit from './forkit.vue';
|
||||||
|
import acct from './acct.vue';
|
||||||
import avatar from './avatar.vue';
|
import avatar from './avatar.vue';
|
||||||
import nav from './nav.vue';
|
import nav from './nav.vue';
|
||||||
import noteHtml from './note-html';
|
import noteHtml from './note-html';
|
||||||
|
@ -29,6 +30,7 @@ import welcomeTimeline from './welcome-timeline.vue';
|
||||||
Vue.component('mk-signin', signin);
|
Vue.component('mk-signin', signin);
|
||||||
Vue.component('mk-signup', signup);
|
Vue.component('mk-signup', signup);
|
||||||
Vue.component('mk-forkit', forkit);
|
Vue.component('mk-forkit', forkit);
|
||||||
|
Vue.component('mk-acct', acct);
|
||||||
Vue.component('mk-avatar', avatar);
|
Vue.component('mk-avatar', avatar);
|
||||||
Vue.component('mk-nav', nav);
|
Vue.component('mk-nav', nav);
|
||||||
Vue.component('mk-note-html', noteHtml);
|
Vue.component('mk-note-html', noteHtml);
|
||||||
|
|
|
@ -126,16 +126,21 @@ root(isDark)
|
||||||
line-height 16px
|
line-height 16px
|
||||||
vertical-align top
|
vertical-align top
|
||||||
|
|
||||||
@media (max-width 500px)
|
@media (max-width 700px)
|
||||||
font-size 8px
|
|
||||||
border none
|
|
||||||
|
|
||||||
> .thumbnail
|
> .thumbnail
|
||||||
width 70px
|
position relative
|
||||||
|
width 100%
|
||||||
|
height 100px
|
||||||
|
|
||||||
& + article
|
& + article
|
||||||
left 70px
|
left 0
|
||||||
width calc(100% - 70px)
|
width 100%
|
||||||
|
|
||||||
|
@media (max-width 500px)
|
||||||
|
font-size 8px
|
||||||
|
|
||||||
|
> .thumbnail
|
||||||
|
height 70px
|
||||||
|
|
||||||
> article
|
> article
|
||||||
padding 8px
|
padding 8px
|
||||||
|
|
|
@ -1,37 +1,37 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mkw-calendar"
|
<div class="mkw-calendar" :data-special="special" :data-mobile="isMobile">
|
||||||
:data-melt="props.design == 1"
|
<mk-widget-container :naked="props.design == 1" :show-header="false">
|
||||||
:data-special="special"
|
<div class="mkw-calendar--body">
|
||||||
:data-mobile="isMobile"
|
<div class="calendar" :data-is-holiday="isHoliday">
|
||||||
>
|
<p class="month-and-year">
|
||||||
<div class="calendar" :data-is-holiday="isHoliday">
|
<span class="year">{{ year }}年</span>
|
||||||
<p class="month-and-year">
|
<span class="month">{{ month }}月</span>
|
||||||
<span class="year">{{ year }}年</span>
|
</p>
|
||||||
<span class="month">{{ month }}月</span>
|
<p class="day">{{ day }}日</p>
|
||||||
</p>
|
<p class="week-day">{{ weekDay }}曜日</p>
|
||||||
<p class="day">{{ day }}日</p>
|
</div>
|
||||||
<p class="week-day">{{ weekDay }}曜日</p>
|
<div class="info">
|
||||||
</div>
|
<div>
|
||||||
<div class="info">
|
<p>今日:<b>{{ dayP.toFixed(1) }}%</b></p>
|
||||||
<div>
|
<div class="meter">
|
||||||
<p>今日:<b>{{ dayP.toFixed(1) }}%</b></p>
|
<div class="val" :style="{ width: `${dayP}%` }"></div>
|
||||||
<div class="meter">
|
</div>
|
||||||
<div class="val" :style="{ width: `${dayP}%` }"></div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>今月:<b>{{ monthP.toFixed(1) }}%</b></p>
|
||||||
|
<div class="meter">
|
||||||
|
<div class="val" :style="{ width: `${monthP}%` }"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>今年:<b>{{ yearP.toFixed(1) }}%</b></p>
|
||||||
|
<div class="meter">
|
||||||
|
<div class="val" :style="{ width: `${yearP}%` }"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
</mk-widget-container>
|
||||||
<p>今月:<b>{{ monthP.toFixed(1) }}%</b></p>
|
|
||||||
<div class="meter">
|
|
||||||
<div class="val" :style="{ width: `${monthP}%` }"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>今年:<b>{{ yearP.toFixed(1) }}%</b></p>
|
|
||||||
<div class="meter">
|
|
||||||
<div class="val" :style="{ width: `${yearP}%` }"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -111,93 +111,82 @@ export default define({
|
||||||
@import '~const.styl'
|
@import '~const.styl'
|
||||||
|
|
||||||
root(isDark)
|
root(isDark)
|
||||||
padding 16px 0
|
|
||||||
color isDark ? #c5ced6 :#777
|
|
||||||
background isDark ? #282C37 : #fff
|
|
||||||
border solid 1px rgba(#000, 0.075)
|
|
||||||
border-radius 6px
|
|
||||||
|
|
||||||
&[data-special='on-new-years-day']
|
&[data-special='on-new-years-day']
|
||||||
border-color #ef95a0
|
border-color #ef95a0
|
||||||
|
|
||||||
&[data-melt]
|
.mkw-calendar--body
|
||||||
background transparent
|
padding 16px 0
|
||||||
border none
|
color isDark ? #c5ced6 : #777
|
||||||
|
|
||||||
&[data-mobile]
|
&:after
|
||||||
border none
|
content ""
|
||||||
border-radius 8px
|
display block
|
||||||
box-shadow 0 0 0 1px rgba(#000, 0.2)
|
clear both
|
||||||
|
|
||||||
&:after
|
> .calendar
|
||||||
content ""
|
float left
|
||||||
display block
|
width 60%
|
||||||
clear both
|
text-align center
|
||||||
|
|
||||||
> .calendar
|
&[data-is-holiday]
|
||||||
float left
|
> .day
|
||||||
width 60%
|
color #ef95a0
|
||||||
text-align center
|
|
||||||
|
|
||||||
&[data-is-holiday]
|
|
||||||
> .day
|
|
||||||
color #ef95a0
|
|
||||||
|
|
||||||
> p
|
|
||||||
margin 0
|
|
||||||
line-height 18px
|
|
||||||
font-size 14px
|
|
||||||
|
|
||||||
> span
|
|
||||||
margin 0 4px
|
|
||||||
|
|
||||||
> .day
|
|
||||||
margin 10px 0
|
|
||||||
line-height 32px
|
|
||||||
font-size 28px
|
|
||||||
|
|
||||||
> .info
|
|
||||||
display block
|
|
||||||
float left
|
|
||||||
width 40%
|
|
||||||
padding 0 16px 0 0
|
|
||||||
|
|
||||||
> div
|
|
||||||
margin-bottom 8px
|
|
||||||
|
|
||||||
&:last-child
|
|
||||||
margin-bottom 4px
|
|
||||||
|
|
||||||
> p
|
> p
|
||||||
margin 0 0 2px 0
|
margin 0
|
||||||
font-size 12px
|
|
||||||
line-height 18px
|
line-height 18px
|
||||||
color isDark ? #7a8692 : #888
|
font-size 14px
|
||||||
|
|
||||||
> b
|
> span
|
||||||
margin-left 2px
|
margin 0 4px
|
||||||
|
|
||||||
> .meter
|
> .day
|
||||||
width 100%
|
margin 10px 0
|
||||||
overflow hidden
|
line-height 32px
|
||||||
background isDark ? #1c1f25 : #eee
|
font-size 28px
|
||||||
border-radius 8px
|
|
||||||
|
|
||||||
> .val
|
> .info
|
||||||
height 4px
|
display block
|
||||||
background $theme-color
|
float left
|
||||||
|
width 40%
|
||||||
|
padding 0 16px 0 0
|
||||||
|
|
||||||
&:nth-child(1)
|
> div
|
||||||
> .meter > .val
|
margin-bottom 8px
|
||||||
background #f7796c
|
|
||||||
|
|
||||||
&:nth-child(2)
|
&:last-child
|
||||||
> .meter > .val
|
margin-bottom 4px
|
||||||
background #a1de41
|
|
||||||
|
|
||||||
&:nth-child(3)
|
> p
|
||||||
> .meter > .val
|
margin 0 0 2px 0
|
||||||
background #41ddde
|
font-size 12px
|
||||||
|
line-height 18px
|
||||||
|
color isDark ? #7a8692 : #888
|
||||||
|
|
||||||
|
> b
|
||||||
|
margin-left 2px
|
||||||
|
|
||||||
|
> .meter
|
||||||
|
width 100%
|
||||||
|
overflow hidden
|
||||||
|
background isDark ? #1c1f25 : #eee
|
||||||
|
border-radius 8px
|
||||||
|
|
||||||
|
> .val
|
||||||
|
height 4px
|
||||||
|
background $theme-color
|
||||||
|
|
||||||
|
&:nth-child(1)
|
||||||
|
> .meter > .val
|
||||||
|
background #f7796c
|
||||||
|
|
||||||
|
&:nth-child(2)
|
||||||
|
> .meter > .val
|
||||||
|
background #a1de41
|
||||||
|
|
||||||
|
&:nth-child(3)
|
||||||
|
> .meter > .val
|
||||||
|
background #41ddde
|
||||||
|
|
||||||
.mkw-calendar[data-darkmode]
|
.mkw-calendar[data-darkmode]
|
||||||
root(true)
|
root(true)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mkw-rss" :data-mobile="isMobile">
|
<div class="mkw-rss">
|
||||||
<mk-widget-container :show-header="!props.compact">
|
<mk-widget-container :show-header="!props.compact">
|
||||||
<template slot="header">%fa:rss-square%RSS</template>
|
<template slot="header">%fa:rss-square%RSS</template>
|
||||||
<button slot="func" title="設定" @click="setting">%fa:cog%</button>
|
<button slot="func" title="設定" @click="setting">%fa:cog%</button>
|
||||||
|
|
||||||
<div class="mkw-rss--body">
|
<div class="mkw-rss--body" :data-mobile="isMobile">
|
||||||
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:common.loading%<mk-ellipsis/></p>
|
||||||
<div class="feed" v-else>
|
<div class="feed" v-else>
|
||||||
<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a>
|
<a v-for="item in items" :href="item.link" target="_blank">{{ item.title }}</a>
|
||||||
|
@ -85,15 +85,17 @@ root(isDark)
|
||||||
margin-right 4px
|
margin-right 4px
|
||||||
|
|
||||||
&[data-mobile]
|
&[data-mobile]
|
||||||
|
background isDark ? #21242f : #f3f3f3
|
||||||
|
|
||||||
.feed
|
.feed
|
||||||
padding 0
|
padding 0
|
||||||
font-size 1em
|
|
||||||
|
|
||||||
> a
|
> a
|
||||||
padding 8px 16px
|
padding 8px 16px
|
||||||
|
border-bottom none
|
||||||
|
|
||||||
&:nth-child(even)
|
&:nth-child(even)
|
||||||
background rgba(#000, 0.05)
|
background isDark ? rgba(#000, 0.05) : rgba(#fff, 0.7)
|
||||||
|
|
||||||
.mkw-rss[data-darkmode]
|
.mkw-rss[data-darkmode]
|
||||||
root(true)
|
root(true)
|
||||||
|
|
|
@ -50,7 +50,7 @@ export default Vue.extend({
|
||||||
return `${this.file.name}\n${this.file.type} ${Vue.filter('bytes')(this.file.datasize)}`;
|
return `${this.file.name}\n${this.file.type} ${Vue.filter('bytes')(this.file.datasize)}`;
|
||||||
},
|
},
|
||||||
background(): string {
|
background(): string {
|
||||||
return this.file.properties.avgColor
|
return this.file.properties.avgColor && this.file.properties.avgColor.length == 3
|
||||||
? `rgb(${this.file.properties.avgColor.join(',')})`
|
? `rgb(${this.file.properties.avgColor.join(',')})`
|
||||||
: 'transparent';
|
: 'transparent';
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
onThumbnailLoaded() {
|
onThumbnailLoaded() {
|
||||||
if (this.file.properties.avgColor) {
|
if (this.file.properties.avgColor && this.file.properties.avgColor.length == 3) {
|
||||||
anime({
|
anime({
|
||||||
targets: this.$refs.thumbnail,
|
targets: this.$refs.thumbnail,
|
||||||
backgroundColor: `rgba(${this.file.properties.avgColor.join(',')}, 0)`,
|
backgroundColor: `rgba(${this.file.properties.avgColor.join(',')}, 0)`,
|
||||||
|
|
|
@ -1,34 +1,34 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mk-home" :data-customize="customize">
|
<div class="mk-home" :data-customize="customize">
|
||||||
<div class="customize" v-if="customize">
|
<div class="customize" v-if="customize">
|
||||||
<router-link to="/">%fa:check%完了</router-link>
|
<router-link to="/">%fa:check%%i18n:@done%</router-link>
|
||||||
<div>
|
<div>
|
||||||
<div class="adder">
|
<div class="adder">
|
||||||
<p>ウィジェットを追加:</p>
|
<p>%i18n:@add-widget%</p>
|
||||||
<select v-model="widgetAdderSelected">
|
<select v-model="widgetAdderSelected">
|
||||||
<option value="profile">プロフィール</option>
|
<option value="profile">%i18n:@profile%</option>
|
||||||
<option value="calendar">カレンダー</option>
|
<option value="calendar">%i18n:@calendar%</option>
|
||||||
<option value="timemachine">カレンダー(タイムマシン)</option>
|
<option value="timemachine">%i18n:@timemachine%</option>
|
||||||
<option value="activity">アクティビティ</option>
|
<option value="activity">%i18n:@activity%</option>
|
||||||
<option value="rss">RSSリーダー</option>
|
<option value="rss">%i18n:@rss%</option>
|
||||||
<option value="trends">トレンド</option>
|
<option value="trends">%i18n:@trends%</option>
|
||||||
<option value="photo-stream">フォトストリーム</option>
|
<option value="photo-stream">%i18n:@photo-stream%</option>
|
||||||
<option value="slideshow">スライドショー</option>
|
<option value="slideshow">%i18n:@slideshow%</option>
|
||||||
<option value="version">バージョン</option>
|
<option value="version">%i18n:@version%</option>
|
||||||
<option value="broadcast">ブロードキャスト</option>
|
<option value="broadcast">%i18n:@broadcast%</option>
|
||||||
<option value="notifications">通知</option>
|
<option value="notifications">%i18n:@notifications%</option>
|
||||||
<option value="users">おすすめユーザー</option>
|
<option value="users">%i18n:@users%</option>
|
||||||
<option value="polls">投票</option>
|
<option value="polls">%i18n:@polls%</option>
|
||||||
<option value="post-form">投稿フォーム</option>
|
<option value="post-form">%i18n:@post-form%</option>
|
||||||
<option value="messaging">メッセージ</option>
|
<option value="messaging">%i18n:@messaging%</option>
|
||||||
<option value="channel">チャンネル</option>
|
<option value="channel">%i18n:@channel%</option>
|
||||||
<option value="access-log">アクセスログ</option>
|
<option value="access-log">%i18n:@access-log%</option>
|
||||||
<option value="server">サーバー情報</option>
|
<option value="server">%i18n:@server%</option>
|
||||||
<option value="donation">寄付のお願い</option>
|
<option value="donation">%i18n:@donation%</option>
|
||||||
<option value="nav">ナビゲーション</option>
|
<option value="nav">%i18n:@nav%</option>
|
||||||
<option value="tips">ヒント</option>
|
<option value="tips">%i18n:@tips%</option>
|
||||||
</select>
|
</select>
|
||||||
<button @click="addWidget">追加</button>
|
<button @click="addWidget">%i18n:@add%</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="trash">
|
<div class="trash">
|
||||||
<x-draggable v-model="trash" :options="{ group: 'x' }" @add="onTrash"></x-draggable>
|
<x-draggable v-model="trash" :options="{ group: 'x' }" @add="onTrash"></x-draggable>
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default Vue.extend({
|
||||||
computed: {
|
computed: {
|
||||||
style(): any {
|
style(): any {
|
||||||
return {
|
return {
|
||||||
'background-color': this.image.properties.avgColor ? `rgb(${this.image.properties.avgColor.join(',')})` : 'transparent',
|
'background-color': this.image.properties.avgColor && this.image.properties.avgColor.length == 3 ? `rgb(${this.image.properties.avgColor.join(',')})` : 'transparent',
|
||||||
'background-image': this.raw ? `url(${this.image.url})` : `url(${this.image.url}?thumbnail&size=512)`
|
'background-image': this.raw ? `url(${this.image.url})` : `url(${this.image.url}?thumbnail&size=512)`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<header>
|
<header>
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
|
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
|
||||||
<span class="username">@{{ note.user | acct }}</span>
|
<span class="username"><mk-acct :user="note.user"/></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<router-link class="time" :to="note | notePage">
|
<router-link class="time" :to="note | notePage">
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<mk-avatar class="avatar" :user="p.user"/>
|
<mk-avatar class="avatar" :user="p.user"/>
|
||||||
<header>
|
<header>
|
||||||
<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link>
|
<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link>
|
||||||
<span class="username">@{{ p.user | acct }}</span>
|
<span class="username"><mk-acct :user="p.user"/></span>
|
||||||
<router-link class="time" :to="p | notePage">
|
<router-link class="time" :to="p | notePage">
|
||||||
<mk-time :time="p.createdAt"/>
|
<mk-time :time="p.createdAt"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<header>
|
||||||
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
|
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
|
||||||
<span class="username">@{{ note.user | acct }}</span>
|
<span class="username"><mk-acct :user="note.user"/></span>
|
||||||
<router-link class="time" :to="note | notePage">
|
<router-link class="time" :to="note | notePage">
|
||||||
<mk-time :time="note.createdAt"/>
|
<mk-time :time="note.createdAt"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
@ -59,17 +59,20 @@ root(isDark)
|
||||||
> .name
|
> .name
|
||||||
margin 0 .5em 0 0
|
margin 0 .5em 0 0
|
||||||
padding 0
|
padding 0
|
||||||
|
overflow hidden
|
||||||
color isDark ? #fff : #607073
|
color isDark ? #fff : #607073
|
||||||
font-size 1em
|
font-size 1em
|
||||||
font-weight bold
|
font-weight bold
|
||||||
text-decoration none
|
text-decoration none
|
||||||
white-space normal
|
text-overflow ellipsis
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
text-decoration underline
|
text-decoration underline
|
||||||
|
|
||||||
> .username
|
> .username
|
||||||
margin 0 .5em 0 0
|
margin 0 .5em 0 0
|
||||||
|
overflow hidden
|
||||||
|
text-overflow ellipsis
|
||||||
color isDark ? #606984 : #d1d8da
|
color isDark ? #606984 : #d1d8da
|
||||||
|
|
||||||
> .time
|
> .time
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<header>
|
<header>
|
||||||
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
|
<router-link class="name" :to="note.user | userPage" v-user-preview="note.userId">{{ note.user | userName }}</router-link>
|
||||||
<span class="username">@{{ note.user | acct }}</span>
|
<span class="username"><mk-acct :user="note.user"/></span>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
|
<span class="mobile" v-if="note.viaMobile">%fa:mobile-alt%</span>
|
||||||
<router-link class="created-at" :to="note | notePage">
|
<router-link class="created-at" :to="note | notePage">
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
<header>
|
<header>
|
||||||
<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link>
|
<router-link class="name" :to="p.user | userPage" v-user-preview="p.user.id">{{ p.user | userName }}</router-link>
|
||||||
<span class="is-bot" v-if="p.user.host === null && p.user.isBot">bot</span>
|
<span class="is-bot" v-if="p.user.host === null && p.user.isBot">bot</span>
|
||||||
<span class="username">@{{ p.user | acct }}</span>
|
<span class="username"><mk-acct :user="p.user"/></span>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
<span class="app" v-if="p.app">via <b>{{ p.app.name }}</b></span>
|
||||||
<span class="mobile" v-if="p.viaMobile">%fa:mobile-alt%</span>
|
<span class="mobile" v-if="p.viaMobile">%fa:mobile-alt%</span>
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
|
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
|
||||||
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
||||||
<mk-note-html v-if="p.text" :text="p.text" :i="os.i" :class="$style.text"/>
|
<mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="os.i" :class="$style.text"/>
|
||||||
<a class="rp" v-if="p.renote">RP:</a>
|
<a class="rp" v-if="p.renote">RP:</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="media" v-if="p.media.length > 0">
|
<div class="media" v-if="p.media.length > 0">
|
||||||
|
@ -94,6 +94,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import dateStringify from '../../../common/scripts/date-stringify';
|
import dateStringify from '../../../common/scripts/date-stringify';
|
||||||
|
import canHideText from '../../../common/scripts/can-hide-text';
|
||||||
import parse from '../../../../../text/parse';
|
import parse from '../../../../../text/parse';
|
||||||
|
|
||||||
import MkPostFormWindow from './post-form-window.vue';
|
import MkPostFormWindow from './post-form-window.vue';
|
||||||
|
@ -130,16 +131,17 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
|
||||||
isRenote(): boolean {
|
isRenote(): boolean {
|
||||||
return (this.note.renote &&
|
return (this.note.renote &&
|
||||||
this.note.text == null &&
|
this.note.text == null &&
|
||||||
this.note.mediaIds.length == 0 &&
|
this.note.mediaIds.length == 0 &&
|
||||||
this.note.poll == null);
|
this.note.poll == null);
|
||||||
},
|
},
|
||||||
|
|
||||||
p(): any {
|
p(): any {
|
||||||
return this.isRenote ? this.note.renote : this.note;
|
return this.isRenote ? this.note.renote : this.note;
|
||||||
},
|
},
|
||||||
|
|
||||||
reactionsCount(): number {
|
reactionsCount(): number {
|
||||||
return this.p.reactionCounts
|
return this.p.reactionCounts
|
||||||
? Object.keys(this.p.reactionCounts)
|
? Object.keys(this.p.reactionCounts)
|
||||||
|
@ -147,9 +149,11 @@ export default Vue.extend({
|
||||||
.reduce((a, b) => a + b)
|
.reduce((a, b) => a + b)
|
||||||
: 0;
|
: 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
title(): string {
|
title(): string {
|
||||||
return dateStringify(this.p.createdAt);
|
return dateStringify(this.p.createdAt);
|
||||||
},
|
},
|
||||||
|
|
||||||
urls(): string[] {
|
urls(): string[] {
|
||||||
if (this.p.text) {
|
if (this.p.text) {
|
||||||
const ast = parse(this.p.text);
|
const ast = parse(this.p.text);
|
||||||
|
@ -205,6 +209,8 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
canHideText,
|
||||||
|
|
||||||
capture(withHandler = false) {
|
capture(withHandler = false) {
|
||||||
if ((this as any).os.isSignedIn) {
|
if ((this as any).os.isSignedIn) {
|
||||||
this.connection.send({
|
this.connection.send({
|
||||||
|
@ -214,6 +220,7 @@ export default Vue.extend({
|
||||||
if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
|
if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
decapture(withHandler = false) {
|
decapture(withHandler = false) {
|
||||||
if ((this as any).os.isSignedIn) {
|
if ((this as any).os.isSignedIn) {
|
||||||
this.connection.send({
|
this.connection.send({
|
||||||
|
@ -223,9 +230,11 @@ export default Vue.extend({
|
||||||
if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
|
if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onStreamConnected() {
|
onStreamConnected() {
|
||||||
this.capture();
|
this.capture();
|
||||||
},
|
},
|
||||||
|
|
||||||
onStreamNoteUpdated(data) {
|
onStreamNoteUpdated(data) {
|
||||||
const note = data.note;
|
const note = data.note;
|
||||||
if (note.id == this.note.id) {
|
if (note.id == this.note.id) {
|
||||||
|
@ -234,28 +243,33 @@ export default Vue.extend({
|
||||||
this.note.renote = note;
|
this.note.renote = note;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
reply() {
|
reply() {
|
||||||
(this as any).os.new(MkPostFormWindow, {
|
(this as any).os.new(MkPostFormWindow, {
|
||||||
reply: this.p
|
reply: this.p
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
renote() {
|
renote() {
|
||||||
(this as any).os.new(MkRenoteFormWindow, {
|
(this as any).os.new(MkRenoteFormWindow, {
|
||||||
note: this.p
|
note: this.p
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
react() {
|
react() {
|
||||||
(this as any).os.new(MkReactionPicker, {
|
(this as any).os.new(MkReactionPicker, {
|
||||||
source: this.$refs.reactButton,
|
source: this.$refs.reactButton,
|
||||||
note: this.p
|
note: this.p
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
menu() {
|
menu() {
|
||||||
(this as any).os.new(MkNoteMenu, {
|
(this as any).os.new(MkNoteMenu, {
|
||||||
source: this.$refs.menuButton,
|
source: this.$refs.menuButton,
|
||||||
note: this.p
|
note: this.p
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onKeydown(e) {
|
onKeydown(e) {
|
||||||
let shouldBeCancel = true;
|
let shouldBeCancel = true;
|
||||||
|
|
||||||
|
@ -336,6 +350,7 @@ root(isDark)
|
||||||
align-items center
|
align-items center
|
||||||
padding 16px 32px
|
padding 16px 32px
|
||||||
line-height 28px
|
line-height 28px
|
||||||
|
white-space pre
|
||||||
color #9dbb00
|
color #9dbb00
|
||||||
background isDark ? linear-gradient(to bottom, #314027 0%, #282c37 100%) : linear-gradient(to bottom, #edfde2 0%, #fff 100%)
|
background isDark ? linear-gradient(to bottom, #314027 0%, #282c37 100%) : linear-gradient(to bottom, #edfde2 0%, #fff 100%)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="root api">
|
<div class="root api">
|
||||||
<p>Token: <code>{{ os.i.token }}</code></p>
|
<p>%i18n:@token% <code>{{ os.i.token }}</code></p>
|
||||||
<p>%i18n:@intro%</p>
|
<p>%i18n:@intro%</p>
|
||||||
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
|
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
|
||||||
<p>%i18n:@regeneration-of-token%</p>
|
<p>%i18n:@regeneration-of-token%</p>
|
||||||
|
|
|
@ -80,10 +80,11 @@
|
||||||
<el-option label="自動" value=""/>
|
<el-option label="自動" value=""/>
|
||||||
</el-option-group>
|
</el-option-group>
|
||||||
<el-option-group label="言語を指定">
|
<el-option-group label="言語を指定">
|
||||||
<el-option label="ja-JP" value="ja"/>
|
<el-option label="ja" value="ja"/>
|
||||||
<el-option label="en-US" value="en"/>
|
<el-option label="en" value="en"/>
|
||||||
<el-option label="fr" value="fr"/>
|
<el-option label="fr" value="fr"/>
|
||||||
<el-option label="pl" value="pl"/>
|
<el-option label="pl" value="pl"/>
|
||||||
|
<el-option label="de" value="de"/>
|
||||||
</el-option-group>
|
</el-option-group>
|
||||||
</el-select>
|
</el-select>
|
||||||
<div class="none ui info">
|
<div class="none ui info">
|
||||||
|
@ -100,7 +101,7 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="notification" v-show="page == 'notification'">
|
<section class="notification" v-show="page == 'notification'">
|
||||||
<h1>通知</h1>
|
<h1>%i18n:@notification%</h1>
|
||||||
<mk-switch v-model="os.i.settings.autoWatch" @change="onChangeAutoWatch" text="投稿の自動ウォッチ">
|
<mk-switch v-model="os.i.settings.autoWatch" @change="onChangeAutoWatch" text="投稿の自動ウォッチ">
|
||||||
<span>リアクションしたり返信したりした投稿に関する通知を自動的に受け取るようにします。</span>
|
<span>リアクションしたり返信したりした投稿に関する通知を自動的に受け取るようにします。</span>
|
||||||
</mk-switch>
|
</mk-switch>
|
||||||
|
@ -117,7 +118,7 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="apps" v-show="page == 'apps'">
|
<section class="apps" v-show="page == 'apps'">
|
||||||
<h1>アプリケーション</h1>
|
<h1>%i18n:@apps%</h1>
|
||||||
<x-apps/>
|
<x-apps/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="signin" v-show="page == 'security'">
|
<section class="signin" v-show="page == 'security'">
|
||||||
<h1>サインイン履歴</h1>
|
<h1>%i18n:@signin%</h1>
|
||||||
<x-signins/>
|
<x-signins/>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<span slot="header">%fa:list% リスト</span>
|
<span slot="header">%fa:list% リスト</span>
|
||||||
|
|
||||||
<div data-id="6e4caea3-d8f9-4ab7-96de-ab67fe8d5c82" :data-darkmode="_darkmode_">
|
<div data-id="6e4caea3-d8f9-4ab7-96de-ab67fe8d5c82" :data-darkmode="_darkmode_">
|
||||||
<button class="ui" @click="add">リストを作成</button>
|
<button class="ui" @click="add">%i18n:@create-list%</button>
|
||||||
<a v-for="list in lists" :key="list.id" @click="choice(list)">{{ list.title }}</a>
|
<a v-for="list in lists" :key="list.id" @click="choice(list)">{{ list.title }}</a>
|
||||||
</div>
|
</div>
|
||||||
</mk-window>
|
</mk-window>
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
<div class="description">{{ u.description }}</div>
|
<div class="description">{{ u.description }}</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<div>
|
<div>
|
||||||
<p>投稿</p><a>{{ u.notesCount }}</a>
|
<p>%i18n:@notes%</p><a>{{ u.notesCount }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p>フォロー</p><a>{{ u.followingCount }}</a>
|
<p>%i18n:@following%</p><a>{{ u.followingCount }}</a>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<p>フォロワー</p><a>{{ u.followersCount }}</a>
|
<p>%i18n:@followers%</p><a>{{ u.followersCount }}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<mk-follow-button v-if="os.isSignedIn && user.id != os.i.id" :user="u"/>
|
<mk-follow-button v-if="os.isSignedIn && user.id != os.i.id" :user="u"/>
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
<div class="mk-users-list">
|
<div class="mk-users-list">
|
||||||
<nav>
|
<nav>
|
||||||
<div>
|
<div>
|
||||||
<span :data-active="mode == 'all'" @click="mode = 'all'">すべて<span>{{ count }}</span></span>
|
<span :data-active="mode == 'all'" @click="mode = 'all'">%i18n:@all%<span>{{ count }}</span></span>
|
||||||
<span v-if="os.isSignedIn && youKnowCount" :data-active="mode == 'iknow'" @click="mode = 'iknow'">知り合い<span>{{ youKnowCount }}</span></span>
|
<span v-if="os.isSignedIn && youKnowCount" :data-active="mode == 'iknow'" @click="mode = 'iknow'">%i18n:@iknow%<span>{{ youKnowCount }}</span></span>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="users" v-if="!fetching && users.length != 0">
|
<div class="users" v-if="!fetching && users.length != 0">
|
||||||
|
@ -12,13 +12,13 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="more" v-if="!fetching && next != null" @click="more" :disabled="moreFetching">
|
<button class="more" v-if="!fetching && next != null" @click="more" :disabled="moreFetching">
|
||||||
<span v-if="!moreFetching">もっと</span>
|
<span v-if="!moreFetching">%i18n:@load-more%</span>
|
||||||
<span v-if="moreFetching">読み込み中<mk-ellipsis/></span>
|
<span v-if="moreFetching">%i18n:common.loading%<mk-ellipsis/></span>
|
||||||
</button>
|
</button>
|
||||||
<p class="no" v-if="!fetching && users.length == 0">
|
<p class="no" v-if="!fetching && users.length == 0">
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</p>
|
</p>
|
||||||
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%読み込んでいます<mk-ellipsis/></p>
|
<p class="fetching" v-if="fetching">%fa:spinner .pulse .fw%%i18n:@fetching%<mk-ellipsis/></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default Vue.extend({
|
||||||
style(): any {
|
style(): any {
|
||||||
if (this.user.bannerUrl == null) return {};
|
if (this.user.bannerUrl == null) return {};
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.user.bannerColor ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
||||||
backgroundImage: `url(${ this.user.bannerUrl })`
|
backgroundImage: `url(${ this.user.bannerUrl })`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,24 @@
|
||||||
import PostForm from '../views/components/post-form.vue';
|
import PostForm from '../views/components/post-form.vue';
|
||||||
//import RenoteForm from '../views/components/renote-form.vue';
|
|
||||||
import getNoteSummary from '../../../../renderers/get-note-summary';
|
|
||||||
|
|
||||||
export default (os) => (opts) => {
|
export default (os) => (opts) => {
|
||||||
const o = opts || {};
|
const o = opts || {};
|
||||||
|
|
||||||
if (o.renote) {
|
const app = document.getElementById('app');
|
||||||
/*const vm = new RenoteForm({
|
app.style.display = 'none';
|
||||||
propsData: {
|
|
||||||
renote: o.renote
|
|
||||||
}
|
|
||||||
}).$mount();
|
|
||||||
vm.$once('cancel', recover);
|
|
||||||
vm.$once('note', recover);
|
|
||||||
document.body.appendChild(vm.$el);*/
|
|
||||||
|
|
||||||
const text = window.prompt(`「${getNoteSummary(o.renote)}」をRenote`);
|
function recover() {
|
||||||
if (text == null) return;
|
app.style.display = 'block';
|
||||||
os.api('notes/create', {
|
|
||||||
renoteId: o.renote.id,
|
|
||||||
text: text == '' ? undefined : text
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const app = document.getElementById('app');
|
|
||||||
app.style.display = 'none';
|
|
||||||
|
|
||||||
function recover() {
|
|
||||||
app.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
const vm = new PostForm({
|
|
||||||
parent: os.app,
|
|
||||||
propsData: {
|
|
||||||
reply: o.reply
|
|
||||||
}
|
|
||||||
}).$mount();
|
|
||||||
vm.$once('cancel', recover);
|
|
||||||
vm.$once('note', recover);
|
|
||||||
document.body.appendChild(vm.$el);
|
|
||||||
(vm as any).focus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const vm = new PostForm({
|
||||||
|
parent: os.app,
|
||||||
|
propsData: {
|
||||||
|
reply: o.reply,
|
||||||
|
renote: o.renote
|
||||||
|
}
|
||||||
|
}).$mount();
|
||||||
|
vm.$once('cancel', recover);
|
||||||
|
vm.$once('note', recover);
|
||||||
|
document.body.appendChild(vm.$el);
|
||||||
|
(vm as any).focus();
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,7 @@ import MkUser from './views/pages/user.vue';
|
||||||
import MkSelectDrive from './views/pages/selectdrive.vue';
|
import MkSelectDrive from './views/pages/selectdrive.vue';
|
||||||
import MkDrive from './views/pages/drive.vue';
|
import MkDrive from './views/pages/drive.vue';
|
||||||
import MkNotifications from './views/pages/notifications.vue';
|
import MkNotifications from './views/pages/notifications.vue';
|
||||||
|
import MkWidgets from './views/pages/widgets.vue';
|
||||||
import MkMessaging from './views/pages/messaging.vue';
|
import MkMessaging from './views/pages/messaging.vue';
|
||||||
import MkMessagingRoom from './views/pages/messaging-room.vue';
|
import MkMessagingRoom from './views/pages/messaging-room.vue';
|
||||||
import MkNote from './views/pages/note.vue';
|
import MkNote from './views/pages/note.vue';
|
||||||
|
@ -56,6 +57,7 @@ init((launch) => {
|
||||||
{ path: '/i/settings', component: MkSettings },
|
{ path: '/i/settings', component: MkSettings },
|
||||||
{ path: '/i/settings/profile', component: MkProfileSetting },
|
{ path: '/i/settings/profile', component: MkProfileSetting },
|
||||||
{ path: '/i/notifications', name: 'notifications', component: MkNotifications },
|
{ path: '/i/notifications', name: 'notifications', component: MkNotifications },
|
||||||
|
{ path: '/i/widgets', name: 'widgets', component: MkWidgets },
|
||||||
{ path: '/i/messaging', name: 'messaging', component: MkMessaging },
|
{ path: '/i/messaging', name: 'messaging', component: MkMessaging },
|
||||||
{ path: '/i/messaging/:user', component: MkMessagingRoom },
|
{ path: '/i/messaging/:user', component: MkMessagingRoom },
|
||||||
{ path: '/i/drive', name: 'drive', component: MkDrive },
|
{ path: '/i/drive', name: 'drive', component: MkDrive },
|
||||||
|
|
|
@ -86,7 +86,7 @@ export default Vue.extend({
|
||||||
return this.file.type.split('/')[0];
|
return this.file.type.split('/')[0];
|
||||||
},
|
},
|
||||||
style(): any {
|
style(): any {
|
||||||
return this.file.properties.avgColor ? {
|
return this.file.properties.avgColor && this.file.properties.avgColor.length == 3 ? {
|
||||||
'background-color': `rgb(${ this.file.properties.avgColor.join(',') })`
|
'background-color': `rgb(${ this.file.properties.avgColor.join(',') })`
|
||||||
} : {};
|
} : {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
thumbnail(): any {
|
thumbnail(): any {
|
||||||
return {
|
return {
|
||||||
'background-color': this.file.properties.avgColor ? `rgb(${this.file.properties.avgColor.join(',')})` : 'transparent',
|
'background-color': this.file.properties.avgColor && this.file.properties.avgColor.length == 3 ? `rgb(${this.file.properties.avgColor.join(',')})` : 'transparent',
|
||||||
'background-image': `url(${this.file.url}?thumbnail&size=128)`
|
'background-image': `url(${this.file.url}?thumbnail&size=128)`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ export default Vue.extend({
|
||||||
computed: {
|
computed: {
|
||||||
style(): any {
|
style(): any {
|
||||||
return {
|
return {
|
||||||
'background-color': this.image.properties.avgColor ? `rgb(${this.image.properties.avgColor.join(',')})` : 'transparent',
|
'background-color': this.image.properties.avgColor && this.image.properties.avgColor.length == 3 ? `rgb(${this.image.properties.avgColor.join(',')})` : 'transparent',
|
||||||
'background-image': this.raw ? `url(${this.image.url})` : `url(${this.image.url}?thumbnail&size=512)`
|
'background-image': this.raw ? `url(${this.image.url})` : `url(${this.image.url}?thumbnail&size=512)`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,9 @@ root(isDark)
|
||||||
text-decoration underline
|
text-decoration underline
|
||||||
|
|
||||||
> .username
|
> .username
|
||||||
text-align left
|
|
||||||
margin 0 .5em 0 0
|
margin 0 .5em 0 0
|
||||||
|
overflow hidden
|
||||||
|
text-overflow ellipsis
|
||||||
color isDark ? #606984 : #d1d8da
|
color isDark ? #606984 : #d1d8da
|
||||||
|
|
||||||
> .time
|
> .time
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
|
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
|
||||||
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
<a class="reply" v-if="p.reply">%fa:reply%</a>
|
||||||
<mk-note-html v-if="p.text" :text="p.text" :i="os.i" :class="$style.text"/>
|
<mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="os.i" :class="$style.text"/>
|
||||||
<a class="rp" v-if="p.renote != null">RP:</a>
|
<a class="rp" v-if="p.renote != null">RP:</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="media" v-if="p.media.length > 0">
|
<div class="media" v-if="p.media.length > 0">
|
||||||
|
@ -85,6 +85,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import parse from '../../../../../text/parse';
|
import parse from '../../../../../text/parse';
|
||||||
|
import canHideText from '../../../common/scripts/can-hide-text';
|
||||||
|
|
||||||
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
|
import MkNoteMenu from '../../../common/views/components/note-menu.vue';
|
||||||
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
|
import MkReactionPicker from '../../../common/views/components/reaction-picker.vue';
|
||||||
|
@ -112,9 +113,11 @@ export default Vue.extend({
|
||||||
this.note.mediaIds.length == 0 &&
|
this.note.mediaIds.length == 0 &&
|
||||||
this.note.poll == null);
|
this.note.poll == null);
|
||||||
},
|
},
|
||||||
|
|
||||||
p(): any {
|
p(): any {
|
||||||
return this.isRenote ? this.note.renote : this.note;
|
return this.isRenote ? this.note.renote : this.note;
|
||||||
},
|
},
|
||||||
|
|
||||||
reactionsCount(): number {
|
reactionsCount(): number {
|
||||||
return this.p.reactionCounts
|
return this.p.reactionCounts
|
||||||
? Object.keys(this.p.reactionCounts)
|
? Object.keys(this.p.reactionCounts)
|
||||||
|
@ -122,6 +125,7 @@ export default Vue.extend({
|
||||||
.reduce((a, b) => a + b)
|
.reduce((a, b) => a + b)
|
||||||
: 0;
|
: 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
urls(): string[] {
|
urls(): string[] {
|
||||||
if (this.p.text) {
|
if (this.p.text) {
|
||||||
const ast = parse(this.p.text);
|
const ast = parse(this.p.text);
|
||||||
|
@ -177,6 +181,8 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
canHideText,
|
||||||
|
|
||||||
capture(withHandler = false) {
|
capture(withHandler = false) {
|
||||||
if ((this as any).os.isSignedIn) {
|
if ((this as any).os.isSignedIn) {
|
||||||
this.connection.send({
|
this.connection.send({
|
||||||
|
@ -186,6 +192,7 @@ export default Vue.extend({
|
||||||
if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
|
if (withHandler) this.connection.on('note-updated', this.onStreamNoteUpdated);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
decapture(withHandler = false) {
|
decapture(withHandler = false) {
|
||||||
if ((this as any).os.isSignedIn) {
|
if ((this as any).os.isSignedIn) {
|
||||||
this.connection.send({
|
this.connection.send({
|
||||||
|
@ -195,9 +202,11 @@ export default Vue.extend({
|
||||||
if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
|
if (withHandler) this.connection.off('note-updated', this.onStreamNoteUpdated);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onStreamConnected() {
|
onStreamConnected() {
|
||||||
this.capture();
|
this.capture();
|
||||||
},
|
},
|
||||||
|
|
||||||
onStreamNoteUpdated(data) {
|
onStreamNoteUpdated(data) {
|
||||||
const note = data.note;
|
const note = data.note;
|
||||||
if (note.id == this.note.id) {
|
if (note.id == this.note.id) {
|
||||||
|
@ -206,16 +215,19 @@ export default Vue.extend({
|
||||||
this.note.renote = note;
|
this.note.renote = note;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
reply() {
|
reply() {
|
||||||
(this as any).apis.post({
|
(this as any).apis.post({
|
||||||
reply: this.p
|
reply: this.p
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
renote() {
|
renote() {
|
||||||
(this as any).apis.post({
|
(this as any).apis.post({
|
||||||
renote: this.p
|
renote: this.p
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
react() {
|
react() {
|
||||||
(this as any).os.new(MkReactionPicker, {
|
(this as any).os.new(MkReactionPicker, {
|
||||||
source: this.$refs.reactButton,
|
source: this.$refs.reactButton,
|
||||||
|
@ -223,6 +235,7 @@ export default Vue.extend({
|
||||||
compact: true
|
compact: true
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
menu() {
|
menu() {
|
||||||
(this as any).os.new(MkNoteMenu, {
|
(this as any).os.new(MkNoteMenu, {
|
||||||
source: this.$refs.menuButton,
|
source: this.$refs.menuButton,
|
||||||
|
@ -255,6 +268,7 @@ root(isDark)
|
||||||
align-items center
|
align-items center
|
||||||
padding 8px 16px
|
padding 8px 16px
|
||||||
line-height 28px
|
line-height 28px
|
||||||
|
white-space pre
|
||||||
color #9dbb00
|
color #9dbb00
|
||||||
background isDark ? linear-gradient(to bottom, #314027 0%, #282c37 100%) : linear-gradient(to bottom, #edfde2 0%, #fff 100%)
|
background isDark ? linear-gradient(to bottom, #314027 0%, #282c37 100%) : linear-gradient(to bottom, #edfde2 0%, #fff 100%)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="mk-notes">
|
<div class="mk-notes">
|
||||||
<div class="newer-indicator" :style="{ top: $store.state.uiHeaderHeight + 'px' }" v-show="queue.length > 0"></div>
|
|
||||||
|
|
||||||
<slot name="head"></slot>
|
<slot name="head"></slot>
|
||||||
|
|
||||||
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
|
<slot name="empty" v-if="notes.length == 0 && !fetching && requestInitPromise == null"></slot>
|
||||||
|
@ -71,6 +69,16 @@ export default Vue.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
queue(x) {
|
||||||
|
if (x.length > 0) {
|
||||||
|
this.$store.commit('indicate', true);
|
||||||
|
} else {
|
||||||
|
this.$store.commit('indicate', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
document.addEventListener('visibilitychange', this.onVisibilitychange, false);
|
document.addEventListener('visibilitychange', this.onVisibilitychange, false);
|
||||||
window.addEventListener('scroll', this.onScroll);
|
window.addEventListener('scroll', this.onScroll);
|
||||||
|
@ -238,13 +246,6 @@ root(isDark)
|
||||||
[data-fa]
|
[data-fa]
|
||||||
margin-right 8px
|
margin-right 8px
|
||||||
|
|
||||||
> .newer-indicator
|
|
||||||
position -webkit-sticky
|
|
||||||
position sticky
|
|
||||||
z-index 100
|
|
||||||
height 3px
|
|
||||||
background $theme-color
|
|
||||||
|
|
||||||
> .init
|
> .init
|
||||||
padding 64px 0
|
padding 64px 0
|
||||||
text-align center
|
text-align center
|
||||||
|
|
|
@ -5,17 +5,22 @@
|
||||||
<div>
|
<div>
|
||||||
<span class="text-count" :class="{ over: text.length > 1000 }">{{ 1000 - text.length }}</span>
|
<span class="text-count" :class="{ over: text.length > 1000 }">{{ 1000 - text.length }}</span>
|
||||||
<span class="geo" v-if="geo">%fa:map-marker-alt%</span>
|
<span class="geo" v-if="geo">%fa:map-marker-alt%</span>
|
||||||
<button class="submit" :disabled="posting" @click="post">{{ reply ? '返信' : '%i18n:!@submit%' }}</button>
|
<button class="submit" :disabled="posting" @click="post">
|
||||||
|
<template v-if="reply">%i18n:@reply%</template>
|
||||||
|
<template v-else-if="renote">%i18n:@renote%</template>
|
||||||
|
<template v-else>%i18n:@submit%</template>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<mk-note-preview v-if="reply" :note="reply"/>
|
<mk-note-preview v-if="reply" :note="reply"/>
|
||||||
|
<mk-note-preview v-if="renote" :note="renote"/>
|
||||||
<div v-if="visibility == 'specified'" class="visibleUsers">
|
<div v-if="visibility == 'specified'" class="visibleUsers">
|
||||||
<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span>
|
<span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span>
|
||||||
<a @click="addVisibleUser">+ユーザーを追加</a>
|
<a @click="addVisibleUser">+ユーザーを追加</a>
|
||||||
</div>
|
</div>
|
||||||
<input v-show="useCw" v-model="cw" placeholder="内容への注釈 (オプション)">
|
<input v-show="useCw" v-model="cw" placeholder="内容への注釈 (オプション)">
|
||||||
<textarea v-model="text" ref="text" :disabled="posting" :placeholder="reply ? '%i18n:!@reply-placeholder%' : '%i18n:!@note-placeholder%'"></textarea>
|
<textarea v-model="text" ref="text" :disabled="posting" :placeholder="reply ? '%i18n:!@reply-placeholder%' : renote ? '%i18n:!@renote-placeholder%' : '%i18n:!@note-placeholder%'"></textarea>
|
||||||
<div class="attaches" v-show="files.length != 0">
|
<div class="attaches" v-show="files.length != 0">
|
||||||
<x-draggable class="files" :list="files" :options="{ animation: 150 }">
|
<x-draggable class="files" :list="files" :options="{ animation: 150 }">
|
||||||
<div class="file" v-for="file in files" :key="file.id">
|
<div class="file" v-for="file in files" :key="file.id">
|
||||||
|
@ -51,7 +56,7 @@ export default Vue.extend({
|
||||||
MkVisibilityChooser
|
MkVisibilityChooser
|
||||||
},
|
},
|
||||||
|
|
||||||
props: ['reply'],
|
props: ['reply', 'renote'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -177,6 +182,7 @@ export default Vue.extend({
|
||||||
text: this.text == '' ? undefined : this.text,
|
text: this.text == '' ? undefined : this.text,
|
||||||
mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
|
mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,
|
||||||
replyId: this.reply ? this.reply.id : undefined,
|
replyId: this.reply ? this.reply.id : undefined,
|
||||||
|
renoteId: this.renote ? this.renote.id : undefined,
|
||||||
poll: this.poll ? (this.$refs.poll as any).get() : undefined,
|
poll: this.poll ? (this.$refs.poll as any).get() : undefined,
|
||||||
cw: this.useCw ? this.cw || '' : undefined,
|
cw: this.useCw ? this.cw || '' : undefined,
|
||||||
geo: this.geo ? {
|
geo: this.geo ? {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<slot name="func"></slot>
|
<slot name="func"></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="indicator" v-show="$store.state.indicate"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -156,6 +157,10 @@ root(isDark)
|
||||||
&, *
|
&, *
|
||||||
user-select none
|
user-select none
|
||||||
|
|
||||||
|
> .indicator
|
||||||
|
height 3px
|
||||||
|
background $theme-color
|
||||||
|
|
||||||
> .main
|
> .main
|
||||||
color rgba(#fff, 0.9)
|
color rgba(#fff, 0.9)
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
<li><router-link to="/othello" :data-active="$route.name == 'othello'">%fa:gamepad%ゲーム<template v-if="hasGameInvitations">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
<li><router-link to="/othello" :data-active="$route.name == 'othello'">%fa:gamepad%ゲーム<template v-if="hasGameInvitations">%fa:circle%</template>%fa:angle-right%</router-link></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><router-link to="/i/widgets" :data-active="$route.name == 'widgets'">%fa:quidditch%%i18n:@widgets%%fa:angle-right%</router-link></li>
|
||||||
<li><router-link to="/i/drive" :data-active="$route.name == 'drive'">%fa:cloud%%i18n:@drive%%fa:angle-right%</router-link></li>
|
<li><router-link to="/i/drive" :data-active="$route.name == 'drive'">%fa:cloud%%i18n:@drive%%fa:angle-right%</router-link></li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
@ -25,27 +25,27 @@ export default Vue.extend({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
.mk-widget-container
|
root(isDark)
|
||||||
background #eee
|
background isDark ? #21242f : #eee
|
||||||
border-radius 8px
|
border-radius 8px
|
||||||
box-shadow 0 0 0 1px rgba(#000, 0.2)
|
box-shadow 0 4px 16px rgba(#000, 0.1)
|
||||||
overflow hidden
|
overflow hidden
|
||||||
|
|
||||||
&.hideHeader
|
|
||||||
background #fff
|
|
||||||
|
|
||||||
&.naked
|
&.naked
|
||||||
background transparent !important
|
background transparent !important
|
||||||
box-shadow none !important
|
box-shadow none !important
|
||||||
|
|
||||||
|
&.hideHeader
|
||||||
|
background isDark ? #21242f : #fff
|
||||||
|
|
||||||
> header
|
> header
|
||||||
> .title
|
> .title
|
||||||
margin 0
|
margin 0
|
||||||
padding 8px 10px
|
padding 8px 10px
|
||||||
font-size 15px
|
font-size 15px
|
||||||
font-weight normal
|
font-weight normal
|
||||||
color #465258
|
color isDark ? #b8c5cc : #465258
|
||||||
background #fff
|
background isDark ? #282c37 : #fff
|
||||||
border-radius 8px 8px 0 0
|
border-radius 8px 8px 0 0
|
||||||
|
|
||||||
> [data-fa]
|
> [data-fa]
|
||||||
|
@ -65,4 +65,10 @@ export default Vue.extend({
|
||||||
font-size 15px
|
font-size 15px
|
||||||
color #465258
|
color #465258
|
||||||
|
|
||||||
|
.mk-widget-container[data-darkmode]
|
||||||
|
root(true)
|
||||||
|
|
||||||
|
.mk-widget-container:not([data-darkmode])
|
||||||
|
root(false)
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -84,7 +84,7 @@ export default Vue.extend({
|
||||||
style(): any {
|
style(): any {
|
||||||
if (this.user.bannerUrl == null) return {};
|
if (this.user.bannerUrl == null) return {};
|
||||||
return {
|
return {
|
||||||
backgroundColor: this.user.bannerColor ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
backgroundColor: this.user.bannerColor && this.user.bannerColor.length == 3 ? `rgb(${ this.user.bannerColor.join(',') })` : null,
|
||||||
backgroundImage: `url(${ this.user.bannerUrl })`
|
backgroundImage: `url(${ this.user.bannerUrl })`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
</x-draggable>
|
</x-draggable>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" :is-mobile="true" @chosen="warp"/>
|
<component class="widget" v-for="widget in widgets" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" :is-mobile="true"/>
|
||||||
</template>
|
</template>
|
||||||
</main>
|
</main>
|
||||||
</mk-ui>
|
</mk-ui>
|
||||||
|
@ -55,17 +55,24 @@ export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XDraggable
|
XDraggable
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showNav: false,
|
showNav: false,
|
||||||
widgets: [],
|
|
||||||
customizing: false,
|
customizing: false,
|
||||||
widgetAdderSelected: null
|
widgetAdderSelected: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
widgets(): any[] {
|
||||||
|
return this.$store.state.settings.data.mobileHome;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if ((this as any).clientSettings.mobileHome == null) {
|
if (this.widgets.length == 0) {
|
||||||
Vue.set((this as any).clientSettings, 'mobileHome', [{
|
this.widgets = [{
|
||||||
name: 'calendar',
|
name: 'calendar',
|
||||||
id: 'a', data: {}
|
id: 'a', data: {}
|
||||||
}, {
|
}, {
|
||||||
|
@ -86,18 +93,9 @@ export default Vue.extend({
|
||||||
}, {
|
}, {
|
||||||
name: 'version',
|
name: 'version',
|
||||||
id: 'g', data: {}
|
id: 'g', data: {}
|
||||||
}]);
|
}];
|
||||||
this.widgets = (this as any).clientSettings.mobileHome;
|
|
||||||
this.saveHome();
|
this.saveHome();
|
||||||
} else {
|
|
||||||
this.widgets = (this as any).clientSettings.mobileHome;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$watch('clientSettings', i => {
|
|
||||||
this.widgets = (this as any).clientSettings.mobileHome;
|
|
||||||
}, {
|
|
||||||
deep: true
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
@ -105,46 +103,33 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onHomeUpdated(data) {
|
|
||||||
if (data.home) {
|
|
||||||
(this as any).clientSettings.mobileHome = data.home;
|
|
||||||
this.widgets = data.home;
|
|
||||||
} else {
|
|
||||||
const w = (this as any).clientSettings.mobileHome.find(w => w.id == data.id);
|
|
||||||
if (w != null) {
|
|
||||||
w.data = data.data;
|
|
||||||
this.$refs[w.id][0].preventSave = true;
|
|
||||||
this.$refs[w.id][0].props = w.data;
|
|
||||||
this.widgets = (this as any).clientSettings.mobileHome;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hint() {
|
hint() {
|
||||||
alert('ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。');
|
alert('ウィジェットを追加/削除したり並べ替えたりできます。ウィジェットを移動するには「三」をドラッグします。ウィジェットを削除するには「x」をタップします。いくつかのウィジェットはタップすることで表示を変更できます。');
|
||||||
},
|
},
|
||||||
|
|
||||||
widgetFunc(id) {
|
widgetFunc(id) {
|
||||||
const w = this.$refs[id][0];
|
const w = this.$refs[id][0];
|
||||||
if (w.func) w.func();
|
if (w.func) w.func();
|
||||||
},
|
},
|
||||||
|
|
||||||
onWidgetSort() {
|
onWidgetSort() {
|
||||||
this.saveHome();
|
this.saveHome();
|
||||||
},
|
},
|
||||||
|
|
||||||
addWidget() {
|
addWidget() {
|
||||||
const widget = {
|
this.$store.dispatch('settings/addMobileHomeWidget', {
|
||||||
name: this.widgetAdderSelected,
|
name: this.widgetAdderSelected,
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
data: {}
|
data: {}
|
||||||
};
|
});
|
||||||
|
},
|
||||||
|
|
||||||
this.widgets.unshift(widget);
|
|
||||||
this.saveHome();
|
|
||||||
},
|
|
||||||
removeWidget(widget) {
|
removeWidget(widget) {
|
||||||
this.widgets = this.widgets.filter(w => w.id != widget.id);
|
this.$store.dispatch('settings/removeMobileHomeWidget', widget);
|
||||||
this.saveHome();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
saveHome() {
|
saveHome() {
|
||||||
(this as any).clientSettings.mobileHome = this.widgets;
|
this.$store.commit('settings/setMobileHome', this.widgets);
|
||||||
(this as any).api('i/update_mobile_home', {
|
(this as any).api('i/update_mobile_home', {
|
||||||
home: this.widgets
|
home: this.widgets
|
||||||
});
|
});
|
||||||
|
@ -156,17 +141,25 @@ export default Vue.extend({
|
||||||
<style lang="stylus" scoped>
|
<style lang="stylus" scoped>
|
||||||
main
|
main
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
padding 8px
|
||||||
max-width 500px
|
max-width 500px
|
||||||
|
width 100%
|
||||||
|
|
||||||
@media (min-width 500px)
|
@media (min-width 500px)
|
||||||
padding 8px
|
padding 16px 8px
|
||||||
|
|
||||||
|
@media (min-width 600px)
|
||||||
|
padding 32px 8px
|
||||||
|
|
||||||
> header
|
> header
|
||||||
padding 8px
|
padding 8px
|
||||||
background #fff
|
background #fff
|
||||||
|
|
||||||
.widget
|
.widget
|
||||||
margin 8px
|
margin-bottom 8px
|
||||||
|
|
||||||
|
@media (min-width 600px)
|
||||||
|
margin-bottom 16px
|
||||||
|
|
||||||
.customize-container
|
.customize-container
|
||||||
margin 8px
|
margin 8px
|
|
@ -3,6 +3,7 @@ import MiOS from './mios';
|
||||||
|
|
||||||
const defaultSettings = {
|
const defaultSettings = {
|
||||||
home: [],
|
home: [],
|
||||||
|
mobileHome: [],
|
||||||
fetchOnScroll: true,
|
fetchOnScroll: true,
|
||||||
showMaps: true,
|
showMaps: true,
|
||||||
showPostFormOnTopOfTl: false,
|
showPostFormOnTopOfTl: false,
|
||||||
|
@ -23,10 +24,15 @@ export default (os: MiOS) => new Vuex.Store({
|
||||||
}],
|
}],
|
||||||
|
|
||||||
state: {
|
state: {
|
||||||
|
indicate: false,
|
||||||
uiHeaderHeight: 0
|
uiHeaderHeight: 0
|
||||||
},
|
},
|
||||||
|
|
||||||
mutations: {
|
mutations: {
|
||||||
|
indicate(state, x) {
|
||||||
|
state.indicate = x;
|
||||||
|
},
|
||||||
|
|
||||||
setUiHeaderHeight(state, height) {
|
setUiHeaderHeight(state, height) {
|
||||||
state.uiHeaderHeight = height;
|
state.uiHeaderHeight = height;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +64,25 @@ export default (os: MiOS) => new Vuex.Store({
|
||||||
|
|
||||||
addHomeWidget(state, widget) {
|
addHomeWidget(state, widget) {
|
||||||
state.data.home.unshift(widget);
|
state.data.home.unshift(widget);
|
||||||
|
},
|
||||||
|
|
||||||
|
setMobileHome(state, data) {
|
||||||
|
state.data.mobileHome = data;
|
||||||
|
},
|
||||||
|
|
||||||
|
setMobileHomeWidget(state, x) {
|
||||||
|
const w = state.data.mobileHome.find(w => w.id == x.id);
|
||||||
|
if (w) {
|
||||||
|
w.data = x.data;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addMobileHomeWidget(state, widget) {
|
||||||
|
state.data.mobileHome.unshift(widget);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMobileHomeWidget(state, widget) {
|
||||||
|
state.data.mobileHome = state.data.mobileHome.filter(w => w.id != widget.id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -85,6 +110,22 @@ export default (os: MiOS) => new Vuex.Store({
|
||||||
os.api('i/update_home', {
|
os.api('i/update_home', {
|
||||||
home: ctx.state.data.home
|
home: ctx.state.data.home
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
addMobileHomeWidget(ctx, widget) {
|
||||||
|
ctx.commit('addMobileHomeWidget', widget);
|
||||||
|
|
||||||
|
os.api('i/update_mobile_home', {
|
||||||
|
home: ctx.state.data.mobileHome
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMobileHomeWidget(ctx, widget) {
|
||||||
|
ctx.commit('removeMobileHomeWidget', widget);
|
||||||
|
|
||||||
|
os.api('i/update_mobile_home', {
|
||||||
|
home: ctx.state.data.mobileHome.filter(w => w.id != widget.id)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ gulp.task('doc:api:endpoints', async () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const i18n = new I18nReplacer(lang);
|
const i18n = new I18nReplacer(lang);
|
||||||
html = html.replace(i18n.pattern, i18n.replacement.bind(null, null));
|
html = html.replace(i18n.pattern, i18n.replacement);
|
||||||
html = fa(html);
|
html = fa(html);
|
||||||
const htmlPath = `./built/client/docs/${lang}/api/endpoints/${ep.endpoint}.html`;
|
const htmlPath = `./built/client/docs/${lang}/api/endpoints/${ep.endpoint}.html`;
|
||||||
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
|
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
|
||||||
|
@ -171,7 +171,7 @@ gulp.task('doc:api:entities', async () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const i18n = new I18nReplacer(lang);
|
const i18n = new I18nReplacer(lang);
|
||||||
html = html.replace(i18n.pattern, i18n.replacement.bind(null, null));
|
html = html.replace(i18n.pattern, i18n.replacement);
|
||||||
html = fa(html);
|
html = fa(html);
|
||||||
const htmlPath = `./built/client/docs/${lang}/api/entities/${kebab(entity.name)}.html`;
|
const htmlPath = `./built/client/docs/${lang}/api/entities/${kebab(entity.name)}.html`;
|
||||||
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
|
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
|
||||||
|
|
|
@ -53,7 +53,7 @@ gulp.task('doc:docs', async () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const i18n = new I18nReplacer(lang);
|
const i18n = new I18nReplacer(lang);
|
||||||
html = html.replace(i18n.pattern, i18n.replacement.bind(null, null));
|
html = html.replace(i18n.pattern, i18n.replacement);
|
||||||
html = fa(html);
|
html = fa(html);
|
||||||
const htmlPath = `./built/client/docs/${lang}/${name}.html`;
|
const htmlPath = `./built/client/docs/${lang}/${name}.html`;
|
||||||
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
|
mkdirp(path.dirname(htmlPath), (mkdirErr) => {
|
||||||
|
|
|
@ -154,6 +154,7 @@ export const pack = (
|
||||||
|
|
||||||
_target = Object.assign(_target, _file.metadata);
|
_target = Object.assign(_target, _file.metadata);
|
||||||
|
|
||||||
|
_target.src = _file.metadata.url;
|
||||||
_target.url = `${config.drive_url}/${_target.id}/${encodeURIComponent(_target.name)}`;
|
_target.url = `${config.drive_url}/${_target.id}/${encodeURIComponent(_target.name)}`;
|
||||||
|
|
||||||
if (_target.properties == null) _target.properties = {};
|
if (_target.properties == null) _target.properties = {};
|
||||||
|
|
|
@ -2,14 +2,20 @@ import * as Koa from 'koa';
|
||||||
import summaly from 'summaly';
|
import summaly from 'summaly';
|
||||||
|
|
||||||
module.exports = async (ctx: Koa.Context) => {
|
module.exports = async (ctx: Koa.Context) => {
|
||||||
const summary = await summaly(ctx.query.url);
|
try {
|
||||||
summary.icon = wrap(summary.icon);
|
const summary = await summaly(ctx.query.url, {
|
||||||
summary.thumbnail = wrap(summary.thumbnail);
|
followRedirects: false
|
||||||
|
});
|
||||||
|
summary.icon = wrap(summary.icon);
|
||||||
|
summary.thumbnail = wrap(summary.thumbnail);
|
||||||
|
|
||||||
// Cache 7days
|
// Cache 7days
|
||||||
ctx.set('Cache-Control', 'max-age=604800, immutable');
|
ctx.set('Cache-Control', 'max-age=604800, immutable');
|
||||||
|
|
||||||
ctx.body = summary;
|
ctx.body = summary;
|
||||||
|
} catch (e) {
|
||||||
|
ctx.status = 500;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function wrap(url: string): string {
|
function wrap(url: string): string {
|
||||||
|
|
|
@ -171,6 +171,9 @@ const addFile = async (
|
||||||
|
|
||||||
log('calculate average color...');
|
log('calculate average color...');
|
||||||
|
|
||||||
|
const info = await prominence(gm(fs.createReadStream(path), name)).identify();
|
||||||
|
const isTransparent = info ? info['Channel depth'].Alpha != null : false;
|
||||||
|
|
||||||
const buffer = await prominence(gm(fs.createReadStream(path), name)
|
const buffer = await prominence(gm(fs.createReadStream(path), name)
|
||||||
.setFormat('ppm')
|
.setFormat('ppm')
|
||||||
.resize(1, 1)) // 1pxのサイズに縮小して平均色を取得するというハック
|
.resize(1, 1)) // 1pxのサイズに縮小して平均色を取得するというハック
|
||||||
|
@ -182,7 +185,7 @@ const addFile = async (
|
||||||
|
|
||||||
log(`average color is calculated: ${r}, ${g}, ${b}`);
|
log(`average color is calculated: ${r}, ${g}, ${b}`);
|
||||||
|
|
||||||
return [r, g, b];
|
return isTransparent ? [r, g, b, 255] : [r, g, b];
|
||||||
})(),
|
})(),
|
||||||
// folder
|
// folder
|
||||||
(async () => {
|
(async () => {
|
||||||
|
|
1152
test/api.ts
1152
test/api.ts
File diff suppressed because it is too large
Load diff
10
test/text.ts
10
test/text.ts
|
@ -1,11 +1,7 @@
|
||||||
/**
|
import * as assert from 'assert';
|
||||||
* Text Tests!
|
|
||||||
*/
|
|
||||||
|
|
||||||
const assert = require('assert');
|
import analyze from '../src/text/parse';
|
||||||
|
import syntaxhighlighter from '../src/text/parse/core/syntax-highlighter';
|
||||||
const analyze = require('../built/text/parse').default;
|
|
||||||
const syntaxhighlighter = require('../built/text/parse/core/syntax-highlighter').default;
|
|
||||||
|
|
||||||
describe('Text', () => {
|
describe('Text', () => {
|
||||||
it('can be analyzed', () => {
|
it('can be analyzed', () => {
|
||||||
|
|
|
@ -110,14 +110,14 @@ const plugins = [
|
||||||
//#region i18n
|
//#region i18n
|
||||||
langs.forEach(lang => {
|
langs.forEach(lang => {
|
||||||
Object.keys(entry).forEach(file => {
|
Object.keys(entry).forEach(file => {
|
||||||
let src = fs.readFileSync(`${__dirname}/built/client/assets/${file}.${version}.-.${isProduction ? 'min' : 'raw'}.js`, 'utf8');
|
let src = fs.readFileSync(`${__dirname}/built/client/assets/${file}.${version}.-.${isProduction ? 'min' : 'raw'}.js`, 'utf-8');
|
||||||
|
|
||||||
const i18nReplacer = new I18nReplacer(lang);
|
const i18nReplacer = new I18nReplacer(lang);
|
||||||
|
|
||||||
src = src.replace(i18nReplacer.pattern, i18nReplacer.replacement);
|
src = src.replace(i18nReplacer.pattern, i18nReplacer.replacement);
|
||||||
src = src.replace('%lang%', lang);
|
src = src.replace('%lang%', lang);
|
||||||
|
|
||||||
fs.writeFileSync(`${__dirname}/built/client/assets/${file}.${version}.${lang}.${isProduction ? 'min' : 'raw'}.js`, src, 'utf8');
|
fs.writeFileSync(`${__dirname}/built/client/assets/${file}.${version}.${lang}.${isProduction ? 'min' : 'raw'}.js`, src, 'utf-8');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
@ -146,27 +146,20 @@ module.exports = {
|
||||||
}, {
|
}, {
|
||||||
loader: 'replace',
|
loader: 'replace',
|
||||||
query: {
|
query: {
|
||||||
search: /%base64:(.+?)%/g.toString(),
|
qs: [{
|
||||||
replace: 'base64replacement'
|
search: /%base64:(.+?)%/g.toString(),
|
||||||
}
|
replace: 'base64replacement'
|
||||||
}, {
|
}, {
|
||||||
loader: 'replace',
|
search: i18nPattern.toString(),
|
||||||
query: {
|
replace: 'i18nReplacement',
|
||||||
search: i18nPattern.toString(),
|
i18n: true
|
||||||
replace: 'i18nReplacement',
|
}, {
|
||||||
i18n: true
|
search: faPattern.toString(),
|
||||||
}
|
replace: 'faReplacement'
|
||||||
}, {
|
}, {
|
||||||
loader: 'replace',
|
search: /^<template>([\s\S]+?)\r?\n<\/template>/.toString(),
|
||||||
query: {
|
replace: 'collapseSpacesReplacement'
|
||||||
search: faPattern.toString(),
|
}]
|
||||||
replace: 'faReplacement'
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
loader: 'replace',
|
|
||||||
query: {
|
|
||||||
search: /^<template>([\s\S]+?)\r?\n<\/template>/.toString(),
|
|
||||||
replace: 'collapseSpacesReplacement'
|
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -1,22 +1,30 @@
|
||||||
const loaderUtils = require('loader-utils');
|
import { getOptions } from 'loader-utils';
|
||||||
|
|
||||||
function trim(text, g) {
|
function trim(text, g) {
|
||||||
return text.substring(1, text.length - (g ? 2 : 0));
|
return text.substring(1, text.length - (g ? 2 : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = function(src) {
|
export default function(src) {
|
||||||
|
const fn = options => {
|
||||||
|
const search = options.search;
|
||||||
|
const g = search[search.length - 1] == 'g';
|
||||||
|
const file = this.resourcePath.replace(/\\/g, '/');
|
||||||
|
const replace = options.i18n ? global[options.replace].bind(null, {
|
||||||
|
src: file,
|
||||||
|
lang: options.lang
|
||||||
|
}) : global[options.replace];
|
||||||
|
if (typeof search != 'string' || search.length == 0) console.error('invalid search');
|
||||||
|
if (typeof replace != 'function') console.error('invalid replacer:', replace, this.request);
|
||||||
|
src = src.replace(new RegExp(trim(search, g), g ? 'g' : ''), replace);
|
||||||
|
};
|
||||||
|
|
||||||
this.cacheable();
|
this.cacheable();
|
||||||
const options = loaderUtils.getOptions(this);
|
const options = getOptions(this);
|
||||||
const search = options.search;
|
if (options.qs) {
|
||||||
const g = search[search.length - 1] == 'g';
|
options.qs.forEach(q => fn(q));
|
||||||
const file = this.resourcePath.replace(/\\/g, '/');
|
} else {
|
||||||
const replace = options.i18n ? global[options.replace].bind(null, {
|
fn(options);
|
||||||
src: file,
|
}
|
||||||
lang: options.lang
|
|
||||||
}) : global[options.replace];
|
|
||||||
if (typeof search != 'string' || search.length == 0) console.error('invalid search');
|
|
||||||
if (typeof replace != 'function') console.error('invalid replacer:', replace, this.request);
|
|
||||||
src = src.replace(new RegExp(trim(search, g), g ? 'g' : ''), replace);
|
|
||||||
this.callback(null, src);
|
this.callback(null, src);
|
||||||
return src;
|
return src;
|
||||||
};
|
}
|
||||||
|
|
Loading…
Reference in a new issue