mirror of
https://github.com/vitovt/obsidian-csv-modern-codeblock.git
synced 2026-07-22 14:30:23 +00:00
Prepare CSV Modern Codeblock for 1.0.0 release
This commit is contained in:
parent
f9595ebd6b
commit
5a2d504e14
5 changed files with 184 additions and 27 deletions
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2026 vitovt
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
137
README.md
Normal file
137
README.md
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
# CSV Modern Codeblock
|
||||
|
||||
CSV Modern Codeblock renders `csv` and `tsv` fenced code blocks as interactive tables inside Obsidian.
|
||||
|
||||
This plugin was rewritten from scratch for modern table UX, stricter CSV handling, and better behavior with data-heavy notes. It was inspired by the original CSV Codeblock idea, but it is not a fork.
|
||||
|
||||
Repository:
|
||||
https://github.com/vitovt/obsidian-csv-modern-codeblock
|
||||
|
||||
Original project that inspired the concept:
|
||||
https://github.com/elrindir/obsidian-csv-codeblock
|
||||
|
||||
## Why This Plugin Exists
|
||||
|
||||
Markdown tables are tedious when the data is large, frequently edited, copied from spreadsheets, or full of long text. CSV and TSV are much easier to write, paste, diff, and maintain in source form. This plugin keeps that convenient source format while rendering it as a much more usable table in preview.
|
||||
|
||||
## Features
|
||||
|
||||
- Renders `csv` and `tsv` code blocks as tables directly in notes
|
||||
- Uses the first row as the header by default
|
||||
- Supports quoted fields, escaped quotes, quoted commas, multiline quoted cells, trailing empty cells, and CRLF line endings
|
||||
- Auto-detects comma and semicolon delimiters for `csv` blocks
|
||||
- Reports malformed CSV with a clear explanation that includes row, field, and line information
|
||||
- Detects `http`, `https`, and `mailto` values and renders them as links
|
||||
- Keeps header rows sticky by default
|
||||
- Uses a vertically scrollable table area for tall datasets
|
||||
- Adds a toolbar with optional view controls for sorting, per-column filtering, compact mode, zebra striping, and high-table mode
|
||||
- Supports per-codeblock options for title, layout, filtering, sorting, links, delimiter selection, and height
|
||||
|
||||
## Performance And Implementation Improvements
|
||||
|
||||
Compared with the earlier plugin idea, this rewrite adds:
|
||||
|
||||
- A real CSV parser instead of splitting rows on delimiters
|
||||
- Correct handling of escaped and quoted fields
|
||||
- Delimiter autodetection for semicolon-separated CSV exports
|
||||
- Stronger malformed-input validation instead of silently rendering broken tables
|
||||
- Direct row rendering without building a separate full parsed matrix first
|
||||
- Lower memory pressure for large tables
|
||||
- A dedicated stylesheet for table presentation and theme integration
|
||||
|
||||
## Default Behavior
|
||||
|
||||
- The first row is treated as the header
|
||||
- Sticky headers are enabled
|
||||
- A base vertical scroll area is enabled
|
||||
- Sorting is off until you press `Sorting`
|
||||
- Per-column filtering is off until you press `Filtering`
|
||||
- Compact mode is off until you press `Compact`
|
||||
- Zebra striping is off until you press `Zebra`
|
||||
- High-table mode is off until you press `High table`
|
||||
|
||||
## Basic Usage
|
||||
|
||||
````markdown
|
||||
```csv
|
||||
Name,Role,City
|
||||
Alice,Researcher,Berlin
|
||||
Bob,Editor,Paris
|
||||
```
|
||||
````
|
||||
|
||||
TSV works the same way:
|
||||
|
||||
````markdown
|
||||
```tsv
|
||||
Name Role City
|
||||
Alice Researcher Berlin
|
||||
Bob Editor Paris
|
||||
```
|
||||
````
|
||||
|
||||
## Toolbar Controls
|
||||
|
||||
Each rendered table includes a toolbar above it:
|
||||
|
||||
- `Sorting` enables sorting by clicking header cells
|
||||
- `Filtering` shows a filter input under each header column
|
||||
- `Compact` switches to fit-to-width mode
|
||||
- `Zebra` toggles alternating row striping
|
||||
- `High table` doubles the vertical scroll height
|
||||
|
||||
These controls change only the rendered view. They do not modify your source data.
|
||||
|
||||
## Codeblock Options
|
||||
|
||||
You can set per-table defaults directly on the opening fence line:
|
||||
|
||||
````markdown
|
||||
```csv title:"Folktales" sort:true filter:true compact:true zebra:true high-table:true
|
||||
Nr.;Titel;Quelle
|
||||
1;Der Froschkönig;https://projekt-gutenberg.org/
|
||||
```
|
||||
````
|
||||
|
||||
Supported options:
|
||||
|
||||
- `title:"..."`
|
||||
- `header:true|false`
|
||||
- `sticky:true|false`
|
||||
- `sort:true|false`
|
||||
- `filter:true|false`
|
||||
- `compact:true|false`
|
||||
- `zebra:true|false`
|
||||
- `high-table:true|false`
|
||||
- `links:true|false`
|
||||
- `delimiter:auto|comma|semicolon|tab`
|
||||
- `max-height:<css-size>`
|
||||
|
||||
Examples:
|
||||
|
||||
- `delimiter:semicolon`
|
||||
- `max-height:32rem`
|
||||
- `compact:true`
|
||||
- `filter:true`
|
||||
|
||||
## Submission And Privacy Disclosures
|
||||
|
||||
- No network requests
|
||||
- No telemetry, analytics, ads, or tracking
|
||||
- No accounts, subscriptions, or payments
|
||||
- No external services
|
||||
- No access to files outside normal Obsidian plugin execution and rendered note content
|
||||
- Fully local behavior inside Obsidian
|
||||
- Open source
|
||||
|
||||
## Inspiration
|
||||
|
||||
CSV Modern Codeblock was inspired by the original CSV Codeblock plugin:
|
||||
|
||||
https://github.com/elrindir/obsidian-csv-codeblock
|
||||
|
||||
This project is a separate rewrite with a new codebase, different implementation, added validation, performance-focused parsing changes, and expanded table functionality.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
30
main.js
30
main.js
|
|
@ -462,7 +462,7 @@ function createFilterController(doc, head, headerRow, rows) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
row.element.style.display = isVisible ? "" : "none";
|
||||
row.element.hidden = !isVisible;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -474,7 +474,7 @@ function createFilterController(doc, head, headerRow, rows) {
|
|||
|
||||
const setEnabled = (nextEnabled) => {
|
||||
enabled = nextEnabled;
|
||||
filterRow.style.display = enabled ? "" : "none";
|
||||
filterRow.hidden = !enabled;
|
||||
if (!enabled) {
|
||||
clearFilters();
|
||||
}
|
||||
|
|
@ -500,6 +500,14 @@ function resolveMaxHeight(maxHeight, highTableEnabled) {
|
|||
return `calc(${maxHeight} * 2)`;
|
||||
}
|
||||
|
||||
function setCssVariable(element, name, value) {
|
||||
if (element.style && typeof element.style.setProperty === "function") {
|
||||
element.style.setProperty(name, value);
|
||||
} else {
|
||||
element.style[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
function setWrapperClasses(wrapper, state, stickyEnabled) {
|
||||
wrapper.className = [
|
||||
"csv-codeblock",
|
||||
|
|
@ -518,11 +526,7 @@ function updateStickyOffsets(wrapper, headerRow) {
|
|||
} else if (headerRow && typeof headerRow.offsetHeight === "number") {
|
||||
height = headerRow.offsetHeight;
|
||||
}
|
||||
if (wrapper.style && typeof wrapper.style.setProperty === "function") {
|
||||
wrapper.style.setProperty("--csv-codeblock-header-height", `${Math.ceil(height || 0)}px`);
|
||||
} else {
|
||||
wrapper.style["--csv-codeblock-header-height"] = `${Math.ceil(height || 0)}px`;
|
||||
}
|
||||
setCssVariable(wrapper, "--csv-codeblock-header-height", `${Math.ceil(height || 0)}px`);
|
||||
};
|
||||
|
||||
if (typeof requestAnimationFrame === "function") {
|
||||
|
|
@ -789,11 +793,7 @@ class CsvCodeBlockPlugin extends import_obsidian.Plugin {
|
|||
let isHeaderRow = options.header;
|
||||
let headerRowElement = null;
|
||||
let applyState = () => {
|
||||
if (wrapper.style && typeof wrapper.style.setProperty === "function") {
|
||||
wrapper.style.setProperty("--csv-codeblock-max-height", resolveMaxHeight(options.maxHeight, state.highTable));
|
||||
} else {
|
||||
wrapper.style["--csv-codeblock-max-height"] = resolveMaxHeight(options.maxHeight, state.highTable);
|
||||
}
|
||||
setCssVariable(wrapper, "--csv-codeblock-max-height", resolveMaxHeight(options.maxHeight, state.highTable));
|
||||
toolbar.update(state);
|
||||
};
|
||||
|
||||
|
|
@ -891,11 +891,7 @@ class CsvCodeBlockPlugin extends import_obsidian.Plugin {
|
|||
const sortController = createSortController(body, sortableHeaders, dataRows);
|
||||
applyState = () => {
|
||||
setWrapperClasses(wrapper, state, options.sticky);
|
||||
if (wrapper.style && typeof wrapper.style.setProperty === "function") {
|
||||
wrapper.style.setProperty("--csv-codeblock-max-height", resolveMaxHeight(options.maxHeight, state.highTable));
|
||||
} else {
|
||||
wrapper.style["--csv-codeblock-max-height"] = resolveMaxHeight(options.maxHeight, state.highTable);
|
||||
}
|
||||
setCssVariable(wrapper, "--csv-codeblock-max-height", resolveMaxHeight(options.maxHeight, state.highTable));
|
||||
sortController.setEnabled(state.sort && options.header);
|
||||
filterController.setEnabled(state.filter && options.header);
|
||||
toolbar.update(state);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"id": "csv-codeblock",
|
||||
"name": "CSV Codeblock",
|
||||
"version": "1.1.0",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "This is a plugin for Obsidian. This plugin renders codeblocks with csv format.",
|
||||
"author": "elrindir",
|
||||
"authorUrl": "https://github.com/elrindir/",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
{
|
||||
"id": "csv-modern-codeblock",
|
||||
"name": "CSV Modern Codeblock",
|
||||
"version": "1.0.0",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Render CSV and TSV code blocks as interactive tables with sticky headers, per-column filters, sorting, layout toggles, link detection, and CSV validation.",
|
||||
"author": "vitovt",
|
||||
"authorUrl": "https://github.com/vitovt/",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
|
|
|
|||
3
versions.json
Normal file
3
versions.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"1.0.0": "0.15.0"
|
||||
}
|
||||
Loading…
Reference in a new issue