Skip to content

Instantly share code, notes, and snippets.

@unarist
Last active November 13, 2022 09:12
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save unarist/71067609416aed633cf74eddb6feb725 to your computer and use it in GitHub Desktop.
Save unarist/71067609416aed633cf74eddb6feb725 to your computer and use it in GitHub Desktop.
:don: - Add tablet layout
// ==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