diff --git a/officeTheme.xml b/officeTheme.xml new file mode 100644 index 0000000..33cb7bf --- /dev/null +++ b/officeTheme.xml @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Views/SheetView.ts b/src/Views/SheetView.ts index 038db74..6d9c1bd 100644 --- a/src/Views/SheetView.ts +++ b/src/Views/SheetView.ts @@ -150,7 +150,7 @@ export function processCodeBlock( tip: "Save", icon: saveIcon, shortcut: "Ctrl+S", - onClick: (s, d) => saveDataIntoBlock(s, d, ctx), + onClick: (s: any, d: any) => saveDataIntoBlock(s, d, ctx), }, ], }; @@ -162,15 +162,15 @@ export function processCodeBlock( const xlsx = XLSX.read(fileContent, { cellStyles: true, - sheetStubs: true // > + sheetStubs: true, // > }); const workbook = new ExcelJS.Workbook(); - - const excelWorkbook = await workbook.xlsx.load(fileContent) + + const excelWorkbook = await workbook.xlsx.load(fileContent); const data2 = toSpreadsheet(excelWorkbook); - + // eslint-disable-next-line @typescript-eslint/no-unused-vars const data = stox(xlsx); (ctx as any).spreadsheet = createSpreadSheet( container, @@ -207,7 +207,8 @@ function saveDataIntoBlock( const s = (ctx as any).spreadsheet; const dts = s.getData(); - const view: MarkdownView = app.workspace.getActiveViewOfType(MarkdownView); + const view = app.workspace.getActiveViewOfType(MarkdownView); + if (!view) return; if (view.getMode() === "source") { const sec = ctx.getSectionInfo((ctx as any).el as HTMLElement); if (sec) { @@ -251,7 +252,7 @@ function createSpreadSheet( type: "buffer", compression: true, bookSST: true, - cellStyles: true + cellStyles: true, }); // fs.writeFile(filename,bytes); app.vault.adapter.writeBinary(options.filename, bytes); @@ -270,11 +271,11 @@ function createSpreadSheet( function applyStyles(ssdata: any, wb: XLSX.WorkBook) { console.log(ssdata, wb); - for (let sheet of ssdata) { + for (const sheet of ssdata) { const { name, styles, rows } = sheet; - for (let rowId in rows) { + for (const rowId in rows) { const cells = rows[rowId]["cells"]; - for (let cellId in cells) { + for (const cellId in cells) { const cell = cells[cellId]; if (cell.style !== undefined) { const wbStyle = styleSS2WB(styles[cell.style]); diff --git a/src/utils/excelColors.ts b/src/utils/excelColors.ts new file mode 100644 index 0000000..1925cac --- /dev/null +++ b/src/utils/excelColors.ts @@ -0,0 +1,67 @@ +// Sample theme color index +// const themeColorIndex = 1; // The theme color index (0-9) +// const tintVal = -0.5; // The tint value (-1 to 1) + +// Sample Office Color Themes +const officeThemeColors = [ + [255, 255, 255], // White + [0, 0, 0], // Black + [238, 236, 225], // Tan + [31, 73, 125], // Dark Blue + [79, 129, 189], // Blue + [192, 80, 77], // Red + [155, 187, 89], // Green + [128, 100, 162], // Purple + [75, 172, 198], // Aqua + [245, 150, 70], // Orange +]; + +const RGBToHSL = (r:number, g:number, b:number) => { + r /= 255; + g /= 255; + b /= 255; + const l = Math.max(r, g, b); + const s = l - Math.min(r, g, b); + const h = s + ? l === r + ? (g - b) / s + : l === g + ? 2 + (b - r) / s + : 4 + (r - g) / s + : 0; + return [ + 60 * h < 0 ? 60 * h + 360 : 60 * h, + 100 * (s ? (l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s))) : 0), + (100 * (2 * l - s)) / 2, + ]; + }; + +// TODO: read theme from XML +export function convertThemeColorToRGB( + themeColorIndex: number, + tintVal: number +) { + const baseColor = officeThemeColors[themeColorIndex]; + const baseHSL = RGBToHSL(baseColor[0],baseColor[1], baseColor[2]) //rgb2hsl(baseColor); + const lumination = baseHSL[2]; + if (tintVal < 0) { + baseHSL[2] = lumination * (1.0 + tintVal); + } else { + baseHSL[2] = lumination * (1.0 - tintVal) + 100 * tintVal; + } + + // return HSLToRGB(baseHSL[0] / 360, baseHSL[1] / 100, baseHSL[2] / 100); + return hsl2rgb(baseHSL[0], baseHSL[1] / 100, baseHSL[2] / 100); +} + +// input: h as an angle in [0,360] and s,l in [0,1] +function hsl2rgb(h:number,s:number,l:number) +{ + const a=s*Math.min(l,1-l); + const f= (n:number,k=(n+h/30)%12) => l - a*Math.max(Math.min(k-3,9-k,1),-1); + return [f(0)*255,f(8)*255,f(4)*255].map(Math.round); +} + +export function rgbToHex(r:number, g:number, b:number) { + return r.toString(16) + g.toString(16) + b.toString(16); +} diff --git a/src/utils/excelConverter.ts b/src/utils/excelConverter.ts index 66c195a..45728df 100644 --- a/src/utils/excelConverter.ts +++ b/src/utils/excelConverter.ts @@ -1,52 +1,111 @@ -import { Workbook } from "exceljs"; +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { Workbook } from "exceljs"; +import { convertThemeColorToRGB, rgbToHex } from "./excelColors"; + + export function toSpreadsheet(wb: Workbook) { - const out = wb.worksheets.map(ws=>{ - const ows = { + + + + const out = wb.worksheets.map((ws) => { + const ows = { name: ws.name, rows: {} as any, merges: [] as string[], styles: [] as any[], - // freezes: - } - ws.eachRow((row, rowNumber)=>{ - const rowId = String(row.number-1) - const rowob:any = { - cells: {} + // freezes: + }; + ws.eachRow((row, rowNumber) => { + const rowId = String(row.number - 1); + const rowob: any = { + cells: {}, }; ows.rows[rowId] = rowob; - const cells = row.eachCell((cell,cellNumber)=>{ + row.eachCell((cell, cellNumber) => { const cellOb = { - text: cell.text, - merge: [] as number[] + text: cell.text + } as any; + if (cell.formula) cellOb.text = "=" + cell.formula; + + // style + const oStyle: any = {}; + if (cell.style.fill) { + // + // console.log(cell.style.fill); + if (cell.style.fill.type === "pattern") { + const fgColor = cell.style.fill.fgColor; + if (fgColor) { + if (fgColor.argb) { + // + } else if (fgColor.theme !== undefined) { + const theme = fgColor?.theme; + const tint = (fgColor as any).tint || 0; + const rgb = convertThemeColorToRGB(theme, tint); + const hex = rgbToHex(rgb[0],rgb[1],rgb[2]); + oStyle.bgcolor = "#" + hex; + + } + } + } + } - if(cell.formula) cellOb.text = "=" + cell.formula; - if(!cell.isMerged || !cell.model.master){ - rowob.cells[Number(cell.col)-1] = cellOb; - if(cell.isMerged){ + + if (cell.style.border) { + // + } + if (cell.style.font) { + // + } + if (cell.style.alignment) { + // + } + if (cell.style.numFmt) { + // + } + if (cell.style.protection) { + // + } + + if(Object.keys(oStyle).length>0){ + console.log(oStyle); + // TODO: index it and put index in cell + const j = JSON.stringify(oStyle) + let styleIndex = ows.styles.findIndex(s => + JSON.stringify(s) == j + ) + if(styleIndex<0) { + ows.styles.push(oStyle); + styleIndex = ows.styles.length-1; + } + cellOb.style = styleIndex; + } + + + if (!cell.isMerged || !cell.model.master) { + rowob.cells[Number(cell.col) - 1] = cellOb; + if (cell.isMerged) { const merge = (ws as any)._merges[cell.address]; - // console.log(merge); cellOb.merge = [ - merge.bottom-merge.top as number, - merge.right-merge.left as number - ] + (merge.bottom - merge.top) as number, + (merge.right - merge.left) as number, + ]; } } else { // } - }) - - }) - // merges + }); + }); + // merges const merges = []; - for(let m in (ws as any)._merges){ + for (const m in (ws as any)._merges) { const merge = (ws as any)._merges[m]; - const range = merge.range + const range = merge.range; merges.push(range); } ows.merges = merges; return ows; }); - - return out; + + return out; }