blacksmithgu / obsidian-dataview

A data index and query language over Markdown files, for https://obsidian.md/.
https://blacksmithgu.github.io/obsidian-dataview/
MIT License
6.98k stars 410 forks source link

Multiple dataviews in one place #2268

Open coop1661 opened 7 months ago

coop1661 commented 7 months ago

I’m looking for guidance on creating multiple views in one place at Obsidian DataView, similar to the functionality available in Notion. The idea is that I will have a view with tabs that I can jump between.

GottZ commented 7 months ago

what a coincidence.. I was also thinking about the lack of tabs and how to solve this. did you toy around with a custom view yet? I was thinking of creating one, that simply takes an array of section links, and uses their headings as tab labels, and embeds the contents as tab content. This would have to be a tad more customizable though. especially if the section links have the overlapping titles.

like:

dv.view("tabs", ["foo.md#Tasks", "bar.md#issues"]);
Atomesh commented 5 months ago

By using minitabs and directly manipulating the DOM, this effect can be achieved at a lower cost. The following example also uses customJS for easier reuse.

renderMapToTabs(dv, map, functionToValue) {
    let titleList = Array.from(map.keys());
    let valueFunctionList = Array.from(map.values()).map(value => () => functionToValue(dv, value));

    let minitabs = "```minitabs \n";
    minitabs += "tabs \n";
    titleList.forEach(title => minitabs += `\`${title}\``);
    titleList.forEach(() => minitabs += `\n=== \n`);
    minitabs += "\n```";
    dv.span(minitabs);

    valueFunctionList.forEach((valueFunction,index) => {
        valueFunction();
        setTimeout(() => dv.container.children[0].children[0].children[0].children[0].children[1].children[index].appendChild(dv.container.children[1]), 0);
    });
}

Here, dv is used as a parameter when calling customJS; if you are using it directly in the code block, you can ignore it. map doesn't need explanation; it represents the content to be rendered. functionToValue is a method used to process the value. Additionally, please note that since my application scenario is relatively fixed, the DOM positions in the code are hard-coded. If your usage is different, remember to modify it accordingly.

An example of usage is as follows:

renderRowsGroupBySubpathMap(dv, rowsGroupBySubpathMap) {
    let functionToValue = (dv, rows) => {
        if (rows.length == 0) {
            dv.span('');
            return;
        }
        let tableTitle = ["文件 - File", "属性 - Field", "主要 - Main", "次要 - Second"];
        let tableItems = rows.map(row => this.rowToArray(row));
        dv.table(tableTitle, tableItems);
    }

    this.renderMapToTabs(dv, rowsGroupBySubpathMap, functionToValue);
}
customJS.Dataview_API.renderRowsGroupBySubpathMap(dv,customJS.Dataview_API.getContainPageRowsGroupBySubpathMap(dv.current(),dv.current()));

The final effect is shown in the image, using custom CSS to change the default style of minitabs. image image