Last active
November 13, 2022 09:12
-
-
Save unarist/71067609416aed633cf74eddb6feb725 to your computer and use it in GitHub Desktop.
:don: - Add tablet layout
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name :don: - Add tablet layout | |
// @namespace https://github.com/unarist/ | |
// @version 0.8 | |
// @description Add tablet layout (w/ tabbar, w/o compose column) for <=1024 width | |
// @author unarist | |
// @match https://mstdn.maud.io/* | |
// @downloadURL https://gist.github.com/unarist/71067609416aed633cf74eddb6feb725/raw/mastodon-add-2col-layout.user.js | |
// @grant none | |
// @run-at document-body | |
// @noframes | |
// ==/UserScript== | |
/* | |
v2.0.0から本家でもブレークポイントが狭くなっていますが(#5063) | |
このスクリプトではそれに加え、 | |
* 最小幅は631pxじゃなくて480px | |
* 最左カラムはドロワー固定でないように(i.e. 最左ドロワーを非表示に) | |
* そうするとメニューがないので、1カラム同様に.tab-barを表示 | |
* v2.3.0からはメニューからも投稿ボタンが消えてしまうので、モバイル同様の投稿ボタンを表示 | |
* カラム幅の自動拡大・縮小 | |
といった変更を加えています。 | |
最小幅の変更と投稿ボタンの追加以外はCSSだけで行えるので、Stylish等でも行えます。 | |
カラム幅もPC版レイアウト同様 flex-grow や flex-shrink で行えます。お好みで調整してください。 | |
*/ | |
/* | |
window.innerWidth を偽装するというシンプルで汚いハックなので、 | |
* 環境やバージョンによっては動かない場合があります | |
* 他のUserScriptやUserStyleと競合する場合があります | |
投稿カラムを消すだけなので、表示するカラムはピン留めでいじります。 | |
3カラムぐらいならいけそうですが、もっと増やしてスクロールしたい場合はCSSでよしなに。 | |
tablet layoutを使いたいドメインのみ、ユーザーによるmatchとして追加することをお勧めします。 | |
(Tampermonkeyだと [インストール済みUserScript]→これ→[設定] で設定する) | |
*/ | |
/* | |
v0.8: Publishボタンがある時に投稿ボタンを生やさないようにした(v4.0.0rc3で確認) | |
v0.7: CSPが適用されていそうならstyleタグを試さないようにして、余分な警告が出ないように | |
v0.6: CSPにstyleタグ蹴られるやつをなんとかした | |
v0.5: React16.3(Mastodon2.4.0)対応 | |
v0.4: デフォルトのmatchをdonのみに戻した。最小幅を指定。 | |
v0.3: v2.3.0の浮いてる投稿ボタン(#6594)対応。ついでに最小幅とmatch変えてしまいましたが、別に戻してもいいのでクレームどうぞ。 | |
v0.2: v2.0.0のブレークポイント変更(#5063)対応 | |
*/ | |
(function() { | |
'use strict'; | |
const MIN_WIDTH = 480; | |
const log = x => console.debug(`${GM.info.script.name}: ${x}`); | |
const tag = (name, props = {}, children = []) => { | |
const e = Object.assign(document.createElement(name), props); | |
if (typeof props.style === "object") Object.assign(e.style, props.style); | |
(children.forEach ? children : [children]).forEach(c => e.appendChild(c)); | |
return e; | |
}; | |
const setupStylesheet = css => { | |
if (!document.querySelector('meta[name="style-nonce"]')) { | |
const styleEl = document.head.appendChild(tag('style', { textContent: css })); | |
if (styleEl.sheet) { | |
return styleEl.sheet; | |
} | |
styleEl.remove(); // 多分CSPで弾かれてるので削除 | |
} | |
// workaround for Blink | |
if (document.adoptedStyleSheets) { | |
log('<style> may be blocked by CSP, using adoptedStylesheets instead.'); | |
const sheet = new CSSStyleSheet(); | |
sheet.replaceSync(css); | |
document.adoptedStyleSheets = document.adoptedStyleSheets.concat(sheet); | |
return sheet; | |
} | |
// workaround2 | |
const usableSheet = [...document.styleSheets].filter(x=>(x.href || "").startsWith(location.origin)).slice(-1)[0]; | |
if (usableSheet) { | |
log(`<style> may be blocked by CSP, inserting into ${usableSheet.href} instead.`); | |
usableSheet.insertRule(`@supports (display:block) { ${css} }`); | |
return usableSheet; | |
} | |
throw Error(`Cannot setup custom styles (probably due to CSP).\nUA: ${navigator.userAgent}`); | |
}; | |
setupStylesheet(` | |
.tablet-layout__compose-button { visibility: hidden; } | |
@media screen and (min-width: ${MIN_WIDTH}px) and (max-width: 1024px) { | |
.drawer:first-child, .drawer__header { display: none; } | |
.columns-area { flex-direction: row; } | |
.column, .drawer { padding: 0; flex: 1 1 100%; min-width: 225px; } | |
.column:not(:last-child) { padding-right: 10px; } | |
.ui:not(.is-composing) .tablet-layout__compose-button { visibility: visible; } | |
/* revert design changes on #5063 */ | |
.columns-area { padding: 10px; } | |
.tabs-bar { display: flex; } | |
} | |
`); | |
const originalProp = Object.getOwnPropertyDescriptor(window, 'innerWidth'); | |
Object.defineProperty(window, 'innerWidth', Object.assign({}, originalProp, { | |
get: (val = originalProp.get.call()) => (val <= 1024 && val >= MIN_WIDTH) ? 1025 : val | |
})); | |
// 念の為resizeイベントを飛ばしてReact側を更新させる | |
// @run-at document-body で十分な気はする | |
const event = document.createEvent('UIEvents'); | |
event.initEvent('resize', false, false); | |
window.dispatchEvent(event); | |
// Compose button on tabbar has been removed at v2.3.0rc1 (#6594) | |
// Since new floating button will only appears on (real) mobile layout, we need to add our one... | |
const getHistory = () => { | |
// >= v16: to descendant | |
const rootContainer = document.querySelector('#mastodon')._reactRootContainer; | |
let current_node = (rootContainer._internalRoot /* v16.3 */ || rootContainer).current.child; | |
while ('function' === typeof current_node.type) { | |
const history = current_node.memoizedProps.history; | |
if (history) return history; | |
current_node = current_node.child; | |
} | |
}; | |
const observer_callback = (records, observer) => { | |
const target = document.querySelector('.ui'); | |
if (!target) return; | |
if (!document.querySelector('.tabs-bar__link[href="/web/statuses/new"], a[href="/publish"]')) { | |
const history = getHistory(); | |
target.appendChild(tag('a', { | |
className: 'floating-action-button tablet-layout__compose-button', | |
href: '/web/statuses/new', | |
onclick: e => { e.preventDefault(); history.push('/statuses/new'); } | |
}, [ | |
tag('i', { className: 'fa fa-pencil' }) | |
])); | |
} | |
observer.disconnect(); | |
}; | |
const observer = new MutationObserver(observer_callback); | |
observer.observe(document.body, { childList: true, subtree: true }); | |
observer_callback([], observer); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment