Perplexity Widescreen & Compact & Code Collapser

v1.9.3: 折疊時青線消失;+新建移至logo正右方獨立顯示

Você precisará instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Você precisará instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Você precisará instalar uma extensão como o Tampermonkey para instalar este script.

Você precisará instalar um gerenciador de scripts de usuário para instalar este script.

(Eu já tenho um gerenciador de scripts de usuário, me deixe instalá-lo!)

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar uma extensão como o Stylus para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

Você precisará instalar um gerenciador de estilos de usuário para instalar este estilo.

(Eu já possuo um gerenciador de estilos de usuário, me deixar fazer a instalação!)

// ==UserScript==
// @name         Perplexity Widescreen & Compact & Code Collapser
// @namespace    http://tampermonkey.net/
// @version      1.9.3
// @description  v1.9.3: 折疊時青線消失;+新建移至logo正右方獨立顯示
// @author       ford933
// @license      All Rights Reserved
// @match        https://www.perplexity.ai/*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-end
// ==/UserScript==

(function () {
    'use strict';

    const MIN_W = 140, MAX_W = 380;
    let savedWidth = 185;
    try { savedWidth = Math.min(Math.max(GM_getValue('pplx_sidebar_width', 185), MIN_W), MAX_W); } catch(e){}

    const css = `
        /* SCROLLBAR */
        *::-webkit-scrollbar{display:none!important;width:0!important;height:0!important}
        *{scrollbar-width:none!important;-ms-overflow-style:none!important}
        .scrollable-container::-webkit-scrollbar{display:block!important;width:4px!important}
        .scrollable-container::-webkit-scrollbar-thumb{background:rgba(128,128,128,.25)!important;border-radius:2px!important}
        .scrollable-container{scrollbar-width:thin!important;-ms-overflow-style:auto!important}

        /* WIDESCREEN */
        html,body{max-width:100%!important;overflow-x:hidden!important}
        .scrollable-container{max-width:100%!important;width:100%!important;padding-left:16px!important;padding-right:12px!important}
        .scrollable-container>div{max-width:100%!important;width:100%!important}
        .scrollable-container div[class*="max-w-"],
        .scrollable-container section[class*="max-w-"],
        .scrollable-container article[class*="max-w-"],
        .scrollable-container main[class*="max-w-"]{max-width:100%!important}
        .scrollable-container .container,.scrollable-container .container.isolate{max-width:100%!important;width:100%!important;padding-left:0!important;padding-right:0!important}
        .scrollable-container .erp-sidecar,.scrollable-container [class*="erp-sidecar"]{max-width:100%!important;width:100%!important}
        .prose,.prose>*{max-width:100%!important;width:100%!important}

        /* HEADER */
        [class*="h-headerHeight"]{height:auto!important;min-height:0!important}
        [class*="containerheader"],[class*="container"][class*="header"]{height:auto!important;min-height:0!important;max-height:none!important}
        [role="tablist"] button[role="tab"]{padding-top:2px!important;padding-bottom:2px!important}
        [role="tablist"]{height:auto!important;gap:12px!important}

        /* PILL */
        div[data-ask-input-container="true"]{max-width:520px!important;margin-left:auto!important;margin-right:auto!important}
        #ask-input{max-height:30vh!important;overflow-y:auto!important}
        div:has(>div[data-ask-input-container="true"]){padding-top:2px!important;padding-bottom:2px!important;margin-top:0!important;margin-bottom:0!important}

        /* CHAT SPACING */
        .scrollable-container .gap-y-lg{row-gap:4px!important}
        .scrollable-container .gap-y-md{row-gap:2px!important}
        .scrollable-container .gap-y-sm{row-gap:1px!important}
        .scrollable-container .gap-5{gap:4px!important}
        .scrollable-container .gap-4{gap:2px!important}
        .scrollable-container .gap-md{gap:2px!important}
        .scrollable-container .gap-sm{gap:1px!important}
        .scrollable-container .mt-md:not(nav .mt-md):not(.prose .mt-md){margin-top:2px!important}
        .scrollable-container .mt-xs:not(nav .mt-xs):not(.prose .mt-xs){margin-top:0!important}
        .scrollable-container [class*="pt-md"]:not(nav [class*="pt-md"]):not(.prose [class*="pt-md"]){padding-top:2px!important}
        .scrollable-container [class*="pt-lg"]:not(nav [class*="pt-lg"]):not(.prose [class*="pt-lg"]){padding-top:2px!important}
        .scrollable-container .flex.items-center.justify-between{padding-top:0!important;margin-top:0!important}
        .scrollable-container button.flex.items-center[class*="gap-sm"][class*="text-quiet"]{margin-top:0!important;margin-bottom:0!important;padding-top:0!important;padding-bottom:0!important}
        .scrollable-container .text-sm.text-quiet[class*="font-sans"]{margin-top:0!important;margin-bottom:0!important;line-height:1.2!important}

        /* PROSE */
        .prose p,.prose li,.prose blockquote{line-height:1.35!important;margin-top:0!important;margin-bottom:2px!important;margin-block-start:0!important;margin-block-end:2px!important;padding-top:0!important;padding-bottom:0!important}
        .prose{margin-top:2px!important}
        .prose h1,.prose h2,.prose h3,.prose h4{margin-top:4px!important;margin-bottom:2px!important;line-height:1.25!important}
        .prose ul,.prose ol{margin-top:0!important;margin-bottom:2px!important;padding-left:1.2em!important}
        .prose li{margin:0!important}
        .prose hr{margin-top:4px!important;margin-bottom:4px!important}

        /* TABLE */
        .scrollable-container table{border-collapse:separate!important;border-spacing:0!important}
        .scrollable-container table th{padding:3px 6px!important;min-width:40px!important;vertical-align:bottom!important;white-space:normal!important;word-break:break-word!important}
        .scrollable-container table td{padding:2px 6px!important;min-width:40px!important;vertical-align:top!important;white-space:normal!important;word-break:break-word!important}
        .scrollable-container .overflow-auto[class*="rounded"]{overflow-x:auto!important;max-width:100%!important;display:block!important}

        /* USER BUBBLE */
        main [class*="justify-end"]{position:relative!important}
        main [class*="justify-end"]>[class*="invisible"]{position:absolute!important;right:4px!important;top:4px!important;left:auto!important;z-index:20!important}
        main [class*="justify-end"]>div:last-child,
        main [class*="justify-end"]>*:last-child:not(button):not(svg){width:100%!important;max-width:100%!important;text-align:left!important}
        main [class*="ml-auto"]:not(button):not(svg):not(input){max-width:100%!important}
        main [class*="ms-auto"]:not(button):not(svg):not(input){max-width:100%!important}
        [class*="UserQuery"],[class*="user-query"],[class*="human"]{max-width:100%!important}
        .scrollable-container [class*="grouptitle"]{display:flex!important;width:100%!important;max-width:100%!important;flex-direction:column!important}
        .scrollable-container [class*="groupquery"]{width:100%!important;max-width:100%!important}
        .scrollable-container [class*="rounded-tl-2xl"][class*="bg-subtle"]{max-width:100%!important;width:100%!important}

        /* ============================================================
           SIDEBAR 緊湊
           ============================================================ */
        div.w-sideBarWidth{flex-shrink:0!important;transition:width .05s!important}
        nav.groupsidebar,nav[class*="groupsidebar"]{overflow-x:hidden!important}
        nav span.w-full.overflow-hidden{display:block!important;white-space:nowrap!important;overflow:hidden!important;-webkit-mask-image:none!important;mask-image:none!important;line-height:1.3!important;max-height:1.3em!important}
        nav .flex.flex-none.flex-col{height:auto!important;min-height:0!important;gap:0!important;padding:0!important}

        nav a,nav button{padding-top:0!important;padding-bottom:0!important;margin-top:0!important;margin-bottom:0!important;min-height:0!important}
        nav a[href],nav button{height:auto!important;max-height:22px!important;line-height:1.2!important}
        nav a svg,nav button svg{width:14px!important;height:14px!important}

        nav [class*="gap-"]{gap:0!important}
        nav [class*="py-"]{padding-top:0!important;padding-bottom:0!important}
        nav [class*="my-"]{margin-top:0!important;margin-bottom:0!important}
        nav [class*="mt-"]{margin-top:0!important}
        nav [class*="mb-"]{margin-bottom:0!important}
        nav [class*="pt-"]{padding-top:0!important}
        nav [class*="pb-"]{padding-bottom:0!important}
        nav [class*="space-y"]>*{margin-top:1px!important}
        nav [class*="px-md"]{padding-left:4px!important;padding-right:4px!important}
        nav [class*="px-12px"]{padding-left:4px!important;padding-right:4px!important}
        nav [class*="pl-14px"]{padding-left:6px!important}
        nav [class*="ml-26px"]{margin-left:10px!important}
        nav [class*="-ml-md"]{margin-left:-4px!important}
        nav [class*="border-t"]{margin-top:2px!important;margin-bottom:2px!important}

        nav [class*="group"][class*="sidebar-sub-menu"] > div[class*="h-10"],
        nav [class*="group\/sidebar-sub-menu"] > div[class*="h-10"]{height:24px!important;min-height:24px!important;max-height:24px!important;padding-top:0!important;padding-bottom:0!important}
        nav [class*="group"][class*="sidebar-sub-menu"] > div[class*="h-7"],
        nav [class*="group\/sidebar-sub-menu"] > div[class*="h-7"]{height:20px!important;min-height:20px!important;max-height:20px!important;padding-top:0!important;padding-bottom:0!important}
        nav [class*="group"][class*="sidebar-sub-menu"] [class*="size-6"],
        nav [class*="group\/sidebar-sub-menu"] [class*="size-6"]{width:16px!important;height:16px!important;min-width:16px!important;min-height:16px!important}
        nav [class*="group"][class*="sidebar-sub-menu"] svg[width="18"],
        nav [class*="group\/sidebar-sub-menu"] svg[width="18"]{width:14px!important;height:14px!important}
        nav [class*="group"][class*="sidebar-sub-menu"] [class*="text-sm"],
        nav [class*="group\/sidebar-sub-menu"] [class*="text-sm"]{line-height:24px!important;font-size:11.5px!important}
        nav [class*="group"][class*="sidebar-sub-menu"] [class*="text-xs"],
        nav [class*="group\/sidebar-sub-menu"] [class*="text-xs"]{line-height:20px!important;font-size:11px!important}
        nav [class*="group"][class*="sidebar-sub-menu"] > div[class*="rounded-xl"],
        nav [class*="group\/sidebar-sub-menu"] > div[class*="rounded-xl"]{border-radius:6px!important}
        nav [class*="group"][class*="sidebar-sub-menu"] [class*="pl-sm"],
        nav [class*="group\/sidebar-sub-menu"] [class*="pl-sm"]{padding-left:4px!important}
        nav [class*="group"][class*="sidebar-sub-menu"] [class*="px-sm"],
        nav [class*="group\/sidebar-sub-menu"] [class*="px-sm"]{padding-left:4px!important;padding-right:4px!important}
        nav [class*="group"][class*="sidebar-sub-menu"] [class*="pr-3"]{padding-right:4px!important}
        nav [class*="group"][class*="sidebar-sub-menu"] button[class*="h-6"],
        nav [class*="group\/sidebar-sub-menu"] button[class*="h-6"]{height:18px!important;min-height:18px!important;padding:0!important}
        nav > div{gap:0!important}
        nav [class*="flex-col"]{gap:0!important}

        /* 隱藏被快捷鈕取代的 nav 列 */
        .pplx-hidden-nav-row{display:none!important}

        /* ── 新建行 position:relative,讓快捷鈕可 absolute 定位 ── */
        /* v1.9.3:+新建 icon 鈕,在 logo 正右方,獨立不融合 */
        #pplx-new-btn-header{
            display:inline-flex!important;align-items:center!important;justify-content:center!important;
            width:26px!important;height:26px!important;
            min-width:26px!important;min-height:26px!important;
            border-radius:6px!important;border:none!important;cursor:pointer!important;
            background:transparent!important;
            color:var(--text-quiet,currentColor)!important;
            opacity:.7!important;flex-shrink:0!important;
            text-decoration:none!important;
            margin-left:3px!important;margin-right:0!important;
            padding:0!important;
            transition:background 130ms,opacity 130ms!important;
            vertical-align:middle!important;
        }
        #pplx-new-btn-header:hover{background:rgba(128,128,128,.15)!important;opacity:1!important}
        #pplx-new-btn-header svg{width:15px!important;height:15px!important;display:block!important;stroke:currentColor!important;fill:none!important;pointer-events:none!important;}
        .pplx-newbtn-anchor{position:relative!important;overflow:visible!important}

        /* ── 快捷鈕群組:absolute 釘在行右端 ── */
        .pplx-hdr-shortcuts{
            position:absolute!important;
            right:2px!important;top:50%!important;
            transform:translateY(-50%)!important;
            display:flex!important;align-items:center!important;
            justify-content:space-around!important;
            gap:0px!important;
            width:calc(100% - 82px)!important;
            z-index:9000!important;
            pointer-events:auto!important;
            visibility:visible!important;opacity:1!important;
        }

        /* ── 快捷鈕本體 ── */
        a.pplx-hdr-btn{
            display:inline-flex!important;align-items:center!important;justify-content:center!important;
            flex:1!important;
            height:22px!important;
            max-height:22px!important;min-height:22px!important;
            min-width:18px!important;
            border-radius:5px!important;
            background:transparent!important;border:none!important;cursor:pointer!important;
            color:var(--text-quiet,currentColor)!important;
            opacity:.7!important;flex-shrink:0!important;
            text-decoration:none!important;
            padding:0!important;margin:0!important;
            line-height:1!important;
            transition:background 130ms,opacity 130ms!important;
            visibility:visible!important;pointer-events:auto!important;
            overflow:visible!important;box-sizing:border-box!important;
        }
        a.pplx-hdr-btn:hover{background:rgba(128,128,128,.15)!important;opacity:1!important}

        /* SVG 固定 14px — 覆蓋所有 nav svg 規則 */
        a.pplx-hdr-btn svg{
            width:14px!important;height:14px!important;
            min-width:14px!important;min-height:14px!important;
            max-width:14px!important;max-height:14px!important;
            display:block!important;pointer-events:none!important;
            stroke:currentColor!important;fill:none!important;
            overflow:visible!important;
        }

        /* Tooltip */
        a.pplx-hdr-btn::after{
            content:attr(data-tip);display:none;
            position:absolute;top:calc(100% + 4px);left:50%;
            transform:translateX(-50%);
            background:rgba(0,0,0,.82);color:#fff;
            font-size:11px;padding:2px 7px;border-radius:4px;
            white-space:nowrap;pointer-events:none;z-index:99999;
            font-family:sans-serif;font-weight:normal;
        }
        a.pplx-hdr-btn:hover::after{display:block}

        /* CODE */
        pre,code{max-width:100%!important;word-break:break-all!important;white-space:pre-wrap!important}
        .pplx-pre-container{position:relative!important;display:block!important;overflow:visible!important;margin-top:2px!important;margin-bottom:2px!important}
        .pplx-code-wrapper{position:sticky!important;top:0!important;height:0!important;width:100%!important;display:flex!important;justify-content:flex-end!important;align-items:flex-start!important;z-index:200!important;pointer-events:none!important;overflow:visible!important}
        .pplx-pre-container>pre{padding-top:38px!important;margin-top:0!important}
        .pplx-code-toolbar{pointer-events:auto!important;margin-right:6px!important;margin-top:3px!important;display:flex!important;flex-direction:row!important;align-items:center!important;gap:5px!important;background:var(--background-base-color,#ffffff)!important;border:1px solid rgba(14,165,233,.22)!important;padding:3px 6px 3px 8px!important;border-radius:20px!important;box-shadow:0 2px 10px rgba(14,165,233,.18)!important;max-width:calc(100% - 40px)!important;min-width:100px!important}
        .pplx-tb-left{display:flex!important;align-items:center!important;gap:4px!important;overflow:hidden!important;flex:1!important;min-width:0!important}
        .pplx-code-name{font-size:11px!important;font-weight:700!important;white-space:nowrap!important;overflow:hidden!important;text-overflow:ellipsis!important;color:#0ea5e9!important;user-select:none!important;background:rgba(14,165,233,.10)!important;padding:1px 7px 1px 5px!important;border-radius:10px!important;line-height:1.6!important;cursor:default!important}
        .pplx-code-name::before{content:'●';margin-right:4px;font-size:7px;vertical-align:middle;opacity:.7}
        .pplx-code-ver{font-size:10px!important;font-weight:500!important;white-space:nowrap!important;flex-shrink:0!important;color:#64748b!important;user-select:none!important;background:rgba(100,116,139,.10)!important;padding:1px 6px!important;border-radius:8px!important;line-height:1.6!important;cursor:default!important}
        .pplx-code-arrow{flex-shrink:0!important;cursor:pointer!important;color:#fff!important;font-size:10px!important;padding:2px 8px!important;border-radius:10px!important;background:#0ea5e9!important;transition:background .15s!important;user-select:none!important;line-height:1.5!important;font-weight:bold!important}
        .pplx-code-arrow:hover{background:#0284c7!important}
        .pplx-code-arrow.pplx-expanded{background:#0284c7!important}
        .pplx-code-copy{flex-shrink:0!important;cursor:pointer!important;font-size:13px!important;padding:2px 6px!important;border-radius:8px!important;line-height:1.4!important;transition:background .15s,transform .1s!important;user-select:none!important;margin-left:2px!important}
        .pplx-code-copy:hover{background:rgba(14,165,233,.15)!important;transform:scale(1.12)!important}
        .pplx-code-collapsed{max-height:0!important;min-height:0!important;overflow:hidden!important;opacity:.75!important;cursor:pointer!important;border-bottom:3px dashed #0ea5e9!important;padding:0!important;margin:0!important;transition:max-height .3s ease,opacity .2s!important}
        .pplx-code-collapsed:hover{opacity:1!important}

        /* DRAG HANDLE */
        #pplx-resize-handle{width:8px;height:100vh;position:fixed;top:0;left:var(--pplx-sidebar-width,185px);z-index:9999999;cursor:col-resize;background:transparent}
        #pplx-resize-handle::after{content:'';position:absolute;left:50%;top:0;bottom:0;width:1px;background:#22d3ee;transform:translateX(-50%)}
        #pplx-resize-handle:hover::after,#pplx-resize-handle.active::after{background:#06b6d4;width:2px}
        #pplx-drag-curtain{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:9999998;cursor:col-resize;display:none}
        body.pplx-resizing #pplx-drag-curtain{display:block}
        body.pplx-resizing *{user-select:none!important}

        /* GLOBAL COLLAPSE BTN */
        #pplx-global-collapse-btn{position:fixed!important;right:18px!important;bottom:60px!important;z-index:9999999!important;background:#0ea5e9!important;color:#fff!important;border:none!important;border-radius:20px!important;width:32px!important;height:32px!important;font-size:15px!important;cursor:pointer!important;box-shadow:0 3px 8px rgba(0,0,0,.25)!important;display:flex!important;align-items:center!important;justify-content:center!important;transition:transform .2s,background .2s!important;user-select:none!important}
        #pplx-global-collapse-btn:hover{transform:scale(1.08)!important;background:#0284c7!important}
    `;

    if (typeof GM_addStyle !== 'undefined') { GM_addStyle(css); }
    else { const s = document.createElement('style'); s.textContent = css; document.documentElement.appendChild(s); }

    // ── Sidebar Width ──
    function applySidebarWidth(px) {
        savedWidth = px;
        document.documentElement.style.setProperty('--pplx-sidebar-width', px + 'px');
        ['div.w-sideBarWidth', 'nav.groupsidebar', 'nav[class*="groupsidebar"]'].forEach(sel => {
            document.querySelectorAll(sel).forEach(el => {
                el.style.setProperty('width', px + 'px', 'important');
                // 不強制 min-width,讓 Perplexity 原生折疊鈕可自由縮小
                el.style.removeProperty('min-width');
                el.style.setProperty('max-width', px + 'px', 'important');
            });
        });
        const h = document.getElementById('pplx-resize-handle');
        if (h) h.style.left = px + 'px';
    }
    function watchSidebarElement() {
        const el = document.querySelector('div.w-sideBarWidth');
        if (!el || el._pplxWatched) return; el._pplxWatched = true;
        new MutationObserver(() => { const _wm = parseInt(el.style.width); if (!isNaN(_wm) && _wm > 60 && _wm !== savedWidth) applySidebarWidth(savedWidth); }).observe(el, { attributes: true, attributeFilter: ['style'] });
    }
    function fixThreadSectionWidth() {
        document.querySelectorAll('nav [style*="width: 200"]').forEach(el => el.style.setProperty('width', '9999px', 'important'));
        document.querySelectorAll('nav span[style*="mask-image"]').forEach(el => { el.style.removeProperty('mask-image'); el.style.removeProperty('-webkit-mask-image'); });
    }
    function fixPageContentWidth() {
        document.querySelectorAll('[style*="--page-content-width"]').forEach(el => {
            if (el.style.getPropertyValue('--page-content-width') !== '9999px')
                el.style.setProperty('--page-content-width', '9999px');
        });
        document.querySelectorAll('[class*="bg-subtle"][class*="rounded-2xl"][style*="max-width"]').forEach(el => { el.style.removeProperty('max-width'); });
        document.querySelectorAll('[class*="bg-subtle"][class*="rounded-tl-2xl"][style*="max-width"]').forEach(el => { el.style.removeProperty('max-width'); });
        document.querySelectorAll('[class*="grouptitle"]').forEach(el => {
            if (getComputedStyle(el).display === 'inline-flex') {
                el.style.setProperty('display', 'flex', 'important');
                el.style.setProperty('width', '100%', 'important');
            }
        });
    }

    // ── 快捷鈕定義 ──
    const SHORTCUT_DEFS = [
        {
            label: '空間', href: '/spaces',
            svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7c0-1.1.9-2 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><line x1="9" y1="13" x2="15" y2="13"/><line x1="12" y1="10" x2="12" y2="16"/></svg>`
        },
        {
            label: '成品', href: '/computer/artifacts',
            svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="8" height="8" rx="1.5"/><rect x="13" y="3" width="8" height="8" rx="1.5"/><rect x="3" y="13" width="8" height="8" rx="1.5"/><rect x="13" y="13" width="8" height="8" rx="1.5"/></svg>`
        },
        {
            label: '自訂', href: '/computer/connectors',
            svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06-.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>`
        },
    ];

    const HIDDEN_LABELS = new Set(['空間', '成品', '自訂']);
    let shortcutsInjected = false;

    // ── v1.8.6 核心:找「新建」所在的 collapsible-sidebar-section
    //   對它加 position:relative,然後 append 一個 absolute 定位的快捷列
    //   完全不改變父層 flex 方向,不影響 nav 結構
    // ── v1.9.2:把 +新建 注入到 sidebar 頂部 header 列(logo 右方)──
    function injectNewBtnToHeader() {
        if (document.getElementById('pplx-new-btn-header')) return true;
        // 找 sidebar header:nav 第一個直接子 div
        const nav = document.querySelector('nav[class*="groupsidebar"]')
                 || document.querySelector('nav[class*="sidebar"]')
                 || document.querySelector('div.w-sideBarWidth nav');
        if (!nav) return false;
        const headerDiv = nav.firstElementChild;
        if (!headerDiv) return false;

        // 找 logo(第一個 a 元素)
        const logoA = headerDiv.querySelector('a');
        if (!logoA) return false;

        const newBtn = document.createElement('a');
        newBtn.id = 'pplx-new-btn-header';
        newBtn.href = '/';
        newBtn.setAttribute('aria-label', '新建');
        newBtn.title = '新建對話';
        // 只有 + 圖示,不加文字,保持 icon 風格一致
        newBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>`;
        // 插在 logo 的正後方(logo nextSibling 前)
        if (logoA.nextSibling) {
            headerDiv.insertBefore(newBtn, logoA.nextSibling);
        } else {
            headerDiv.appendChild(newBtn);
        }
        return true;
    }

    // ── v1.9.1:多選擇器找 section,完全不動 nav flex 結構 ──
    function findAnchorSection() {
        // 嘗試各種可能的「新建」aria-label(中英文,有無 draggable)
        const selectors = [
            'a[draggable="false"][aria-label="新建"]',
            'a[aria-label="新建"]',
            'a[aria-label="New"]',
            'a[aria-label="新增"]',
            'a[draggable="false"][href="/"]',
        ];
        for (const sel of selectors) {
            const link = document.querySelector(sel);
            if (!link) continue;
            let el = link;
            for (let i = 0; i < 10; i++) {
                el = el.parentElement;
                if (!el) break;
                if ((el.className || '').includes('collapsible-sidebar-section')) return el;
            }
        }
        // 最後備援:取第一個 collapsible-sidebar-section
        return document.querySelector('div[class*="collapsible-sidebar-section"]') || null;
    }
    function injectSidebarShortcuts() {
        if (document.querySelector('.pplx-newbtn-anchor')) return true;  // 已注入
        const sectionEl = findAnchorSection();
        if (!sectionEl) return false;
        if (sectionEl.dataset.pplxDone) return true;
        sectionEl.dataset.pplxDone = '1';

        // 加 position:relative,讓快捷鈕 absolute 相對此 section 定位(不動 flex)
        sectionEl.classList.add('pplx-newbtn-anchor');

        // 建立快捷鈕群組
        const wrap = document.createElement('div');
        wrap.className = 'pplx-hdr-shortcuts';

        SHORTCUT_DEFS.forEach(({ label, href, svg }) => {
            const a = document.createElement('a');
            a.href = href;
            a.className = 'pplx-hdr-btn';
            a.setAttribute('data-tip', label);
            a.setAttribute('aria-label', label);
            a.innerHTML = svg;
            wrap.appendChild(a);
        });

        sectionEl.appendChild(wrap);
        hideOriginalNavRows();
        return true;
    }

    function hideOriginalNavRows() {
        document.querySelectorAll('div[class*="collapsible-sidebar-section"]').forEach(section => {
            if (section.classList.contains('pplx-hidden-nav-row')) return;
            const link = section.querySelector('a[aria-label]');
            if (link && HIDDEN_LABELS.has(link.getAttribute('aria-label'))) {
                section.classList.add('pplx-hidden-nav-row');
            }
        });
    }

    applySidebarWidth(savedWidth);
    setInterval(() => {
        const el = document.querySelector('div.w-sideBarWidth');
        const _w191 = parseInt(el ? el.style.width : '0');
        if (el && !isNaN(_w191) && _w191 > 60 && _w191 !== savedWidth) applySidebarWidth(savedWidth);
        // 折疊時隱藏青色 resize handle
        const rh = document.getElementById('pplx-resize-handle');
        if (rh) rh.style.display = (!isNaN(_w191) && _w191 < 60) ? 'none' : '';
        fixThreadSectionWidth();
    }, 400);

    let scrollToBottomTimers = [];
    function scheduleScrollToBottom() {
        scrollToBottomTimers.forEach(t => clearTimeout(t));
        scrollToBottomTimers = [];
        [300, 700, 1300, 2500, 4000].forEach(delay => {
            scrollToBottomTimers.push(setTimeout(() => {
                const sc = document.querySelector('.scrollable-container');
                if (sc) sc.scrollTop = sc.scrollHeight;
            }, delay));
        });
    }

    let lastUrl = location.href, lastBubbleScan = 0;
    function checkUrlChange() {
        if (location.href === lastUrl) return;
        lastUrl = location.href;
        lastBubbleScan = 0;
        shortcutsInjected = false;
        setTimeout(fixPageContentWidth, 300);
        setTimeout(fixPageContentWidth, 800);
        scheduleScrollToBottom();
    }

    function expandUserBubbles() {
        const now = Date.now();
        if (now - lastBubbleScan < 600) return;
        lastBubbleScan = now;
        const sc = document.querySelector('.scrollable-container');
        if (!sc || sc.getBoundingClientRect().width < 10) return;
        sc.querySelectorAll('[class*="justify-end"]').forEach(row => {
            if (row._pplxRowFixed || row.children.length < 2) return;
            const children = Array.from(row.children);
            const bubble = children[children.length - 1];
            const ac = children.slice(0, -1).filter(c => {
                const cls = typeof c.className === 'string' ? c.className : '';
                return cls.includes('invisible') || cls.includes('opacity-0') || c.querySelectorAll('button').length > 0;
            });
            if (!ac.length) return;
            row._pplxRowFixed = true; row.style.position = 'relative';
            ac.forEach(el => { el.style.position = 'absolute'; el.style.right = '4px'; el.style.left = 'auto'; el.style.top = '4px'; el.style.zIndex = '20'; });
            bubble.style.setProperty('width', '100%', 'important');
            bubble.style.setProperty('max-width', '100%', 'important');
            bubble.style.setProperty('text-align', 'left', 'important');
        });
    }

    function compressNavIcons() {
        ['32px', '28px'].forEach(px => {
            document.querySelectorAll(`nav [style*="width: ${px}"]`).forEach(el => {
                if (el.style.width === px || el.style.minWidth === px) {
                    el.style.setProperty('width', '20px', 'important');
                    el.style.setProperty('min-width', '20px', 'important');
                }
            });
        });
    }

    const LANG_RE = /^(javascript|typescript|python|java|css|html|sql|bash|sh|shell|json|yaml|xml|go|rust|c\+\+|cpp|c#|ruby|php|swift|kotlin|r|matlab|scala|perl|lua|dart|vue|jsx|tsx|sass|scss|less|toml|ini|dockerfile|makefile|plaintext|text)$/i;
    function getCleanCode(pre) {
        const codeEl = pre.querySelector('code');
        if (codeEl) return codeEl.innerText;
        const clone = pre.cloneNode(true);
        clone.querySelectorAll('[data-testid="code-language-indicator"]').forEach(el => el.remove());
        clone.querySelectorAll('.pplx-code-toolbar,.pplx-code-wrapper').forEach(el => el.remove());
        const raw = clone.innerText.trim();
        const lines = raw.split('\n');
        if (LANG_RE.test((lines[0] || '').trim())) return lines.slice(1).join('\n').trimStart();
        return raw;
    }

    let isGlobalCollapsed = true;
    function ensureGlobalBtn() {
        if (document.getElementById('pplx-global-collapse-btn') || !document.body) return;
        const btn = document.createElement('div');
        btn.id = 'pplx-global-collapse-btn'; btn.textContent = '⏬'; btn.title = '全域折疊/展開代碼';
        btn.onclick = () => {
            isGlobalCollapsed = !isGlobalCollapsed;
            btn.textContent = isGlobalCollapsed ? '⏬' : '⏫';
            document.querySelectorAll('pre.pplx-processed').forEach(pre => {
                const arrow = pre._pplxArrow;
                if (isGlobalCollapsed) { pre.classList.add('pplx-code-collapsed'); if (arrow) { arrow.textContent = '▼ 展開'; arrow.classList.remove('pplx-expanded'); } }
                else { pre.classList.remove('pplx-code-collapsed'); if (arrow) { arrow.textContent = '▲ 折疊'; arrow.classList.add('pplx-expanded'); } }
            });
        };
        document.body.appendChild(btn);
    }

    function processCodeBlocks() {
        document.querySelectorAll('pre:not(.pplx-processed)').forEach(pre => {
            pre.classList.add('pplx-processed');
            if (!pre.parentNode) return;
            const txt = pre.innerText || '';
            const nmMatch = txt.match(/@name\s+([^\n]+)/i);
            const vmMatch = txt.match(/@version\s+([^\n]+)/i);
            const container = document.createElement('div'); container.className = 'pplx-pre-container';
            const wrap = document.createElement('div'); wrap.className = 'pplx-code-wrapper';
            const tbar = document.createElement('div'); tbar.className = 'pplx-code-toolbar';
            const left = document.createElement('div'); left.className = 'pplx-tb-left';
            if (nmMatch) { const n = document.createElement('span'); n.className = 'pplx-code-name'; n.textContent = nmMatch[1].trim(); n.title = nmMatch[1].trim(); left.appendChild(n); }
            if (vmMatch) { const v = document.createElement('span'); v.className = 'pplx-code-ver'; v.textContent = 'v' + vmMatch[1].trim(); left.appendChild(v); }
            const arrow = document.createElement('span');
            arrow.className = 'pplx-code-arrow'; arrow.title = '展開 / 折疊代碼';
            if (isGlobalCollapsed) { arrow.textContent = '▼ 展開'; pre.classList.add('pplx-code-collapsed'); }
            else { arrow.textContent = '▲ 折疊'; arrow.classList.add('pplx-expanded'); }
            arrow.onclick = e => {
                e.preventDefault(); e.stopPropagation();
                const collapsed = pre.classList.toggle('pplx-code-collapsed');
                arrow.textContent = collapsed ? '▼ 展開' : '▲ 折疊';
                arrow.classList.toggle('pplx-expanded', !collapsed);
            };
            left.appendChild(arrow);
            const copyBtn = document.createElement('span');
            copyBtn.className = 'pplx-code-copy'; copyBtn.textContent = '📋'; copyBtn.title = '複製代碼';
            copyBtn.onclick = e => {
                e.preventDefault(); e.stopPropagation();
                const code = getCleanCode(pre);
                const fb = () => { copyBtn.textContent = '✅'; setTimeout(() => copyBtn.textContent = '📋', 2000); };
                if (navigator.clipboard) navigator.clipboard.writeText(code).then(fb).catch(() => { const ta = document.createElement('textarea'); ta.value = code; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); fb(); });
                else { const ta = document.createElement('textarea'); ta.value = code; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); fb(); }
            };
            pre.onclick = () => { if (pre.classList.contains('pplx-code-collapsed')) { pre.classList.remove('pplx-code-collapsed'); arrow.textContent = '▲ 折疊'; arrow.classList.add('pplx-expanded'); } };
            tbar.appendChild(left); tbar.appendChild(copyBtn); wrap.appendChild(tbar);
            pre.parentNode.insertBefore(container, pre);
            container.appendChild(wrap); container.appendChild(pre);
            pre._pplxArrow = arrow;
        });
    }

    let isResizing = false, animId = null;
    function ensureResizeHandle() {
        if (document.getElementById('pplx-resize-handle') || !document.body) return;
        const h = document.createElement('div'); h.id = 'pplx-resize-handle'; h.title = '拖曳側欄寬度 | 雙擊還原';
        const c = document.createElement('div'); c.id = 'pplx-drag-curtain';
        document.body.appendChild(h); document.body.appendChild(c);
        h.addEventListener('mousedown', e => { isResizing = true; h.classList.add('active'); document.body.classList.add('pplx-resizing'); e.preventDefault(); });
        window.addEventListener('mousemove', e => { if (!isResizing) return; if (animId) cancelAnimationFrame(animId); animId = requestAnimationFrame(() => applySidebarWidth(Math.min(Math.max(e.clientX, MIN_W), MAX_W))); });
        window.addEventListener('mouseup', () => { if (!isResizing) return; isResizing = false; h.classList.remove('active'); document.body.classList.remove('pplx-resizing'); try { GM_setValue('pplx_sidebar_width', savedWidth); } catch (_) { } });
        h.addEventListener('dblclick', () => { applySidebarWidth(185); try { GM_setValue('pplx_sidebar_width', 185); } catch (_) { } });
    }

    let originalTitle = document.title, tabState = 'IDLE', wasGenerating = false;
    function setTabState(s) { let t = originalTitle; if (s === 'GENERATING') t = '【⏳】 ' + originalTitle; else if (s === 'DONE') t = '【✅】 ' + originalTitle; if (document.title !== t) document.title = t; }
    window.addEventListener('focus', () => { if (tabState === 'DONE') { tabState = 'IDLE'; setTabState('IDLE'); } });
    window.addEventListener('click', () => { if (tabState === 'DONE') { tabState = 'IDLE'; setTabState('IDLE'); } });
    function detectGenerating() {
        const stop = document.querySelector('button[aria-label*="Stop"],button[aria-label*="停止"]');
        const gen = !!(stop && stop.offsetParent !== null);
        if (gen && !wasGenerating) { tabState = 'GENERATING'; setTabState(tabState); wasGenerating = true; if (!originalTitle.includes('【')) originalTitle = document.title; }
        else if (!gen && wasGenerating) { tabState = 'DONE'; setTabState(tabState); wasGenerating = false; }
        if (tabState === 'IDLE' && !document.title.includes('【')) originalTitle = document.title;
    }

    function maintainUI() {
        ensureResizeHandle();
        watchSidebarElement();
        ensureGlobalBtn();
        processCodeBlocks();
        detectGenerating();
        checkUrlChange();
        expandUserBubbles();
        compressNavIcons();
        fixPageContentWidth();
        if (!shortcutsInjected) shortcutsInjected = injectSidebarShortcuts();
        injectNewBtnToHeader();
        hideOriginalNavRows();
    }
    setInterval(maintainUI, 300);
    maintainUI();
    scheduleScrollToBottom();
})();