wilsons
关注
142093 号成员,2024-05-12 13:24:23 加入
4.7k
个人主页 浏览
2.7k
帖子 + 回帖 + 评论
正式入驻知乎了,以后新贴主要在这里。 欢迎大家订阅关注! 你的关注对我是莫大鼓励,也能让我持续产出优质内容,我们一起成长 🙏 点这里立即关注:https://www.zhihu.com/people/wilsonses
  • [js] 思源屏保,酷炫防偷窥

    2025-08-04 21:19

    代码织就锦屏新,
    字走龙蛇避烙痕。
    十息未动轻纱落,
    半藏玄机半护君。

  • 震惊,思源表格和数据库竟然可以用 SQL 查询

    2025-08-04 18:15

    这个是因为获取数据和思源渲染数据用的不同的 api,当涉及排序和筛选时可能会出现这个问题,后面考虑怎么修复。

  • 震惊,思源表格和数据库竟然可以用 SQL 查询

    2025-08-04 18:14

    这个现实太复杂,目前没有更好的解决办法。唯一可行的办法,是根据数据把模板中的值按照模板的逻辑重新计算一遍。

  • 你应当有个免费的 webdav(一场由浏览器升级引发的“数据灾难”)

    2025-08-04 15:54

    国内用坚果云也不错

    刚才看了下每月上传 1g/下载 3g 限制,如果小文件同步,还是不错的。

  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-08-04 12:34

    夫大者载物,小者藏精;不执于巨,不溺于微,执中守一,乃见天地之妙trollface

  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-08-03 13:11

    菜单轻滑如梦行,
    心随指动共风轻。
    往事如烟随风逝,
    唯有丝滑入梦萦。

  • 取消标签搜索的自动分屏

    2025-08-02 19:18

    通过 [js] 连续点击 openAny,小代码,大作用,让一切触手可达 可以实现。

    缺点:已有左右分屏的情况下其他左右分屏也会被取消(思源设计如此,已提改进 issue

    效果

    r162.gif

    代码

    // 利用openAny取消标签搜索分屏(点击标签生效)
    // 缺点:已有左右分屏的情况下其他分屏也会被取消(思源设计如此,已提issue)
    // issue https://github.com/siyuan-note/siyuan/issues/15416
    document.addEventListener('click', async (event) => {
        const target = event.target;
        if (target instanceof HTMLSpanElement && target.dataset.type === 'tag') {
            const searchTab = await openAny.fn.whenElementExistOrNull(()=>{
                const focusTab = openAny.queryEl(`.layout__wnd--active .layout-tab-bar [data-type="tab-header"].item--focus`);
                if(focusTab && focusTab.textContent.trim() === window.siyuan.languages.search) return focusTab;
            });
            if(!searchTab) return;
            openAny.press('mouseright', searchTab).click('#commonMenu [data-id="unsplit"]');
        }
    });
    
  • 开源因尊重而美好

    2025-08-01 23:28

    确实,目前没有更好的办法。

    维权太难,小范围只能睁一只眼闭一只眼。

    大范围和严重的可先提醒,拒不听的可通过举报和声讨。

  • 求助复制图片时获取“提示文本”的内容

    2025-08-01 21:32

    综上所述,你可以在 quicker 获取选中文本内容时选择 html,然后解析出 <img> 标签的 title 即可

    quicker 步骤如下

    image.png

    image.png

    最终获取结果

    image.png

    把这个结果复制给 ai,分分钟钟给你提取想要的数据,js,c#各种语言都可以。

    或者也可以让 quicker 模拟先按 Esc,再模拟按 ctrl+c,看个人喜好。

  • 求助复制图片时获取“提示文本”的内容

    2025-08-01 20:59

    你粘贴到记事本就好了,粘贴为纯文本可能会过滤掉 Markdown 标记

  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-08-01 20:38

    我的分辨率比较高,可能用不上了

    还是有机会的,比如

    分屏时,窗口缩小时,开启控制台时,各种情况引起的可视区域变小等就显得菜单多了,这时需要trollface

  • 求助复制图片时获取“提示文本”的内容

    2025-08-01 20:24

    估计是你插件或代码片段等影响导致的,我这边 3.2.1 复制正常。

    建议在新空间测试看看,以排除干扰项。

  • 在使用 [[ 或者【【的时候想引用本文档的可能会引用到外部文档

    2025-08-01 19:33

    效果如下,样式和排序可在代码开头的参数里按说明修改

    image.png

    代码

    // 自定义引用列表排序和样式
    // see https://ld246.com/article/1754037296210
    (()=>{
        // 是否优先显示当前文档的块
        const isShowCurrDocBlocksFirst = true;
      
        // 这里设置列表样式👇
        addStyle(`
            /* 设置列表文本样式 */
            .protyle-hint .b3-list-item:has(.search-ref-curr-doc-item) .b3-list-item__text{
                color: green;
                font-weight: bold;
            }
            /* 设置列表path等样式 */
            .protyle-hint .b3-list-item:has(.search-ref-curr-doc-item) .b3-list-item__meta{
                color: red;
            }
        `);
    
        // 获取引用列表
        searchRefBlockSortBy(isShowCurrDocBlocksFirst);
        // isSortByCurrDocId 是否按当前文档id优先排序
        function searchRefBlockSortBy(isSortByCurrDocId = true) {
            const originalFetch = window.fetch;
            window.fetch = async function (url, init) {
                // 真正发请求
                const response = await originalFetch(url, init);
      
                // 只处理目标接口
                if (url.toString().toLowerCase().endsWith('/api/search/searchrefblock')) {
                    const docId = (document.querySelector('[data-type="wnd"].layout__wnd--active .protyle:not(.fn__none)')||document.querySelector('[data-type="wnd"] .protyle:not(.fn__none)'))?.querySelector('.protyle-title')?.dataset?.nodeId;
                    const docIds = docId ? [docId] : [];
                    try {
                        // 克隆一份 response,用来读 body
                        const cloned = response.clone();
                        const bodyJson = await cloned.json();
                        const blocks = bodyJson?.data?.blocks;
                        if (Array.isArray(blocks) && blocks.length > 0) {
                            // 设置颜色
                            blocks.forEach(block => {
                                // 设置样式标记
                                if(docIds.includes(block.rootID)) block.content = `<span class="search-ref-curr-doc-item">${block.content}</span>`;
                            });
                        
                             // 排序返回结果
                            let sortedBlocks = [];
                            if(isSortByCurrDocId && docIds.length) sortedBlocks = sortByDocIds(blocks, docIds);
                            if(sortedBlocks.length) bodyJson.data.blocks = sortedBlocks;
                        
                            // 把修改后的数据串回去,构造一个新的 Response
                            const newBody = JSON.stringify(bodyJson);
                            const { status, statusText, headers } = response;
                            return new Response(newBody, { status, statusText, headers });
                        }
                    } catch (e) {
                        // 如果不是 JSON,直接返回原始 response
                        console.log(e);
                        return response;
                    }
                }
      
                // 默认返回原始 response
                return response;
            };
            // 按id列表顺序排序,相同的按原序不动
            function sortByDocIds(blocks, docIds) {
                const orderMap = new Map(docIds.map((id, idx) => [id, idx]));
                return blocks.sort((a, b) => {
                    const orderA = orderMap.has(a.rootID) ? orderMap.get(a.rootID) : Infinity;
                    const orderB = orderMap.has(b.rootID) ? orderMap.get(b.rootID) : Infinity;
                    return orderA - orderB;
                });
            }
        }
        function addStyle(css) {
            const style = document.createElement('style');
            style.textContent = css;
            document.head.appendChild(style);
        }
    })();
    

    参考帖子 有什么办法可以在搜索双链时优先展示某些路径下的内容块呀

  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-08-01 07:47

    @alanelminster @queguaiya @chenshinshi @qiancang @HugZephyr @PearlLin @XuanJoy
    @1ssss @Ganymede @leolee @5kyfkr @Mustakshif @ACai @nightstars @8V9q7V @Sonsy
    @Silva @mecoren @wucunwei @mm-o @shawnkurt @openAI @siyuan100861186
    @suxiang999 @att88 @gcdjbr @JeffreyChen @heiyi

    0.0.7 迎来重大更新!建议升级!

    ⚠️ 风险提醒:0.0.6 版,当窗口拖动后,子菜单显示可能会乱,需要重新打开菜单才行。

    更新内容:

    1. 从根本上解决子菜单跳动问题
    2. 修复视窗变化时菜单可能错乱问题;
    3. 修复鸿蒙手机版,菜单不可滑动问题,感谢 @5kyfkr 反馈
  • [js][css] 请问有没有 CSS/JS 代码可以控制文档树和大纲等栏目的最低宽度?

    2025-07-30 18:18

    js 方案

    @JeffreyChen 我测试下来发现 css 版不够稳定,经常不生效,我用 js 写了一版

    // 自定义侧边栏最小宽度限制
    setTimeout(() => {
        // 设置侧边栏最小宽度
        const minWidth = 100;
      
        if (!!document.getElementById("sidebar")) return; // 手机版返回
        const dockl = document.querySelector('.layout__dockl');
        const resizerl = getNextResizeLr(dockl);
        const dockr = document.querySelector('.layout__dockr');
        const resizerr = getPreviousResizeLr(dockr);
    
        let isDragging = false, dockType = '';
    
        // 鼠标按下开始拖动
        resizerl.addEventListener('mousedown', (e) => {
            isDragging = true;
            dockType = 'l';
        });
        resizerr.addEventListener('mousedown', (e) => {
            isDragging = true;
            dockType = 'r';
        });
    
        // 鼠标移动,调整宽度
        document.addEventListener('mousemove', (e) => {
            if (!isDragging || !dockType) return;
            const dockEl = dockType === 'l' ? dockl : dockr;
        
            // 计算鼠标相对于页面左侧的位置
            const newWidth = dockType === 'l' ?
                e.clientX - dockEl.getBoundingClientRect().left :
                dockEl.getBoundingClientRect().right - e.clientX;
    
            // 设置最小和最大宽度限制(可选)240之外用思源自带拖动即可
            if (newWidth >= minWidth && newWidth < 240) {
                dockEl.style.width = `${newWidth}px`;
            }
        });
    
        // 鼠标释放,结束拖动
        document.addEventListener('mouseup', () => {
            if (isDragging) {
                isDragging = false;
                dockType = '';
            }
        });
    
        function getNextResizeLr(el) {
            let sibling = el.nextElementSibling;
            while (sibling) {
                if (sibling.matches('.layout__resize--lr')) {
                    return sibling;
                }
                sibling = sibling.nextElementSibling;
            }
            return null;
        }
        function getPreviousResizeLr(el) {
            let sibling = el.previousElementSibling;
            while (sibling) {
                if (sibling.matches('.layout__resize--lr')) {
                    return sibling;
                }
                sibling = sibling.previousElementSibling;
            }
            return null; // 没找到
        }
    }, 2000);
    
  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-07-30 18:08

    if(("ontouchstart" in window) && navigator.maxTouchPoints > 1) return; // 触碰设备跳过

    这个限制不起作用?

    你试试这个,手机版都跳过

    if(!!document.getElementById("sidebar")) return; // 手机版跳过

  • [js] 属性引用:彻底解决引用丢失问题

    2025-07-30 17:05

    @lianhenhei @Finnsmoge @wucunwei @sunrain @hg124848 @FlyingY @EonWen

    @ACai @8V9q7V @PearlLin @shaoxia @TaxolNorth @sweesalt @leeyaunlong

    0.0.6 重大更新!

    彻底解决全局搜索时,可能导致的搜索框失去焦点问题(0.0.6 之前虽然也解决了搜索失焦问题,但治标不治本,0.0.6 从根源抓起,彻底解决了该问题)

    ⚠️ 风险提醒:0.0.6 之前可能会导致全局搜索时,搜索输入框失去焦点,而预览窗口获得焦点,从而导致误输问题,建议立刻马上更新!

  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-07-30 06:46

    @qiancang @HugZephyr @PearlLin @XuanJoy @1ssss @Ganymede @leolee @5kyfkr @Mustakshif @ACai @nightstars @8V9q7V @att88 @gcdjbr @JeffreyChen @heiyi @wucunwei @mm-o @shawnkurt @openAI @suxiang999

    0.0.6 升级啦!

    彻底解决鼠标移入移出子菜单时,子菜单出现轻微跳动问题

  • 思源笔记与博思白板

    2025-07-30 00:01

    仅仅嵌入,无法与思源发生关联

    也可以叫 ob 最强白板 哈哈哈

  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-07-29 22:57

    @qiancang @HugZephyr @PearlLin @XuanJoy @1ssss @Ganymede @leolee @5kyfkr @Mustakshif @ACai @nightstars @8V9q7V @att88 @gcdjbr @JeffreyChen @heiyi @wucunwei @mm-o @shawnkurt @openAI

    0.0.5 升级啦!

    更新内容:

    改进体验,修复鼠标从主菜单移向子菜单时,子菜单会出现跳动的问题等。

  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-07-29 14:45

    比如插件自己实现的菜单,不是思源的 #commonMenu,就不能自动滚动。

    如果作者不用插件提供的方法,自己实现,谁都没办法。这个无法避免。即使思源原生方式,如果用户不设置 overflow:auto,甚至不能滚动,这得作者自己负责。

    然后就是如果插件用了 #commonMenu,但添加百十来个选项,自动滚动就会太快

    这个我感觉还可以,且这种情况极少,另外 0.0.3 版我加了 maxMenuItems 参数,可设置最大菜单项数,超过指定的数目将不使用该效果。

    改进后:

    改进前:

  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-07-29 14:00

    有的菜单自动滚动,有的又不行。

    如果菜单选项多了,动一下鼠标就会越过很多选项,反而很难点中。

    这两个问题什么意思?可否录屏看看?

    目前和 ob 体验一致,在 ob 社区也没看到有反馈你说的问题,我相信还是可靠的。

    唯一不同的是,思源无法从主菜单斜移到子菜单,但这是思源本身实现机制的原因,不用这个效果也不支持。

  • [js] 好玩:模仿 obsidian 自滚动菜单,丝滑!

    2025-07-28 23:12

    @ACai @nightstars @8V9q7V

    0.0.2 升级啦!

    1. 支持子菜单啦
    2. 去除菜单滚动条
  • 关于 ob 和思源的界面区别的想法

    2025-07-28 19:27

    不是可以吗?

    image.png

  • [js] 窗口宽度自适应变化(自动显示 / 隐藏侧边栏)

    2025-07-28 18:40

    其实我觉得不用这么麻烦,即无需这么多判断,只需判断窗口宽度即可。

    根据你的描述,大概有 3 种状态,1 两侧固定 2 仅左侧固定 3 两侧都不固定(隐藏)

    那么只需要判断 1 和 2 即可,且仅需判断窗口宽度即可,临界值根据自己需要修改。

    比如以下代码,经测试我觉得可以满足需求。

    // 窗口宽度自适应变化(自动显示/隐藏侧边栏)
    window.addEventListener('resize', () => {
        // 两侧固定阈值,当窗口大于这个值时两侧固定(可根据自己需要修改)
        const bothFixedBreakpoint = 1100;
      
        // 左侧固定阈值,当窗口大于这个值时左侧固定(可根据自己需要修改)
        const leftSideFixedBreakpoint = 800;
      
        if(!!document.getElementById("sidebar")) return; // 手机版跳过
        const leftPin = document.querySelector('#dockLeft .dock__item--pin');
        const rightPin = document.querySelector('#dockRight .dock__item--pin');
        const isPin = (pin) => !!pin.querySelector('svg use[*|href="#iconUnpin"]');
        const hideDock = (dock) => {
            let sign = '', dockEl;
            if(dock === 'left') {
                sign = '-';
                dockEl = document.querySelector('#layouts .layout__dockl.layout--float');
            } else {
                dockEl = document.querySelector('#layouts .layout__dockr.layout--float');
            }
            if(dockEl && !dockEl.style.transform) {
                // https://github.com/siyuan-note/siyuan/blob/5f0f4e3ba6aabd5af26f9879695e5b9b796b5fb9/app/src/layout/dock/index.ts#L478
                dockEl.style.transform = `translateX(${sign}${dockEl.clientWidth + 8}px)`;
                dockEl.style.opacity = "0";
            }
        }
        if(window.innerWidth > bothFixedBreakpoint) {
            // 两侧固定
            if(!isPin(leftPin)) leftPin.click();
            if(!isPin(rightPin)) rightPin.click();
        } else if(window.innerWidth > leftSideFixedBreakpoint) {
            // 左侧固定
            if(!isPin(leftPin)) leftPin.click();
            if(isPin(rightPin)) {rightPin.click();hideDock('right');}
        } else {
            // 两侧都不固定(隐藏)
            if(isPin(leftPin)) {leftPin.click();hideDock('left')}
            if(isPin(rightPin)) {rightPin.click();hideDock('right');}
        }
    });
    

    r159.gif


    版本 2,可能这个版本更符合你的需求

    // 窗口宽度自适应变化(自动显示/隐藏侧边栏)
    window.addEventListener('resize', () => {
        // 编辑器最小宽度,当窗口宽度大于编辑器最小宽度+两侧宽度时全固定,当仅容纳一个侧栏时左侧固定,否则全隐藏
        const minEditorWidth = 600;
    
        if(!!document.getElementById("sidebar")) return; // 手机版跳过
        const leftPin = document.querySelector('#dockLeft .dock__item--pin');
        const rightPin = document.querySelector('#dockRight .dock__item--pin');
        const isPin = (pin) => !!pin.querySelector('svg use[*|href="#iconUnpin"]');
        const hideDock = (dock) => {
            let sign = '', dockEl;
            if(dock === 'left') {
                sign = '-';
                dockEl = document.querySelector('#layouts .layout__dockl.layout--float');
            } else {
                dockEl = document.querySelector('#layouts .layout__dockr.layout--float');
            }
            if(dockEl && !dockEl.style.transform) {
                // https://github.com/siyuan-note/siyuan/blob/5f0f4e3ba6aabd5af26f9879695e5b9b796b5fb9/app/src/layout/dock/index.ts#L478
                dockEl.style.transform = `translateX(${sign}${dockEl.clientWidth + 8}px)`;
                dockEl.style.opacity = "0";
            }
        }
        const leftSideWdith = document.querySelector('#layouts .layout__dockl')?.offsetWidth || 0;
        const rightSideWidth = document.querySelector('#layouts .layout__dockr')?.offsetWidth || 0;
        if((window.innerWidth -  minEditorWidth) > (leftSideWdith + rightSideWidth)) {
            // 两侧固定
            if(!isPin(leftPin)) leftPin.click();
            if(!isPin(rightPin)) rightPin.click();
        } else if((window.innerWidth -  minEditorWidth) > leftSideWdith) {
            // 左侧固定
            if(!isPin(leftPin)) leftPin.click();
            if(isPin(rightPin)) {rightPin.click();hideDock('right');}
        } else {
            // 两侧都不固定(隐藏)
            if(isPin(leftPin)) {leftPin.click();hideDock('left')}
            if(isPin(rightPin)) {rightPin.click();hideDock('right');}
        }
    });
    

    版本 3,兼容性更好,兼容直接拖动侧边栏的情况

    // 窗口宽度自适应变化(自动显示/隐藏侧边栏)
    setTimeout(() => {
        // 编辑器最小宽度,当窗口宽度大于编辑器最小宽度+两侧宽度时全固定,当仅容纳一个侧栏时左侧固定,否则全隐藏
        const minEditorWidth = 600;
        
        const layoutCenter = document.querySelector('.layout__center');
        if(!layoutCenter) return;
        new ResizeObserver((entries) => {
            const leftPin = document.querySelector('#dockLeft .dock__item--pin');
            const rightPin = document.querySelector('#dockRight .dock__item--pin');
            const isPin = (pin) => !!pin.querySelector('svg use[*|href="#iconUnpin"]');
            const hideDock = (dock) => {
                let sign = '', dockEl;
                if(dock === 'left') {
                    sign = '-';
                    dockEl = document.querySelector('#layouts .layout__dockl.layout--float');
                } else {
                    dockEl = document.querySelector('#layouts .layout__dockr.layout--float');
                }
                if(dockEl && !dockEl.style.transform) {
                    // https://github.com/siyuan-note/siyuan/blob/5f0f4e3ba6aabd5af26f9879695e5b9b796b5fb9/app/src/layout/dock/index.ts#L478
                    dockEl.style.transform = `translateX(${sign}${dockEl.clientWidth + 8}px)`;
                    dockEl.style.opacity = "0";
                }
            }
            const leftSideWdith = document.querySelector('#layouts .layout__dockl')?.offsetWidth || 0;
            const rightSideWidth = document.querySelector('#layouts .layout__dockr')?.offsetWidth || 0;
            if((window.innerWidth -  minEditorWidth) > (leftSideWdith + rightSideWidth)) {
                // 两侧固定
                if(!isPin(leftPin)) leftPin.click();
                if(!isPin(rightPin)) rightPin.click();
            } else if((window.innerWidth -  minEditorWidth) > leftSideWdith) {
                // 左侧固定
                if(!isPin(leftPin)) leftPin.click();
                if(isPin(rightPin)) {rightPin.click();hideDock('right');}
            } else {
                // 两侧都不固定(隐藏)
                if(isPin(leftPin)) {leftPin.click();hideDock('left')}
                if(isPin(rightPin)) {rightPin.click();hideDock('right');}
            }
        }).observe(layoutCenter);
    }, 2000);
    
  • 集市为什么进不去 有知道原因的吗?

    2025-07-28 14:44

    思源集市好奇怪,明明国内镜像加速了,结果速度和稳定度还不如 ob。感觉可能镜像没生效。

  • 关于 ob 和思源的界面区别的想法

    2025-07-28 14:16

    按你的说法反而思源更好,不用打开侧边栏就可以找了,obsidian 多一步。

    我觉得 ob 在于细腻,空间布局利用率高。思源界面太浪费空间了。

  • [js] 属性引用:彻底解决引用丢失问题

    2025-07-28 13:14

    @lianhenhei @Finnsmoge @wucunwei @sunrain @hg124848

    @FlyingY @EonWen @ACai @8V9q7V @PearlLin

    0.0.5 重大更新!

    ⚠️ 风险提醒:0.0.4 不小心加了调试代码,导致代码失效,建议立刻马上更新!

    1. 去除 0.0.4 调试代码(导致代码不生效的问题)
    2. 新增支持超级链接的引用丢失问题