From dbabde8b75f0b1cfb305d4e1eac8f36b4dfb74db Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Tue, 7 Jan 2025 22:56:15 +0900 Subject: [PATCH 01/14] =?UTF-8?q?[REFACTOR]=20innerHTML=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.ts | 13 ++- src/csvdisplay.ts | 131 +++++++++++++++-------- src/styles/{modal.css => csvdisplay.css} | 0 3 files changed, 98 insertions(+), 46 deletions(-) rename src/styles/{modal.css => csvdisplay.css} (100%) diff --git a/main.ts b/main.ts index b17d8b3..54ba9da 100644 --- a/main.ts +++ b/main.ts @@ -7,6 +7,7 @@ import { TFile, } from 'obsidian'; import { createInflate } from 'zlib'; +import CsvCreateModal from 'src/csvcreator'; interface CsvPluginSettings { mySetting: string; @@ -31,7 +32,7 @@ export default class CsvPlugin extends Plugin { openCsvInputModal = async (app: App, headers: string[], fileName: string) => { createCsvInputModal_(app, headers, fileName); } - createCsvTableView = (csvTable: CSVTable): string => { + createCsvTableView = (csvTable: CSVTable): HTMLElement => { return createCsvTableView_(csvTable); } @@ -43,6 +44,16 @@ export default class CsvPlugin extends Plugin { // This adds a settings tab so the user can configure various aspects of the plugin this.addSettingTab(new CsvSettingTab(this.app, this)); + + + // commands + this.addCommand({ + id: "create-csv-table", + name: "Create CSV Table", + callback: () => { + new CsvCreateModal(this.app).open(); + }, + }); } onunload() {} diff --git a/src/csvdisplay.ts b/src/csvdisplay.ts index df9688f..e3fbab0 100644 --- a/src/csvdisplay.ts +++ b/src/csvdisplay.ts @@ -1,13 +1,14 @@ import { App, Modal } from "obsidian"; import { CSVRow, CSVTable } from "./types"; import { readCSV_, saveCSV_ } from "./csvfilemanager"; -import './styles/modal.css'; +import './styles/csvdisplay.css'; export const createCsvInputModal_ = async (app: App, headers: string[], fileName: string) => { const form = generateForm(headers); const modal = new Modal(app); - modal.contentEl.innerHTML = form; + modal.contentEl.empty(); + modal.contentEl.appendChild(form); modal.open(); // 파일을 새로 읽어서, 추가된 라인을 포함 저장. @@ -36,53 +37,93 @@ export const createCsvInputModal_ = async (app: App, headers: string[], fileName }); } -const generateForm = (headers: string[]): string => { - // 입력 필드를 HTML로 생성 - const fields = headers.map(header => createInputField(header)); - // 폼 래퍼에 입력 필드를 삽입 - return ` -
- ${fields.join("\n")} -
-
- -
-
- `; -} -const createInputField = (key: string): string => { - return ` -
- - -
- `; +const generateForm = (headers: string[]): HTMLFormElement => { + // 폼 요소 생성 + const form = document.createElement("form"); + form.id = "csv-input-form"; + + // 입력 필드 생성 및 추가 + headers.forEach(header => { + const field = createInputField(header); + form.appendChild(field); + }); + + // 버튼 그룹 생성 및 추가 + const buttonGroup = document.createElement("div"); + buttonGroup.className = "button-group"; + + const submitButton = document.createElement("button"); + submitButton.className = "submit-button"; + submitButton.type = "submit"; + submitButton.textContent = "Submit"; + + buttonGroup.appendChild(submitButton); + form.appendChild(buttonGroup); + + return form; } -export const createCsvTableView_ = (csvTable: CSVTable): string => { +const createInputField = (key: string): HTMLDivElement => { + // 입력 필드 래퍼 생성 + const formGroup = document.createElement("div"); + formGroup.className = "form-group"; + + // 라벨 생성 + const label = document.createElement("label"); + label.className = "input-key"; + label.htmlFor = key; + label.textContent = key; + + // 입력 필드 생성 + const input = document.createElement("input"); + input.className = "input-value"; + input.type = "text"; + input.id = key; + input.name = key; + + // 요소 추가 + formGroup.appendChild(label); + formGroup.appendChild(input); + + return formGroup; +} + +export const createCsvTableView_ = (csvTable: CSVTable): HTMLElement => { const headers = csvTable.getHeaders(); const rows = csvTable.getRows(); - const table = rows.map(row => { - return ` - - ${row.map(cell => `${cell}`).join("")} - - `; - }).join(""); + // 테이블 래퍼 생성 + const tableWrapper = document.createElement("div"); + tableWrapper.className = "table-wrapper"; - return ` -
- - - - ${headers.map(header => ``).join("")} - - - - ${table} - -
${header}
-
- `; + // 테이블 생성 + const table = document.createElement("table"); + + // 테이블 헤더 생성 + const thead = document.createElement("thead"); + const headerRow = document.createElement("tr"); + headers.forEach(header => { + const th = document.createElement("th"); + th.textContent = header; + headerRow.appendChild(th); + }); + thead.appendChild(headerRow); + table.appendChild(thead); + + // 테이블 바디 생성 + const tbody = document.createElement("tbody"); + rows.forEach(row => { + const tableRow = document.createElement("tr"); + row.forEach(cell => { + const td = document.createElement("td"); + td.textContent = cell?.toString() ?? ""; + tableRow.appendChild(td); + }); + tbody.appendChild(tableRow); + }); + table.appendChild(tbody); + + tableWrapper.appendChild(table); + + return tableWrapper; } \ No newline at end of file diff --git a/src/styles/modal.css b/src/styles/csvdisplay.css similarity index 100% rename from src/styles/modal.css rename to src/styles/csvdisplay.css From 6411c725aeb4d4795bdbe4121f4c46d881411340 Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Tue, 7 Jan 2025 22:56:26 +0900 Subject: [PATCH 02/14] =?UTF-8?q?[FEAT]=20Create=20Modal=20command=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/csvcreator.ts | 26 ++++++++++++++++++++++++++ src/styles/csvcreator.css | 0 2 files changed, 26 insertions(+) create mode 100644 src/csvcreator.ts create mode 100644 src/styles/csvcreator.css diff --git a/src/csvcreator.ts b/src/csvcreator.ts new file mode 100644 index 0000000..d341bb0 --- /dev/null +++ b/src/csvcreator.ts @@ -0,0 +1,26 @@ +import { App, Modal, Plugin } from 'obsidian'; + +export default class CsvCreateModal extends Modal { + constructor(app: App) { + super(app); + } + + onOpen() { + let {contentEl} = this; + contentEl.createEl('h2', {text: 'Create CSV Table'}); + + let inputEl = contentEl.createEl('input'); + inputEl.value = 'Hello World'; + + let buttonEl = contentEl.createEl('button', {text: 'Create'}); + buttonEl.addEventListener('click', () => { + console.log(inputEl.value); + this.close(); + }); + } + + onClose() { + let {contentEl} = this; + contentEl.empty(); + } +} \ No newline at end of file diff --git a/src/styles/csvcreator.css b/src/styles/csvcreator.css new file mode 100644 index 0000000..e69de29 From ced5e47a28c4bcca435ee35b733816990d2b7574 Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Tue, 7 Jan 2025 22:59:24 +0900 Subject: [PATCH 03/14] =?UTF-8?q?[CLEANUP]=20=EC=95=88=EC=93=B0=EB=8A=94?= =?UTF-8?q?=20import=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.ts | 4 +--- src/csvcreator.ts | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/main.ts b/main.ts index 54ba9da..748565a 100644 --- a/main.ts +++ b/main.ts @@ -3,10 +3,8 @@ import { createCsvInputModal_, createCsvTableView_ } from './src/csvdisplay'; import { CSVTable } from './src/types' import { - App, Modal, Plugin, PluginSettingTab, Setting, - TFile, + App, Plugin, PluginSettingTab, Setting, } from 'obsidian'; -import { createInflate } from 'zlib'; import CsvCreateModal from 'src/csvcreator'; interface CsvPluginSettings { diff --git a/src/csvcreator.ts b/src/csvcreator.ts index d341bb0..20455ca 100644 --- a/src/csvcreator.ts +++ b/src/csvcreator.ts @@ -5,6 +5,7 @@ export default class CsvCreateModal extends Modal { super(app); } + // common api onOpen() { let {contentEl} = this; contentEl.createEl('h2', {text: 'Create CSV Table'}); From e99fd4b982b17fbb03a0f444d08e3176b37bd73f Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Tue, 7 Jan 2025 23:53:26 +0900 Subject: [PATCH 04/14] =?UTF-8?q?[FEAT]=20csv=20create=20form=20=EC=A0=9C?= =?UTF-8?q?=EC=9E=91=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/csvcreator.ts | 41 +++++++++++++++++++++++++++++++++------ src/styles/csvcreator.css | 23 ++++++++++++++++++++++ 2 files changed, 58 insertions(+), 6 deletions(-) diff --git a/src/csvcreator.ts b/src/csvcreator.ts index 20455ca..282ddfc 100644 --- a/src/csvcreator.ts +++ b/src/csvcreator.ts @@ -1,23 +1,52 @@ import { App, Modal, Plugin } from 'obsidian'; +import './styles/csvcreator.css'; export default class CsvCreateModal extends Modal { + columnTypes: string[] = [ + 'string', + 'number', + 'boolean', + ]; + + columnsWrapper: HTMLElement; + constructor(app: App) { super(app); } + addColumn() { + let inputWarpper = this.columnsWrapper.createEl('div'); + let columnInput = inputWarpper.createEl('input'); + columnInput.placeholder = 'Column Name'; + + let typeSelect = inputWarpper.createEl('select'); + for (let type of this.columnTypes) { + let option = typeSelect.createEl('option'); + option.value = type; + option.text = type; + }; + + + } + // common api onOpen() { let {contentEl} = this; contentEl.createEl('h2', {text: 'Create CSV Table'}); + contentEl.createEl('hr'); - let inputEl = contentEl.createEl('input'); - inputEl.value = 'Hello World'; + let filenameEl = contentEl.createEl('input'); + filenameEl.placeholder = 'Title'; + filenameEl.classList.add('filename-input'); + + let addColumnButton = contentEl.createEl('button', {text: 'Add Column'}); + addColumnButton.addEventListener('click', () => { this.addColumn(); }); + + this.columnsWrapper = contentEl.createEl('div'); + this.columnsWrapper.classList.add('column-warpper'); let buttonEl = contentEl.createEl('button', {text: 'Create'}); - buttonEl.addEventListener('click', () => { - console.log(inputEl.value); - this.close(); - }); + buttonEl.addEventListener('click', () => { this.close(); }); } onClose() { diff --git a/src/styles/csvcreator.css b/src/styles/csvcreator.css index e69de29..d545ead 100644 --- a/src/styles/csvcreator.css +++ b/src/styles/csvcreator.css @@ -0,0 +1,23 @@ +.filename-input { + width: 100%; + padding: 0.5rem; + margin: 0.5rem 0; + border: 1px solid #ccc; + border-radius: 0.25rem; + font-size: 1rem; + font-family: var(--font-monospace); + color: var(--text-normal); + background-color: var(--background-secondary); +} + +hr { + margin: 5px 0; + border: 0; + border-top: 1px solid #ccc; +} + +.columns-wrapper { + display: flex; + flex-direction: column; + gap: 1rem; +} \ No newline at end of file From 0094f8028ade9bff4c6fc2fc779711f39fa52a79 Mon Sep 17 00:00:00 2001 From: hihangeol Date: Sat, 11 Jan 2025 21:54:36 +0900 Subject: [PATCH 05/14] [FEAT] csv explorer module --- main.ts | 11 +++++++++- src/csvcreator.ts | 7 +++++++ src/csvexplorer.ts | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/csvexplorer.ts diff --git a/main.ts b/main.ts index 748565a..1d7ce3d 100644 --- a/main.ts +++ b/main.ts @@ -6,6 +6,7 @@ import { App, Plugin, PluginSettingTab, Setting, } from 'obsidian'; import CsvCreateModal from 'src/csvcreator'; +import CsvExplorerModal, { getCsvFileStructure } from 'src/csvexplorer'; interface CsvPluginSettings { mySetting: string; @@ -43,7 +44,6 @@ export default class CsvPlugin extends Plugin { // This adds a settings tab so the user can configure various aspects of the plugin this.addSettingTab(new CsvSettingTab(this.app, this)); - // commands this.addCommand({ id: "create-csv-table", @@ -52,6 +52,15 @@ export default class CsvPlugin extends Plugin { new CsvCreateModal(this.app).open(); }, }); + + this.addCommand({ + id: "open-csv-explorer", + name: "Open CSV Explorer", + callback: async () => { + const csvStructure = await getCsvFileStructure(this.app); + new CsvExplorerModal(this.app, csvStructure).open(); + } + }) } onunload() {} diff --git a/src/csvcreator.ts b/src/csvcreator.ts index 282ddfc..0750908 100644 --- a/src/csvcreator.ts +++ b/src/csvcreator.ts @@ -29,6 +29,13 @@ export default class CsvCreateModal extends Modal { } + createSCVFile() { + // .csv 파일 생성 + + // .csv.meta 파일 생성 + + } + // common api onOpen() { let {contentEl} = this; diff --git a/src/csvexplorer.ts b/src/csvexplorer.ts new file mode 100644 index 0000000..03cf7fa --- /dev/null +++ b/src/csvexplorer.ts @@ -0,0 +1,52 @@ +import { App, Modal, TFile } from 'obsidian'; + +/* + obsidian 탐색기에서 csv 파일이 표시가 안되기 때문에,\ + 파일 탐색하고 지우는 용도로 사용. +*/ +export const getCsvFileStructure = async (app: App): Promise> => { + const csvStructure: Record = {}; + const files = app.vault.getFiles(); + + // Vault 내의 모든 파일 순회 + files.forEach((file: TFile) => { + if (file.extension === "csv") { + if(file.parent) { + const folderPath = file.parent.path; + if (!csvStructure[folderPath]) + csvStructure[folderPath] = []; + + csvStructure[folderPath].push(file.name); + } + } + }); + return csvStructure; +} + +export default class CsvExplorerModal extends Modal { + csvStructure: Record = {}; + + constructor(app: App, csvStructure: Record) { + super(app); + this.csvStructure = csvStructure; + } + + onOpen() { + const { contentEl } = this; + contentEl.empty(); + + contentEl.createEl("h2", { text: "CSV Explorer" }); + + Object.keys(this.csvStructure).forEach((folder) => { + contentEl.createEl("h3", { text: folder }); + this.csvStructure[folder].forEach((file) => { + contentEl.createEl("p", { text: file }); + }); + }); + } + + onClose() { + const { contentEl } = this; + contentEl.empty(); + } +} \ No newline at end of file From 090b1bdb40ad3883640fcc6531e96686e99cd0df Mon Sep 17 00:00:00 2001 From: hihangeol Date: Sun, 12 Jan 2025 00:25:14 +0900 Subject: [PATCH 06/14] =?UTF-8?q?[FEAT]=20create=20csv=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/csvcreator.ts | 133 ++++++++++++++++++++++++++++++++------ src/styles/csvcreator.css | 60 +++++++++++++++-- src/types.ts | 8 ++- 3 files changed, 175 insertions(+), 26 deletions(-) diff --git a/src/csvcreator.ts b/src/csvcreator.ts index 0750908..efd7883 100644 --- a/src/csvcreator.ts +++ b/src/csvcreator.ts @@ -1,12 +1,10 @@ -import { App, Modal, Plugin } from 'obsidian'; +import { App, Modal, Notice, Plugin } from 'obsidian'; import './styles/csvcreator.css'; +import { columnTypes } from './types'; + + export default class CsvCreateModal extends Modal { - columnTypes: string[] = [ - 'string', - 'number', - 'boolean', - ]; columnsWrapper: HTMLElement; @@ -15,25 +13,95 @@ export default class CsvCreateModal extends Modal { } addColumn() { - let inputWarpper = this.columnsWrapper.createEl('div'); - let columnInput = inputWarpper.createEl('input'); - columnInput.placeholder = 'Column Name'; + let inputWarpper = this.columnsWrapper.createEl('tr'); + let columnTd = inputWarpper.createEl('td'); + let columnInput = columnTd.createEl('input'); + columnInput.classList.add('colname-input'); + columnInput.placeholder = 'name'; - let typeSelect = inputWarpper.createEl('select'); - for (let type of this.columnTypes) { + let typeTd = inputWarpper.createEl('td'); + let typeSelect = typeTd.createEl('select'); + typeSelect.classList.add('coltype-select'); + for (let type of columnTypes) { let option = typeSelect.createEl('option'); option.value = type; option.text = type; }; - - } createSCVFile() { // .csv 파일 생성 - - // .csv.meta 파일 생성 - + const { contentEl } = this; + + // 파일 이름과 경로 가져오기 + const filenameInput = contentEl.querySelector('.filename-input') as HTMLInputElement; + const filePathInput = contentEl.querySelector('.filepath-input') as HTMLInputElement; + + let filename = filenameInput.value.trim(); + let filePath = filePathInput.value.trim() || '/'; + + // validation + if (!filename) { + new Notice('파일 이름을 입력해주세요.'); + return; + } + if(filename.endsWith('.csv')) { + filename = filename.slice(0, -4); + } + if(filePath.length > 1 && filePath.endsWith('/')) { + filePath = filePath.slice(0, -1); + } + + // 컬럼 정보 수집 + const columnData: { name: string; type: string }[] = []; + this.columnsWrapper.querySelectorAll('tr').forEach((columnEl) => { + const inputEl = columnEl.querySelector('input') as HTMLInputElement; + const selectEl = columnEl.querySelector('select') as HTMLSelectElement; + + const columnName = inputEl?.value.trim(); + const columnType = selectEl?.value; + + if (columnName && columnType) { + columnData.push({ name: columnName, type: columnType }); + } + }); + + if (columnData.length === 0) { + new Notice('적어도 하나의 컬럼을 추가해주세요.'); + return; + } + + // .csv 내용 생성 (헤더만 추가) + const csvContent = columnData.map((col) => col.name).join(',') + '\n'; + + // .csv.meta 내용 생성 + const metaContent = JSON.stringify( + columnData.reduce((acc, col) => { + acc[col.name] = col.type; + return acc; + }, {} as Record), + null, + 2 + ); + + // 파일 저장 + const vault = this.app.vault; + const fullPathCsv = `${filePath}/${filename}.csv`; + const fullPathMeta = `${filePath}/${filename}.csv.meta`; + + // .csv 파일 저장 + vault.adapter.write(fullPathCsv, csvContent).then(() => { + new Notice(`${fullPathCsv} 파일이 생성되었습니다.`); + }).catch((err) => { + new Notice(`.csv 파일 생성 중 오류 발생: ${err}`); + }); + + // .csv.meta 파일 저장 + vault.adapter.write(fullPathMeta, metaContent).then(() => { + new Notice(`${fullPathMeta} 파일이 생성되었습니다.`); + }).catch((err) => { + new Notice(`.csv.meta 파일 생성 중 오류 발생: ${err}`); + }); } // common api @@ -42,18 +110,43 @@ export default class CsvCreateModal extends Modal { contentEl.createEl('h2', {text: 'Create CSV Table'}); contentEl.createEl('hr'); - let filenameEl = contentEl.createEl('input'); + // file setting + let filenameContainer = contentEl.createEl('div'); + filenameContainer.classList.add('filename-container'); + + let filenameEl = filenameContainer.createEl('input'); filenameEl.placeholder = 'Title'; filenameEl.classList.add('filename-input'); + + let filePathEl = filenameContainer.createEl('input'); + filePathEl.placeholder = 'file path(default: root)'; + filePathEl.classList.add('filepath-input'); + // add column button let addColumnButton = contentEl.createEl('button', {text: 'Add Column'}); addColumnButton.addEventListener('click', () => { this.addColumn(); }); - this.columnsWrapper = contentEl.createEl('div'); - this.columnsWrapper.classList.add('column-warpper'); + // column making table + let columnsTable = contentEl.createEl('table'); + columnsTable.classList.add('columns-table'); + let tHead = columnsTable.createEl('thead'); + let tHeadRow = tHead.createEl('tr'); + tHeadRow.classList.add('columns-table-header'); + tHeadRow.createEl('th', {text: 'Column Name'}); + tHeadRow.createEl('th', {text: 'Type'}); + + columnsTable.createEl('hr'); + this.columnsWrapper = columnsTable.createEl('tbody'); + this.columnsWrapper.classList.add('columns-wrapper'); + + // submit button + contentEl.createEl('hr'); let buttonEl = contentEl.createEl('button', {text: 'Create'}); - buttonEl.addEventListener('click', () => { this.close(); }); + buttonEl.addEventListener('click', () => { + this.createSCVFile(); + this.close(); + }); } onClose() { diff --git a/src/styles/csvcreator.css b/src/styles/csvcreator.css index d545ead..dfb192d 100644 --- a/src/styles/csvcreator.css +++ b/src/styles/csvcreator.css @@ -1,5 +1,23 @@ +.filename-container { + display: flex; + flex-direction: row; + gap: 1rem; + align-items: center; +} + .filename-input { - width: 100%; + flex-grow : 2; + padding: 0.5rem; + margin: 0.5rem 0; + border: 1px solid #ccc; + border-radius: 0.25rem; + font-size: 1rem; + font-family: var(--font-monospace); + color: var(--text-normal); + background-color: var(--background-secondary); +} +.filepath-input { + flex-grow: 1; padding: 0.5rem; margin: 0.5rem 0; border: 1px solid #ccc; @@ -13,11 +31,43 @@ hr { margin: 5px 0; border: 0; + width: 100%; border-top: 1px solid #ccc; } +.columns-table { + width: 100%; +} + .columns-wrapper { - display: flex; - flex-direction: column; - gap: 1rem; -} \ No newline at end of file + width: 100%; +} +.columns-wrapper > :nth-child(2n) { + background-color: var(--background-secondary); +} + +.columns-table-header { + gap: 1rem; + align-items: center; +} + +.colname-input { + padding: 2px; + width: 100%; + border: 1px solid #ccc; + border-radius: 0.25rem; + font-size: 1rem; + font-family: var(--font-monospace); + color: var(--text-normal); +} + +.coltype-select { + padding: 2px; + width: 100%; + /* border: 1px solid #ccc; */ + border-radius: 0.25rem; + font-size: 1rem; + font-family: var(--font-monospace); + color: var(--text-normal); +} + diff --git a/src/types.ts b/src/types.ts index 94a7cd0..cf3c0f9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -88,4 +88,10 @@ export interface CSVFile { name: string; path: string; content: CSVTable; -} \ No newline at end of file +} + +export const columnTypes: string[] = [ + 'string', + 'number', + 'boolean', +]; \ No newline at end of file From edab966bca5ed44bc8e472cae62a1887de1192f6 Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Sun, 12 Jan 2025 21:41:23 +0900 Subject: [PATCH 07/14] =?UTF-8?q?[FEAT,=20STYLE]=20csv=20table=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20api=20=EB=B6=84=EB=A6=AC,=20css=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.ts | 6 ++-- src/csvcreator.ts | 76 ++++++++++++++++++++------------------- src/csvfilemanager.ts | 1 + src/styles/csvcreator.css | 8 +++-- 4 files changed, 50 insertions(+), 41 deletions(-) diff --git a/main.ts b/main.ts index 1d7ce3d..78d565f 100644 --- a/main.ts +++ b/main.ts @@ -5,7 +5,7 @@ import { CSVTable } from './src/types' import { App, Plugin, PluginSettingTab, Setting, } from 'obsidian'; -import CsvCreateModal from 'src/csvcreator'; +import CsvCreateModal, { createCsvFile_ } from 'src/csvcreator'; import CsvExplorerModal, { getCsvFileStructure } from 'src/csvexplorer'; interface CsvPluginSettings { @@ -34,7 +34,9 @@ export default class CsvPlugin extends Plugin { createCsvTableView = (csvTable: CSVTable): HTMLElement => { return createCsvTableView_(csvTable); } - + createCsvFile = (filename: string, filePath: string, columnData: { name:string, type: string }[]) => { + createCsvFile_(this.app, filename, filePath, columnData); + } async onload() { await this.loadSettings(); diff --git a/src/csvcreator.ts b/src/csvcreator.ts index efd7883..fa08bb3 100644 --- a/src/csvcreator.ts +++ b/src/csvcreator.ts @@ -2,7 +2,41 @@ import { App, Modal, Notice, Plugin } from 'obsidian'; import './styles/csvcreator.css'; import { columnTypes } from './types'; +// dataviewjs 등으로 자동적으로 파일을 생성하게 할 때 사용할 수 있는 api +export const createCsvFile_ = (app: App, filename: string, filePath: string, columnData: { name:string, type: string }[]) => { + // .csv 내용 생성 (헤더만 추가) + const csvContent = columnData.map((col) => col.name).join(',') + '\n'; + // .csv.meta 내용 생성 + const metaContent = JSON.stringify( + columnData.reduce((acc, col) => { + acc[col.name] = col.type; + return acc; + }, {} as Record), + null, + 2 + ); + + // 파일 저장 + const vault = app.vault; + const fullPathCsv = `${filePath}/${filename}.csv`; + const fullPathMeta = `${filePath}/${filename}.csv.meta`; + + // .csv 파일 저장 + vault.adapter.write(fullPathCsv, csvContent).then(() => { + new Notice(`${fullPathCsv} file has been created.`); + }).catch((err) => { + new Notice(`Error occurred while creating .csv file: ${err}`); + }); + + // .csv.meta 파일 저장 + vault.adapter.write(fullPathMeta, metaContent).then(() => { + new Notice(`${fullPathMeta} file has been created.`); + }).catch((err) => { + new Notice(`.csv.meta 파일 생성 중 오류 발생: ${err}`); + new Notice(`Error occurred while creating .csv.meta file: ${err}`); + }); +} export default class CsvCreateModal extends Modal { @@ -29,7 +63,7 @@ export default class CsvCreateModal extends Modal { }; } - createSCVFile() { + createCsvFile() { // .csv 파일 생성 const { contentEl } = this; @@ -42,7 +76,7 @@ export default class CsvCreateModal extends Modal { // validation if (!filename) { - new Notice('파일 이름을 입력해주세요.'); + new Notice('Please enter a file name.'); return; } if(filename.endsWith('.csv')) { @@ -67,41 +101,11 @@ export default class CsvCreateModal extends Modal { }); if (columnData.length === 0) { - new Notice('적어도 하나의 컬럼을 추가해주세요.'); + new Notice('add at least one column'); return; } - - // .csv 내용 생성 (헤더만 추가) - const csvContent = columnData.map((col) => col.name).join(',') + '\n'; - - // .csv.meta 내용 생성 - const metaContent = JSON.stringify( - columnData.reduce((acc, col) => { - acc[col.name] = col.type; - return acc; - }, {} as Record), - null, - 2 - ); - - // 파일 저장 - const vault = this.app.vault; - const fullPathCsv = `${filePath}/${filename}.csv`; - const fullPathMeta = `${filePath}/${filename}.csv.meta`; - - // .csv 파일 저장 - vault.adapter.write(fullPathCsv, csvContent).then(() => { - new Notice(`${fullPathCsv} 파일이 생성되었습니다.`); - }).catch((err) => { - new Notice(`.csv 파일 생성 중 오류 발생: ${err}`); - }); - - // .csv.meta 파일 저장 - vault.adapter.write(fullPathMeta, metaContent).then(() => { - new Notice(`${fullPathMeta} 파일이 생성되었습니다.`); - }).catch((err) => { - new Notice(`.csv.meta 파일 생성 중 오류 발생: ${err}`); - }); + + createCsvFile_(this.app, filename, filePath, columnData); } // common api @@ -144,7 +148,7 @@ export default class CsvCreateModal extends Modal { contentEl.createEl('hr'); let buttonEl = contentEl.createEl('button', {text: 'Create'}); buttonEl.addEventListener('click', () => { - this.createSCVFile(); + this.createCsvFile(); this.close(); }); } diff --git a/src/csvfilemanager.ts b/src/csvfilemanager.ts index 62d74fc..e232e05 100644 --- a/src/csvfilemanager.ts +++ b/src/csvfilemanager.ts @@ -1,6 +1,7 @@ import { CSVTable } from './types' import { App, TFile } from 'obsidian'; +// public api export const readCSV_ = async (app: App, fileName: string): Promise => { if(fileName.endsWith(".csv")) { // 확장자 검사. const content = await loadFile(app, fileName); // 파일 로드. diff --git a/src/styles/csvcreator.css b/src/styles/csvcreator.css index dfb192d..938b390 100644 --- a/src/styles/csvcreator.css +++ b/src/styles/csvcreator.css @@ -6,6 +6,7 @@ } .filename-input { + width: 60%; flex-grow : 2; padding: 0.5rem; margin: 0.5rem 0; @@ -17,6 +18,7 @@ background-color: var(--background-secondary); } .filepath-input { + width: 30%; flex-grow: 1; padding: 0.5rem; margin: 0.5rem 0; @@ -53,7 +55,7 @@ hr { .colname-input { padding: 2px; - width: 100%; + width: 100%; height: 30px; border: 1px solid #ccc; border-radius: 0.25rem; font-size: 1rem; @@ -63,8 +65,8 @@ hr { .coltype-select { padding: 2px; - width: 100%; - /* border: 1px solid #ccc; */ + width: 100%; height: 30px; + border: 1px solid #ccc; border-radius: 0.25rem; font-size: 1rem; font-family: var(--font-monospace); From 19c38728688b005ed1f1d3ee2d7ac0f4d300fbd5 Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Sun, 12 Jan 2025 22:47:41 +0900 Subject: [PATCH 08/14] =?UTF-8?q?[REFACTOR]=20csv=20table=20type=20?= =?UTF-8?q?=EA=B5=AC=EC=A1=B0=20=EC=9D=BC=EB=B6=80=20=EB=B3=80=EA=B2=BD.?= =?UTF-8?q?=20API=20=EA=B2=80=EC=A6=9D=20=EC=95=88=EB=90=A8=20=EC=A3=BC?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/csvdisplay.ts | 2 +- src/csvfilemanager.ts | 46 ++++++++++++++++++++++++++++++++++--------- src/types.ts | 42 ++++++++++++++++++++++----------------- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/csvdisplay.ts b/src/csvdisplay.ts index e3fbab0..e4daec9 100644 --- a/src/csvdisplay.ts +++ b/src/csvdisplay.ts @@ -104,7 +104,7 @@ export const createCsvTableView_ = (csvTable: CSVTable): HTMLElement => { const headerRow = document.createElement("tr"); headers.forEach(header => { const th = document.createElement("th"); - th.textContent = header; + th.textContent = header[0]; headerRow.appendChild(th); }); thead.appendChild(headerRow); diff --git a/src/csvfilemanager.ts b/src/csvfilemanager.ts index e232e05..e40ed0a 100644 --- a/src/csvfilemanager.ts +++ b/src/csvfilemanager.ts @@ -1,11 +1,31 @@ -import { CSVTable } from './types' +import { CSVTable, Header } from './types' import { App, TFile } from 'obsidian'; +// meta file을 수정하는 로직이 포함되어야 함. + // public api export const readCSV_ = async (app: App, fileName: string): Promise => { if(fileName.endsWith(".csv")) { // 확장자 검사. - const content = await loadFile(app, fileName); // 파일 로드. - return await new CSVTable(content) // CSV 파싱. + // read .csv file, + const csvContent = await loadFile(app, fileName); // 파일 로드. + + const lines = csvContent.split("\n").map(line => line.trim()); + const headersString = lines.shift()?.split(",") ?? []; + const rows = lines.map(line => line.split(",").map(cell => cell.trim())); + + // read .csv.meta file, + // meta file 존재 여부 확인해서 없으면 생성. + if(await app.vault.adapter.exists(`${fileName}.meta`) == false) { + const headers: Header[] = headersString.map((header) => [header, "string"]); + const metaContent = JSON.stringify(headers, null, 2); + await saveFile(app, `${fileName}.meta`, metaContent); + } + + // meta file 로드. + const metaData = await loadFile(app, `${fileName}.meta`); // 메타 파일 로드. + const headers: Header[] = JSON.parse(metaData); + + return await new CSVTable(headers, rows) // CSV 파싱. } else { console.error(`file extension is not csv : ${fileName} (read)`); } @@ -13,8 +33,11 @@ export const readCSV_ = async (app: App, fileName: string): Promise => { if(fileName.endsWith(".csv")) { + // contents, meta로 분리 필요. const content = table.toCSV(); await saveFile(app, fileName, content); + // const meta = table.getMeta(); + // await saveMetaFile(app, `${fileName}.meta`, meta); } else { console.error(`file extension is not csv : ${fileName} (save)`); } @@ -36,6 +59,10 @@ const saveFile = async (app: App, fileName: string, content: string): Promise => { + +} + const loadFile = async (app: App, fileName: string): Promise => { const vault = app.vault; const file = vault.getAbstractFileByPath(fileName); @@ -46,10 +73,11 @@ const loadFile = async (app: App, fileName: string): Promise => { } } -const parseCSV = (content: string): CSVTable => { - const lines = content.split("\n").map(line => line.trim()); - const headers = lines.shift()?.split(",") ?? []; - const rows = lines.map(line => line.split(",").map(cell => cell.trim())); +// api 재설계 필요. -> 애초에 사용할 일 있는지 모르겠음. +// const parseCSV = (content: string): CSVTable => { + // const lines = content.split("\n").map(line => line.trim()); + // const headers = lines.shift()?.split(",") ?? []; + // const rows = lines.map(line => line.split(",").map(cell => cell.trim())); - return new CSVTable(headers, rows); -} \ No newline at end of file + // return new CSVTable(headers, rows); +// } \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index cf3c0f9..a622bc9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,24 +1,29 @@ export type CSVCell = string | number | null; export type CSVRow = CSVCell[]; +export type Header = [string, string]; // [columnName, columnType] export class CSVTable { - private headers: string[]; + private headers: Header[]; private rows: CSVRow[]; // string으로 넣거나, 분리된 headers/rows로 생성자 호출 가능. - constructor(contentOrHeaders: string | string[], rows: CSVRow[] = []) { - if (typeof contentOrHeaders === 'string') { - // content가 문자열일 때 - const lines = contentOrHeaders.split("\n").map(line => line.trim()); - this.headers = lines.shift()?.split(",") ?? []; - this.rows = lines.map(line => line.split(",").map(cell => cell.trim())); - } else { - // headers가 배열일 때 - this.headers = contentOrHeaders; - this.rows = rows; - } + constructor(headers: Header[], rows: CSVRow[] = []) { + this.headers = headers; + this.rows = rows; } + // constructor(contentOrHeaders: string | string[], rows: CSVRow[] = []) { + // if (typeof contentOrHeaders === 'string') { + // // content가 문자열일 때 + // const lines = contentOrHeaders.split("\n").map(line => line.trim()); + // this.headers = lines.shift()?.split(",") ?? []; + // this.rows = lines.map(line => line.split(",").map(cell => cell.trim())); + // } else { + // // headers가 배열일 때 + // this.headers = contentOrHeaders; + // this.rows = rows; + // } + // } - getHeaders(): string[] { + getHeaders(): Header[] { return this.headers; } getRows(): CSVRow[] { @@ -35,8 +40,9 @@ export class CSVTable { this.rows.push(row); } else { + // key-value로 들어올 때 const newRow: CSVRow = []; - for(const header of this.headers) { newRow.push(row[header]); } + for(const header of this.headers) { newRow.push(row[header[0]]); } this.rows.push(newRow); } } @@ -48,7 +54,7 @@ export class CSVTable { this.rows.splice(rowIndex, 1); } updateCell(rowIndex: number, columnName: string, value: CSVCell): void { - const columnIndex = this.headers.indexOf(columnName); + const columnIndex = this.headers.findIndex(([colname]) => colname === columnName); if (columnIndex === -1) { throw new Error(`Column '${columnName}' does not exist.`); } @@ -67,14 +73,14 @@ export class CSVTable { } // 실제로 사용하게될 api일지는 모르겠습니다. - addColoumn(columnName: string, value: CSVCell = 0): void { - this.headers.push(columnName); + addColoumn(columnName: string, columnType: string, value: CSVCell = 0): void { + this.headers.push([columnName, columnType]); for (let i = 0; i < this.rows.length; i++) { this.rows[i].push(value); } } deleteColumn(columnName: string): void { - const columnIndex = this.headers.indexOf(columnName); + const columnIndex = this.headers.findIndex(([colname]) => colname === columnName); if (columnIndex === -1) { throw new Error(`Column '${columnName}' does not exist.`); } From 78f6b828dd7c205e6096dbf3f285ae8d8ee60c22 Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Mon, 13 Jan 2025 21:54:11 +0900 Subject: [PATCH 09/14] =?UTF-8?q?[VALIDATE]=20api=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/csvfilemanager.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/csvfilemanager.ts b/src/csvfilemanager.ts index e40ed0a..8ac2f59 100644 --- a/src/csvfilemanager.ts +++ b/src/csvfilemanager.ts @@ -16,14 +16,25 @@ export const readCSV_ = async (app: App, fileName: string): Promise [header, "string"]); - const metaContent = JSON.stringify(headers, null, 2); + const headers: { name: string, type: string }[] = + headersString.map((header) => ({ name: header, type: "string" })); + + const metaContent = JSON.stringify( + headers.reduce((acc, col) => { + acc[col.name] = col.type; + return acc; + }, {} as Record), + null, + 2 + ); + // const metaContent = JSON.stringify(headers, null, 2); await saveFile(app, `${fileName}.meta`, metaContent); } + // meta file 로드. const metaData = await loadFile(app, `${fileName}.meta`); // 메타 파일 로드. - const headers: Header[] = JSON.parse(metaData); + const headers: Header[] = Object.entries(JSON.parse(metaData)); return await new CSVTable(headers, rows) // CSV 파싱. } else { From ce26b6d539fdf8b14dee576235af46af34a4bc57 Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Tue, 14 Jan 2025 18:57:17 +0900 Subject: [PATCH 10/14] =?UTF-8?q?[REFACTOR]=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.ts | 12 ++++++------ src/{csvdisplay.ts => csvPlugin.ts} | 4 ++-- src/csvcreator.ts | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) rename src/{csvdisplay.ts => csvPlugin.ts} (97%) diff --git a/main.ts b/main.ts index 78d565f..fd97d71 100644 --- a/main.ts +++ b/main.ts @@ -1,12 +1,12 @@ -import { readCSV_, saveCSV_} from 'src/csvfilemanager'; -import { createCsvInputModal_, createCsvTableView_ } from './src/csvdisplay'; -import { CSVTable } from './src/types' - import { App, Plugin, PluginSettingTab, Setting, } from 'obsidian'; -import CsvCreateModal, { createCsvFile_ } from 'src/csvcreator'; -import CsvExplorerModal, { getCsvFileStructure } from 'src/csvexplorer'; + +import { createCsvInputModal_, createCsvTableView_ } from './src/csvPlugin'; +import { readCSV_, saveCSV_} from 'src/csvFilemanager'; +import { CSVTable } from './src/types' +import CsvExplorerModal, { getCsvFileStructure } from 'src/csvExplorer'; +import CsvCreateModal, { createCsvFile_ } from 'src/csvCreator'; interface CsvPluginSettings { mySetting: string; diff --git a/src/csvdisplay.ts b/src/csvPlugin.ts similarity index 97% rename from src/csvdisplay.ts rename to src/csvPlugin.ts index e4daec9..29c102f 100644 --- a/src/csvdisplay.ts +++ b/src/csvPlugin.ts @@ -1,7 +1,7 @@ import { App, Modal } from "obsidian"; import { CSVRow, CSVTable } from "./types"; -import { readCSV_, saveCSV_ } from "./csvfilemanager"; -import './styles/csvdisplay.css'; +import { readCSV_, saveCSV_ } from "./csvFilemanager"; +import './styles/csvDisplay.css'; export const createCsvInputModal_ = async (app: App, headers: string[], fileName: string) => { const form = generateForm(headers); diff --git a/src/csvcreator.ts b/src/csvcreator.ts index fa08bb3..1c606fd 100644 --- a/src/csvcreator.ts +++ b/src/csvcreator.ts @@ -1,5 +1,5 @@ import { App, Modal, Notice, Plugin } from 'obsidian'; -import './styles/csvcreator.css'; +import './styles/csvCreator.css'; import { columnTypes } from './types'; // dataviewjs 등으로 자동적으로 파일을 생성하게 할 때 사용할 수 있는 api From 1a2f08ac1694564c0bff7e0f0ee9e6d0ef5f5b40 Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Tue, 14 Jan 2025 19:37:47 +0900 Subject: [PATCH 11/14] =?UTF-8?q?[STYLE]=20row=20adding=20plugin=20?= =?UTF-8?q?=EC=9D=BC=EB=B6=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.ts | 4 +- src/csvPlugin.ts | 56 +++++++++++++++++--- src/styles/{csvdisplay.css => csvPlugin.css} | 4 ++ 3 files changed, 54 insertions(+), 10 deletions(-) rename src/styles/{csvdisplay.css => csvPlugin.css} (90%) diff --git a/main.ts b/main.ts index fd97d71..e1ed27b 100644 --- a/main.ts +++ b/main.ts @@ -4,7 +4,7 @@ import { import { createCsvInputModal_, createCsvTableView_ } from './src/csvPlugin'; import { readCSV_, saveCSV_} from 'src/csvFilemanager'; -import { CSVTable } from './src/types' +import { CSVTable, Header } from './src/types' import CsvExplorerModal, { getCsvFileStructure } from 'src/csvExplorer'; import CsvCreateModal, { createCsvFile_ } from 'src/csvCreator'; @@ -28,7 +28,7 @@ export default class CsvPlugin extends Plugin { } //// csvdisplay.ts - openCsvInputModal = async (app: App, headers: string[], fileName: string) => { + openCsvInputModal = async (app: App, headers: Header[], fileName: string) => { createCsvInputModal_(app, headers, fileName); } createCsvTableView = (csvTable: CSVTable): HTMLElement => { diff --git a/src/csvPlugin.ts b/src/csvPlugin.ts index 29c102f..49a9c55 100644 --- a/src/csvPlugin.ts +++ b/src/csvPlugin.ts @@ -1,10 +1,10 @@ import { App, Modal } from "obsidian"; -import { CSVRow, CSVTable } from "./types"; +import { CSVRow, CSVTable, Header } from "./types"; import { readCSV_, saveCSV_ } from "./csvFilemanager"; -import './styles/csvDisplay.css'; +import './styles/csvPlugin.css'; -export const createCsvInputModal_ = async (app: App, headers: string[], fileName: string) => { - const form = generateForm(headers); +export const createCsvInputModal_ = async (app: App, headers: Header[], fileName: string) => { + const form = generateForm(fileName, headers); const modal = new Modal(app); modal.contentEl.empty(); @@ -20,7 +20,7 @@ export const createCsvInputModal_ = async (app: App, headers: string[], fileName const newRow: CSVRow = []; for(const header of headers) { - newRow.push(formData.get(header) as string); + newRow.push(formData.get(header[0]) as string); } // 파일 읽기 @@ -37,14 +37,28 @@ export const createCsvInputModal_ = async (app: App, headers: string[], fileName }); } -const generateForm = (headers: string[]): HTMLFormElement => { - // 폼 요소 생성 +const generateForm = (fileName: string, headers: Header[]): HTMLFormElement => { const form = document.createElement("form"); form.id = "csv-input-form"; + const fileNameArray = fileName.split('/'); + const fileNameShort = fileNameArray[fileNameArray.length - 1]; + + const titleTinkle = document.createElement("h6"); + titleTinkle.textContent = "Add new row to"; + const title = document.createElement("h2"); + title.textContent = fileNameShort; + + form.appendChild(titleTinkle); + form.appendChild(title); + + // 수평선 삽입. + form.appendChild(document.createElement("hr")); + + // 폼 요소 생성 // 입력 필드 생성 및 추가 headers.forEach(header => { - const field = createInputField(header); + const field = createHeaderInputField(header); form.appendChild(field); }); @@ -63,6 +77,32 @@ const generateForm = (headers: string[]): HTMLFormElement => { return form; } +const createHeaderInputField = (key: [string, string]): HTMLDivElement => { + // 입력 필드 래퍼 생성 + const formGroup = document.createElement("div"); + formGroup.className = "form-group"; + + // 라벨 생성 + const label = document.createElement("label"); + label.className = "input-key"; + label.htmlFor = key[0]; + label.textContent = key[0]; + + // 입력 필드 생성 + const input = document.createElement("input"); + input.className = "input-value"; + input.type = "text"; + input.id = key[0]; + input.name = key[0]; + input.placeholder = key[1]; + + // 요소 추가 + formGroup.appendChild(label); + formGroup.appendChild(input); + + return formGroup; +} + const createInputField = (key: string): HTMLDivElement => { // 입력 필드 래퍼 생성 const formGroup = document.createElement("div"); diff --git a/src/styles/csvdisplay.css b/src/styles/csvPlugin.css similarity index 90% rename from src/styles/csvdisplay.css rename to src/styles/csvPlugin.css index e814c7d..2740a7b 100644 --- a/src/styles/csvdisplay.css +++ b/src/styles/csvPlugin.css @@ -18,6 +18,10 @@ padding: 1rem; } +.input-type { + background-color: grey; +} + .input-key { text-align: left; margin-right: 0.5rem; From d023a6b7ff959b609374b5fb2959e9d28743935f Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Tue, 14 Jan 2025 19:44:59 +0900 Subject: [PATCH 12/14] =?UTF-8?q?[FEAT]=20csv=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=EC=97=90=20=EC=8B=A4=ED=8C=A8=20=EC=8B=9C=20?= =?UTF-8?q?=EB=AA=A8=EB=8B=AC=20=EB=8B=AB=EC=A7=80=20=EC=95=8A=EC=9D=8C=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/csvcreator.ts | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/csvcreator.ts b/src/csvcreator.ts index 1c606fd..e9ad3f8 100644 --- a/src/csvcreator.ts +++ b/src/csvcreator.ts @@ -3,7 +3,7 @@ import './styles/csvCreator.css'; import { columnTypes } from './types'; // dataviewjs 등으로 자동적으로 파일을 생성하게 할 때 사용할 수 있는 api -export const createCsvFile_ = (app: App, filename: string, filePath: string, columnData: { name:string, type: string }[]) => { +export const createCsvFile_ = (app: App, filename: string, filePath: string, columnData: { name:string, type: string }[]) : boolean => { // .csv 내용 생성 (헤더만 추가) const csvContent = columnData.map((col) => col.name).join(',') + '\n'; @@ -26,16 +26,18 @@ export const createCsvFile_ = (app: App, filename: string, filePath: string, col vault.adapter.write(fullPathCsv, csvContent).then(() => { new Notice(`${fullPathCsv} file has been created.`); }).catch((err) => { - new Notice(`Error occurred while creating .csv file: ${err}`); + new Notice(`Error occurred while creating .csv file:\n${err}`); + return false; }); // .csv.meta 파일 저장 vault.adapter.write(fullPathMeta, metaContent).then(() => { new Notice(`${fullPathMeta} file has been created.`); }).catch((err) => { - new Notice(`.csv.meta 파일 생성 중 오류 발생: ${err}`); - new Notice(`Error occurred while creating .csv.meta file: ${err}`); + new Notice(`Error occurred while creating .csv.meta file:\n${err}`); + return false; }); + return true; } export default class CsvCreateModal extends Modal { @@ -77,7 +79,7 @@ export default class CsvCreateModal extends Modal { // validation if (!filename) { new Notice('Please enter a file name.'); - return; + return false; } if(filename.endsWith('.csv')) { filename = filename.slice(0, -4); @@ -102,10 +104,10 @@ export default class CsvCreateModal extends Modal { if (columnData.length === 0) { new Notice('add at least one column'); - return; + return false; } - createCsvFile_(this.app, filename, filePath, columnData); + return createCsvFile_(this.app, filename, filePath, columnData); } // common api @@ -148,8 +150,14 @@ export default class CsvCreateModal extends Modal { contentEl.createEl('hr'); let buttonEl = contentEl.createEl('button', {text: 'Create'}); buttonEl.addEventListener('click', () => { - this.createCsvFile(); - this.close(); + event?.preventDefault(); + const result = this.createCsvFile(); + if(result) { + this.close(); + } + else { + new Notice('Error occurred while creating .csv file'); + } }); } From a225b565888d6e8c9520a9e4931ce027f4fe8783 Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Tue, 14 Jan 2025 20:09:28 +0900 Subject: [PATCH 13/14] =?UTF-8?q?[RENAME]=20=EC=B9=B4=EB=A9=9C=20=EC=BC=80?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/{csvcreator.ts => csvCreateor.ts} | 0 src/{csvexplorer.ts => csvExplorer.ts} | 0 src/{csvfilemanager.ts => csvFilemanager.ts} | 0 src/styles/{csvcreator.css => csvCreator.css} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/{csvcreator.ts => csvCreateor.ts} (100%) rename src/{csvexplorer.ts => csvExplorer.ts} (100%) rename src/{csvfilemanager.ts => csvFilemanager.ts} (100%) rename src/styles/{csvcreator.css => csvCreator.css} (100%) diff --git a/src/csvcreator.ts b/src/csvCreateor.ts similarity index 100% rename from src/csvcreator.ts rename to src/csvCreateor.ts diff --git a/src/csvexplorer.ts b/src/csvExplorer.ts similarity index 100% rename from src/csvexplorer.ts rename to src/csvExplorer.ts diff --git a/src/csvfilemanager.ts b/src/csvFilemanager.ts similarity index 100% rename from src/csvfilemanager.ts rename to src/csvFilemanager.ts diff --git a/src/styles/csvcreator.css b/src/styles/csvCreator.css similarity index 100% rename from src/styles/csvcreator.css rename to src/styles/csvCreator.css From 1e429510a5de115847d018da9ceb01e83f5f929c Mon Sep 17 00:00:00 2001 From: ChangHangeol Date: Tue, 14 Jan 2025 20:12:52 +0900 Subject: [PATCH 14/14] [VERSION] fix manifest --- manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index bd10535..91491ee 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,11 @@ { "id": "csv-allinone", "name": "CSV All-in-One", - "version": "0.1.1", + "version": "0.1.0", "minAppVersion": "1.7.7", "description": "all about csv.", "author": "hihangeol", "authorUrl": "https://github.com/Hangeol-Chang/obsidian-csv-allinone", - "fundingUrl": "https://github.com/Hangeol-Chang/obsidian-csv-allinone", + "fundingUrl": "https://buymeacoffee.com/hihangeol", "isDesktopOnly": false -} +} \ No newline at end of file