From f26a119269533ebb6029c7c45dfdde68cde3d9fa Mon Sep 17 00:00:00 2001 From: Marius <136248525+Sophokles187@users.noreply.github.com> Date: Fri, 7 Mar 2025 19:13:48 +0100 Subject: [PATCH] added text size settings --- main.js | 12 ++++---- src/models/settings.ts | 7 +++++ src/services/renderer.ts | 10 +++++++ src/ui/settings-tab.ts | 15 ++++++++++ styles.css | 62 ++++++++++++++++++++++++++++++++++------ 5 files changed, 91 insertions(+), 15 deletions(-) diff --git a/main.js b/main.js index 0eeea7b..8844d70 100644 --- a/main.js +++ b/main.js @@ -3,7 +3,7 @@ THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin- */ -var A=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var U=(h,s)=>{for(var e in s)A(h,e,{get:s[e],enumerable:!0})},B=(h,s,e,t)=>{if(s&&typeof s=="object"||typeof s=="function")for(let r of $(s))!R.call(h,r)&&r!==e&&A(h,r,{get:()=>s[r],enumerable:!(t=I(s,r))||t.enumerable});return h};var N=h=>B(A({},"__esModule",{value:!0}),h);var q={};U(q,{default:()=>k});module.exports=N(q);var b=require("obsidian");var v={preset:"grid",imageProperty:"cover",imageHeight:"200px",imageFit:"cover",properties:"all",exclude:[],scrollableProperties:!1,contentHeight:"200px",showLabels:!0,cardSpacing:16,enableShadows:!0,propertiesAlign:"left",titleAlign:"left",defaultDateFormat:"YYYY-MM-DD",propertyFormatters:{},mobileColumns:1,mobilePreset:"grid",mobileImageHeight:"150px",mobileScrollableProperties:!0,mobileContentHeight:"150px",forceMobileMode:!1,enableLazyLoading:!1,debugMode:!1};var m=require("obsidian"),E=class extends m.PluginSettingTab{constructor(e,t){super(e,t);this.plugin=t}display(){let{containerEl:e}=this;e.empty(),e.createEl("h2",{text:"DataCards Settings"}),e.createEl("h3",{text:"Preset Settings"}),new m.Setting(e).setName("Default Preset").setDesc("Choose the default preset for cards").addDropdown(r=>r.addOption("grid","Grid (balanced, 3 columns)").addOption("portrait","Portrait (optimized for book covers, 3 columns)").addOption("square","Square (1:1 cards with minimal text, 4 columns)").addOption("compact","Compact (side-by-side layout, 4 columns)").addOption("dense","Dense (maximum density, 6 columns)").setValue(this.plugin.settings.preset).onChange(async i=>{this.plugin.settings.preset=i,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Image Settings"}),new m.Setting(e).setName("Default Image Property").setDesc("The frontmatter property to use for images").addText(r=>r.setPlaceholder("cover").setValue(this.plugin.settings.imageProperty).onChange(async i=>{this.plugin.settings.imageProperty=i,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Display Settings"}),new m.Setting(e).setName("Show Property Labels").setDesc("Show labels for properties").addToggle(r=>r.setValue(this.plugin.settings.showLabels).onChange(async i=>{this.plugin.settings.showLabels=i,await this.plugin.saveSettings()})),new m.Setting(e).setName("Card Spacing").setDesc("Space between cards (in pixels)").addSlider(r=>r.setLimits(0,32,4).setValue(this.plugin.settings.cardSpacing).setDynamicTooltip().onChange(async i=>{this.plugin.settings.cardSpacing=i,await this.plugin.saveSettings()})),new m.Setting(e).setName("Enable Card Shadows").setDesc("Add subtle shadows to cards for a more three-dimensional appearance").addToggle(r=>r.setValue(this.plugin.settings.enableShadows).onChange(async i=>{this.plugin.settings.enableShadows=i,await this.plugin.saveSettings()})),new m.Setting(e).setName("Properties Alignment").setDesc("Text alignment for properties and their labels").addDropdown(r=>r.addOption("left","Left").addOption("center","Center").addOption("right","Right").setValue(this.plugin.settings.propertiesAlign).onChange(async i=>{this.plugin.settings.propertiesAlign=i,await this.plugin.saveSettings()})),new m.Setting(e).setName("Title Alignment").setDesc("Text alignment for the title (filename)").addDropdown(r=>r.addOption("left","Left").addOption("center","Center").addOption("right","Right").setValue(this.plugin.settings.titleAlign).onChange(async i=>{this.plugin.settings.titleAlign=i,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Card Content Settings"}),new m.Setting(e).setName("Scrollable Properties").setDesc("Enable scrolling for card properties when they exceed the content height (Note: Square and Compact presets are scrollable by default)").addToggle(r=>r.setValue(this.plugin.settings.scrollableProperties).onChange(async i=>{this.plugin.settings.scrollableProperties=i,await this.plugin.saveSettings()})),new m.Setting(e).setName("Content Height").setDesc("Height of the scrollable content area (e.g., 200px)").addText(r=>r.setPlaceholder("200px").setValue(this.plugin.settings.contentHeight).onChange(async i=>{this.plugin.settings.contentHeight=i||"200px",await this.plugin.saveSettings()})),e.createEl("h3",{text:"Formatting Settings"}),new m.Setting(e).setName("Default Date Format").setDesc("Format for displaying dates (YYYY = year, MM = month, DD = day)").addText(r=>r.setPlaceholder("YYYY-MM-DD").setValue(this.plugin.settings.defaultDateFormat).onChange(async i=>{this.plugin.settings.defaultDateFormat=i||"YYYY-MM-DD",await this.plugin.saveSettings()})),e.createEl("h3",{text:"Mobile Settings"}),new m.Setting(e).setName("Mobile Preset").setDesc("Preset to use on mobile devices (all presets default to 1 column on mobile)").addDropdown(r=>r.addOption("grid","Grid (balanced)").addOption("portrait","Portrait (optimized for book covers)").addOption("square","Square (1:1 cards with minimal text)").addOption("compact","Compact (side-by-side layout)").addOption("dense","Dense (maximum density)").setValue(this.plugin.settings.mobilePreset).onChange(async i=>{this.plugin.settings.mobilePreset=i,await this.plugin.saveSettings()})),new m.Setting(e).setName("Mobile Scrollable Properties").setDesc("Enable scrolling for card properties on mobile devices").addToggle(r=>r.setValue(this.plugin.settings.mobileScrollableProperties).onChange(async i=>{this.plugin.settings.mobileScrollableProperties=i,await this.plugin.saveSettings()})),new m.Setting(e).setName("Mobile Content Height").setDesc("Height of the scrollable content area on mobile devices").addText(r=>r.setPlaceholder("150px").setValue(this.plugin.settings.mobileContentHeight).onChange(async i=>{this.plugin.settings.mobileContentHeight=i||"150px",await this.plugin.saveSettings()})),new m.Setting(e).setName("Force Mobile Mode").setDesc("Force the plugin to use mobile settings even on desktop (for testing)").addToggle(r=>r.setValue(this.plugin.settings.forceMobileMode).onChange(async i=>{this.plugin.settings.forceMobileMode=i,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Performance Settings"}),new m.Setting(e).setName("Enable Lazy Loading").setDesc("Only load images when they become visible (improves performance with many cards)").addToggle(r=>r.setValue(this.plugin.settings.enableLazyLoading).onChange(async i=>{this.plugin.settings.enableLazyLoading=i,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Developer Settings"}),new m.Setting(e).setName("Debug Mode").setDesc("Enable debug logging (only use during development or troubleshooting)").addToggle(r=>r.setValue(this.plugin.settings.debugMode).onChange(async i=>{this.plugin.settings.debugMode=i,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Help"});let t=e.createEl("div");t.innerHTML=` +var A=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var R=Object.prototype.hasOwnProperty;var U=(h,n)=>{for(var e in n)A(h,e,{get:n[e],enumerable:!0})},B=(h,n,e,t)=>{if(n&&typeof n=="object"||typeof n=="function")for(let a of $(n))!R.call(h,a)&&a!==e&&A(h,a,{get:()=>n[a],enumerable:!(t=I(n,a))||t.enumerable});return h};var N=h=>B(A({},"__esModule",{value:!0}),h);var O={};U(O,{default:()=>k});module.exports=N(O);var b=require("obsidian");var v={preset:"grid",imageProperty:"cover",imageHeight:"200px",imageFit:"cover",properties:"all",exclude:[],scrollableProperties:!1,contentHeight:"200px",showLabels:!0,cardSpacing:16,enableShadows:!0,propertiesAlign:"left",titleAlign:"left",fontSize:"default",defaultDateFormat:"YYYY-MM-DD",propertyFormatters:{},mobileColumns:1,mobilePreset:"grid",mobileImageHeight:"150px",mobileScrollableProperties:!0,mobileContentHeight:"150px",forceMobileMode:!1,enableLazyLoading:!1,debugMode:!1};var m=require("obsidian"),E=class extends m.PluginSettingTab{constructor(e,t){super(e,t);this.plugin=t}display(){let{containerEl:e}=this;e.empty(),e.createEl("h2",{text:"DataCards Settings"}),e.createEl("h3",{text:"Preset Settings"}),new m.Setting(e).setName("Default Preset").setDesc("Choose the default preset for cards").addDropdown(a=>a.addOption("grid","Grid (balanced, 3 columns)").addOption("portrait","Portrait (optimized for book covers, 3 columns)").addOption("square","Square (1:1 cards with minimal text, 4 columns)").addOption("compact","Compact (side-by-side layout, 4 columns)").addOption("dense","Dense (maximum density, 6 columns)").setValue(this.plugin.settings.preset).onChange(async r=>{this.plugin.settings.preset=r,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Image Settings"}),new m.Setting(e).setName("Default Image Property").setDesc("The frontmatter property to use for images").addText(a=>a.setPlaceholder("cover").setValue(this.plugin.settings.imageProperty).onChange(async r=>{this.plugin.settings.imageProperty=r,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Display Settings"}),new m.Setting(e).setName("Show Property Labels").setDesc("Show labels for properties").addToggle(a=>a.setValue(this.plugin.settings.showLabels).onChange(async r=>{this.plugin.settings.showLabels=r,await this.plugin.saveSettings()})),new m.Setting(e).setName("Card Spacing").setDesc("Space between cards (in pixels)").addSlider(a=>a.setLimits(0,32,4).setValue(this.plugin.settings.cardSpacing).setDynamicTooltip().onChange(async r=>{this.plugin.settings.cardSpacing=r,await this.plugin.saveSettings()})),new m.Setting(e).setName("Enable Card Shadows").setDesc("Add subtle shadows to cards for a more three-dimensional appearance").addToggle(a=>a.setValue(this.plugin.settings.enableShadows).onChange(async r=>{this.plugin.settings.enableShadows=r,await this.plugin.saveSettings()})),new m.Setting(e).setName("Properties Alignment").setDesc("Text alignment for properties and their labels").addDropdown(a=>a.addOption("left","Left").addOption("center","Center").addOption("right","Right").setValue(this.plugin.settings.propertiesAlign).onChange(async r=>{this.plugin.settings.propertiesAlign=r,await this.plugin.saveSettings()})),new m.Setting(e).setName("Title Alignment").setDesc("Text alignment for the title (filename)").addDropdown(a=>a.addOption("left","Left").addOption("center","Center").addOption("right","Right").setValue(this.plugin.settings.titleAlign).onChange(async r=>{this.plugin.settings.titleAlign=r,await this.plugin.saveSettings()})),new m.Setting(e).setName("Font Size").setDesc("Text size for all card elements (properties, labels, and title)").addDropdown(a=>a.addOption("larger","Larger (120%)").addOption("large","Large (110%)").addOption("default","Default (100%)").addOption("small","Small (90% - similar to dense preset)").addOption("smaller","Smaller (80%)").setValue(this.plugin.settings.fontSize).onChange(async r=>{this.plugin.settings.fontSize=r,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Card Content Settings"}),new m.Setting(e).setName("Scrollable Properties").setDesc("Enable scrolling for card properties when they exceed the content height (Note: Square and Compact presets are scrollable by default)").addToggle(a=>a.setValue(this.plugin.settings.scrollableProperties).onChange(async r=>{this.plugin.settings.scrollableProperties=r,await this.plugin.saveSettings()})),new m.Setting(e).setName("Content Height").setDesc("Height of the scrollable content area (e.g., 200px)").addText(a=>a.setPlaceholder("200px").setValue(this.plugin.settings.contentHeight).onChange(async r=>{this.plugin.settings.contentHeight=r||"200px",await this.plugin.saveSettings()})),e.createEl("h3",{text:"Formatting Settings"}),new m.Setting(e).setName("Default Date Format").setDesc("Format for displaying dates (YYYY = year, MM = month, DD = day)").addText(a=>a.setPlaceholder("YYYY-MM-DD").setValue(this.plugin.settings.defaultDateFormat).onChange(async r=>{this.plugin.settings.defaultDateFormat=r||"YYYY-MM-DD",await this.plugin.saveSettings()})),e.createEl("h3",{text:"Mobile Settings"}),new m.Setting(e).setName("Mobile Preset").setDesc("Preset to use on mobile devices (all presets default to 1 column on mobile)").addDropdown(a=>a.addOption("grid","Grid (balanced)").addOption("portrait","Portrait (optimized for book covers)").addOption("square","Square (1:1 cards with minimal text)").addOption("compact","Compact (side-by-side layout)").addOption("dense","Dense (maximum density)").setValue(this.plugin.settings.mobilePreset).onChange(async r=>{this.plugin.settings.mobilePreset=r,await this.plugin.saveSettings()})),new m.Setting(e).setName("Mobile Scrollable Properties").setDesc("Enable scrolling for card properties on mobile devices").addToggle(a=>a.setValue(this.plugin.settings.mobileScrollableProperties).onChange(async r=>{this.plugin.settings.mobileScrollableProperties=r,await this.plugin.saveSettings()})),new m.Setting(e).setName("Mobile Content Height").setDesc("Height of the scrollable content area on mobile devices").addText(a=>a.setPlaceholder("150px").setValue(this.plugin.settings.mobileContentHeight).onChange(async r=>{this.plugin.settings.mobileContentHeight=r||"150px",await this.plugin.saveSettings()})),new m.Setting(e).setName("Force Mobile Mode").setDesc("Force the plugin to use mobile settings even on desktop (for testing)").addToggle(a=>a.setValue(this.plugin.settings.forceMobileMode).onChange(async r=>{this.plugin.settings.forceMobileMode=r,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Performance Settings"}),new m.Setting(e).setName("Enable Lazy Loading").setDesc("Only load images when they become visible (improves performance with many cards)").addToggle(a=>a.setValue(this.plugin.settings.enableLazyLoading).onChange(async r=>{this.plugin.settings.enableLazyLoading=r,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Developer Settings"}),new m.Setting(e).setName("Debug Mode").setDesc("Enable debug logging (only use during development or troubleshooting)").addToggle(a=>a.setValue(this.plugin.settings.debugMode).onChange(async r=>{this.plugin.settings.debugMode=r,await this.plugin.saveSettings()})),e.createEl("h3",{text:"Help"});let t=e.createEl("div");t.innerHTML=`

Basic Usage:
Use the datacards code block to create card layouts from Dataview queries.

@@ -29,8 +29,8 @@ defaultDateFormat: YYYY

Tip: Data Cards works best with the Editor-Setting "Readable line length" disabled.


View complete documentation and examples on GitHub

- `}};var n=class{static setDebugMode(s){this.debugMode=s}static error(s,...e){console.error(`[DataCards] ${s}`,...e)}static warn(s,...e){console.warn(`[DataCards] ${s}`,...e)}static debug(s,...e){this.debugMode&&console.log(`[DataCards] ${s}`,...e)}};n.debugMode=!1;var D=class{parseDataCardsBlock(s){n.debug("Parsing datacards block");let e=/\n-{3,}\n|\n\/\/\s*Settings.*|\n\/\*\s*Settings\s*\*\/.*/,t=s.match(e),r=/^\/\/\s*Settings.*/,i=s.match(r),a,o;t&&t.index!==void 0?(n.debug("Found settings separator at index:",t.index),a=s.substring(0,t.index).trim(),o=s.substring(t.index+t[0].length).trim()):i?(n.debug("Block starts with settings marker"),a="",o=s.substring(i[0].length).trim()):(n.debug("No settings separator found"),a=s.trim(),o=""),n.debug("Extracted query:",a),a=this.ensureQueryType(a);let l=this.parseSettings(o),d=this.extractColumnAliases(a);return d.length>0&&(l.columnAliases=d,n.debug("Extracted column aliases:",d)),{query:a,settings:l}}extractColumnAliases(s){let e=[];if(!s.trim().toUpperCase().startsWith("TABLE"))return e;try{let t=s.match(/TABLE\s+(without\s+id\s+)?([\s\S]*?)(?:\s+FROM|\s+WHERE|\s+SORT|\s+GROUP BY|\s+LIMIT|\s+FLATTEN|$)/i);if(!t||!t[2])return e;let r=t[2].trim();if(n.debug("Extracted columns text:",r),!r)return e;let i=this.splitColumnsPreservingExpressions(r);for(let a of i){let o=a.match(/^(.*?)\s+as\s+(?:"([^"]+)"|'([^']+)'|([^\s,]+))$/i);if(o){let l=o[1].trim(),d=o[2]||o[3]||o[4],c=l;if(/^[a-zA-Z0-9_.-]+$/.test(l))c=l;else{let g=l.match(/\(\s*".*?"\s*\+\s*([a-zA-Z0-9_.-]+)\s*\+\s*".*?"\s*\)/);g&&g[1]&&(c=g[1],n.debug(`Extracted field name from complex expression: ${c}`))}e.push({original:c,alias:d,expression:l}),n.debug(`Found column alias: ${c} as "${d}"`)}}}catch(t){n.error("Error extracting column aliases:",t)}return e}splitColumnsPreservingExpressions(s){let e=[],t="",r=0,i=!1,a=!1;for(let o=0;o=0){let i=this.parseSettings(t.slice(r+1).join(` -`)),a="",o=[];return i.imageProperty&&o.push(i.imageProperty),a="",n.debug("Using simple TABLE query without property list"),a.trim()===""?t[r]="TABLE "+t[r]:t[r]="TABLE"+a+" "+t[r],t.join(` -`)}else return"TABLE "+s}return s}parseSettings(s){if(!s)return{};let e={},t=s.split(` -`);n.debug("Parsing settings from text");for(let r of t){if(r.trim().startsWith("//")||r.trim().startsWith("/*")||!r.trim())continue;let i=r.match(/^\s*([a-zA-Z0-9_]+)\s*:\s*(.+)\s*$/);if(i){let[,a,o]=i;if(n.debug(`Found setting: ${a} = ${o}`),a==="properties"&&o.trim().startsWith("[")&&o.trim().endsWith("]")){n.debug("Detected properties array");let l=o.substring(1,o.length-1).trim();if(l){let d=l.split(",").map(c=>c.trim());e[a]=d}else e[a]=[]}else a==="defaultDateFormat"?e[a]=o.trim():e[a]=this.parseValue(o.trim())}}return e}parseValue(s){n.debug("Parsing value:",s);try{return JSON.parse(s)}catch(e){}if(s.startsWith("[")&&s.endsWith("]")){n.debug("Detected array syntax");let e=s.substring(1,s.length-1).trim();return e?e.split(",").map(r=>r.trim()):[]}return/^-?\d+(\.\d+)?$/.test(s)?Number(s):s.toLowerCase()==="true"?!0:s.toLowerCase()==="false"?!1:s}};var F=require("obsidian");var C=class{constructor(s,e){this.currentSettings=null;this.app=s,this.pluginSettings=e}updateSettings(s){this.pluginSettings=s}isMobileDevice(){return F.Platform.isMobile||this.pluginSettings.forceMobileMode}renderCards(s,e,t){let r=this.isMobileDevice();n.debug("Is mobile device:",r);let i={...this.pluginSettings};n.debug("Initial settings from plugin:",{preset:i.preset,imageHeight:i.imageHeight,mobileColumns:i.mobileColumns,mobilePreset:i.mobilePreset,mobileImageHeight:i.mobileImageHeight}),i={...i,...t},n.debug("After applying block settings:",{preset:i.preset,imageHeight:i.imageHeight,mobileColumns:i.mobileColumns,mobilePreset:i.mobilePreset,mobileImageHeight:i.mobileImageHeight}),r&&(n.debug("Applying mobile settings..."),n.debug(`Using mobile columns: ${i.mobileColumns}`),i.mobilePreset!==void 0&&(n.debug(`Overriding preset: ${i.preset} with mobilePreset: ${i.mobilePreset}`),i.preset=i.mobilePreset),i.mobileImageHeight!==void 0&&(n.debug(`Overriding imageHeight: ${i.imageHeight} with mobileImageHeight: ${i.mobileImageHeight}`),i.imageHeight=i.mobileImageHeight),n.debug("Final settings after applying mobile settings:",{preset:i.preset,imageHeight:i.imageHeight})),this.currentSettings=i;let a=s.createEl("div",{cls:"datacards-container"});a.addClass(`datacards-preset-${i.preset}`),i.enableShadows||a.addClass("datacards-no-shadows"),a.style.setProperty("--card-gap",`${i.cardSpacing}px`);let o;if(r)o=i.mobileColumns;else{let d=3;i.preset==="dense"?d=6:i.preset==="compact"||i.preset==="square"?d=4:i.preset==="portrait"&&(d=3),o=t.columns!==void 0?t.columns:d}n.debug(`Using ${o} columns`),a.style.setProperty("--card-columns",o.toString(),"important");let l;if(t.imageHeight!==void 0?l=i.imageHeight:i.preset==="portrait"?l="350px":i.preset==="square"||i.preset==="compact"?l="200px":i.preset==="dense"?l="120px":l="200px",(typeof l=="number"||/^\d+$/.test(l))&&(l=`${l}px`),a.style.setProperty("--image-height",l),t.imageFit!==void 0)a.style.setProperty("--image-fit",i.imageFit);else{let d=i.preset==="portrait"?"contain":"cover";a.style.setProperty("--image-fit",d)}e&&e.values&&Array.isArray(e.values)?(n.debug("Detected table-like results with values array"),this.renderTableResults(a,e,i)):e&&Array.isArray(e)?(n.debug("Detected array results"),this.renderArrayResults(a,e,i)):e&&typeof e=="object"?(n.debug("Detected object results"),this.renderObjectResults(a,e,i)):(n.debug("No valid results detected"),this.renderError(a,"No results or unsupported result type"))}renderError(s,e){let t=s.createEl("div",{cls:"datacards-error",text:e})}renderTableResults(s,e,t){let{values:r,headers:i}=e;n.debug("Rendering table results:"),n.debug("- Headers:",i),n.debug("- Number of rows:",r.length),r.forEach((a,o)=>{n.debug(`Processing row ${o}`);let l=this.createCardElement(s);if(t.imageProperty&&i.includes(t.imageProperty)){let u=i.indexOf(t.imageProperty),y=a[u];n.debug(`Image property '${t.imageProperty}' value:`,y),y&&this.addImageToCard(l,y)}else t.imageProperty&&n.debug(`Image property '${t.imageProperty}' not found in headers:`,i);let d=l.createEl("div",{cls:"datacards-content"});if(i.includes("File")||i.includes("file")){let u=i.findIndex(y=>y.toLowerCase()==="file");if(u>=0){let y=a[u];n.debug("File property value:",y);let f=d.createEl("div",{cls:"datacards-property datacards-file-property-container"});this.formatFileProperty(f,y)}}let c=d.createEl("div",{cls:"datacards-properties-container"});if(this.shouldUseScrollableProperties(t)){c.addClass("datacards-scrollable-properties");let u=this.getContentHeight(t);c.style.setProperty("--content-height",u)}let p=[];t.properties==="all"?(p=[...i],n.debug("Using all headers as properties:",p)):Array.isArray(t.properties)?(p=[...t.properties],n.debug("Using specified properties:",p)):n.debug("No properties specified, using empty array");let x=p.filter(u=>!t.exclude.includes(u)&&u!==t.imageProperty&&u.toLowerCase()!=="file");n.debug("Filtered properties (after excluding file):",x),x.forEach(u=>{if(n.debug(`Checking property '${u}' in headers:`,i.includes(u)),i.includes(u)){let y=i.indexOf(u),f=a[y];if(console.log(`Property '${u}' value:`,f),console.log(`Property '${u}' type:`,typeof f),typeof f=="string"&&f.includes("[[")&&f.includes("]]")){console.log(`Found wiki link in property '${u}':`,f);let P=c.createEl("div",{cls:"datacards-property"});t.showLabels&&P.createEl("div",{cls:"datacards-property-label",text:u});let M=P.createEl("div",{cls:"datacards-property-value"}),T=f.match(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/);if(T){let w=T[1],L=T[2]||this.getCleanFilename(w);console.log(`Creating direct link for wiki link: path="${w}", display="${L}"`);let H=M.createEl("a",{cls:"internal-link",text:L,attr:{href:w,"data-href":w,"data-type":"link"}});this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:H,targetEl:H,linktext:w})}else M.setText(f)}else this.addPropertyToCard(c,u,f,t)}else n.debug(`Property '${u}' not found in headers`)}),x.length===0&&!i.some(u=>u.toLowerCase()==="file")&&(n.debug("No properties were added to the card"),d.createEl("div",{cls:"datacards-property",text:"No properties to display"}))})}renderArrayResults(s,e,t){e.forEach(r=>{let i=this.createCardElement(s);t.imageProperty&&r[t.imageProperty]&&this.addImageToCard(i,r[t.imageProperty]);let a=i.createEl("div",{cls:"datacards-content"});if("file"in r){let p=a.createEl("div",{cls:"datacards-property datacards-file-property-container"});this.formatFileProperty(p,r.file)}let o=a.createEl("div",{cls:"datacards-properties-container"});if(this.shouldUseScrollableProperties(t)){o.addClass("datacards-scrollable-properties");let p=this.getContentHeight(t);o.style.setProperty("--content-height",p)}let d=Object.keys(r);(t.properties==="all"?d:Array.isArray(t.properties)?t.properties:[]).filter(p=>!t.exclude.includes(p)&&p!==t.imageProperty&&p.toLowerCase()!=="file").forEach(p=>{p in r&&this.addPropertyToCard(o,p,r[p],t)})})}renderObjectResults(s,e,t){let r=this.createCardElement(s);t.imageProperty&&e[t.imageProperty]&&this.addImageToCard(r,e[t.imageProperty]);let i=r.createEl("div",{cls:"datacards-content"});if("file"in e){let g=i.createEl("div",{cls:"datacards-property datacards-file-property-container"});this.formatFileProperty(g,e.file)}let a=i.createEl("div",{cls:"datacards-properties-container"});if(this.shouldUseScrollableProperties(t)){a.addClass("datacards-scrollable-properties");let g=this.getContentHeight(t);a.style.setProperty("--content-height",g)}let l=Object.keys(e);(t.properties==="all"?l:Array.isArray(t.properties)?t.properties:[]).filter(g=>!t.exclude.includes(g)&&g!==t.imageProperty&&g.toLowerCase()!=="file").forEach(g=>{g in e&&this.addPropertyToCard(a,g,e[g],t)})}createCardElement(s){return s.createEl("div",{cls:"datacards-card"})}addImageToCard(s,e){var a;let t=s.createEl("div",{cls:"datacards-image-container"}),r;typeof e=="object"&&e!==null?(n.debug("Image value is an object:",e),"path"in e?(r=e.path,n.debug("Extracted path from Link object:",r)):(r=String(e),n.debug("Converted object to string:",r))):(r=String(e),n.debug("Image value is a string:",r)),r=this.extractImageSource(r),n.debug("After image source extraction:",r);let i=t.createEl("div",{cls:"datacards-image-placeholder",text:"Loading image..."});(a=this.currentSettings)!=null&&a.enableLazyLoading?this.lazyLoadImage(t,i,r):this.loadImage(t,i,r)}extractImageSource(s){if(!s||typeof s!="string")return String(s||"");let e=s.match(/!\[(.*?)\]\((.*?)\)/);if(e){let i=e[2];return n.debug("Extracted URL from markdown image syntax:",i),i.replace(/['",.;:]+$/,"")}let t=s.match(/\[\[(.*?)\]\]/);if(t){let i=`[[${t[1]}]]`;return n.debug("Extracted wiki link:",i),i}let r=s.match(/(https?:\/\/[^\s"'<>[\]{}]+)/);if(r){let i=r[1];return n.debug("Extracted URL:",i),i.replace(/['",.;:]+$/,"")}return s}lazyLoadImage(s,e,t){n.debug("Lazy loading image:",t),new IntersectionObserver((i,a)=>{i.forEach(o=>{o.isIntersecting&&(n.debug("Image container is now visible, loading image:",t),this.loadImage(s,e,t),a.disconnect())})},{rootMargin:"100px",threshold:.1}).observe(s)}loadImage(s,e,t){let r=t.match(/!\[(.*?)\]\((.*?)\)/);if(r){let i=r[2];n.debug("Extracted URL from markdown image syntax:",i),this.loadImage(s,e,i);return}if(t.startsWith("http")||t.startsWith("https")){n.debug("Handling as external URL:",t);let i=t.replace(/['",.;:]+$/,"");n.debug("Cleaned URL:",i),this.loadExternalImage(s,e,i)}else if(t.startsWith("[[")&&t.endsWith("]]")){n.debug("Handling as wiki link");let i=t.substring(2,t.length-2),a=i;i.includes("|")&&(a=i.split("|")[0]);try{let o=this.app.vault.getAbstractFileByPath(a);if(o&&"stat"in o){n.debug("Found file in vault:",o);let l=o,d=this.app.vault.getResourcePath(l);n.debug("Resource path:",d);let c=s.createEl("img",{cls:"datacards-image",attr:{src:d}});c.onload=()=>{e.remove(),c.addClass("loaded")},c.onerror=()=>{e.setText("Image not found")}}else n.debug("File not found in vault or not a file:",a),e.setText("Image not found")}catch(o){n.error("Error loading image:",o),e.setText("Error loading image")}}else{n.debug("Handling as local path");try{let i=this.app.vault.getAbstractFileByPath(t);if(i&&"stat"in i){n.debug("Found file in vault:",i);let a=i,o=this.app.vault.getResourcePath(a);n.debug("Resource path:",o);let l=s.createEl("img",{cls:"datacards-image",attr:{src:o}});l.onload=()=>{e.remove(),l.addClass("loaded")},l.onerror=()=>{e.setText("Image not found")}}else n.debug("File not found in vault:",t),e.setText("Image not found")}catch(i){n.error("Error loading image:",i),e.setText("Error loading image")}}}loadExternalImage(s,e,t){n.debug("Loading external image with URL:",t);let r=s.createEl("img",{cls:"datacards-image",attr:{src:t,crossorigin:"anonymous"}});r.onload=()=>{n.debug("External image loaded successfully:",t),e.remove(),r.addClass("loaded")},r.onerror=i=>{n.error("Failed to load external image with crossorigin attribute:",t,i),n.debug("Trying again without crossorigin attribute"),r.removeAttribute("crossorigin"),r.onload=()=>{n.debug("External image loaded successfully without crossorigin:",t),e.remove(),r.addClass("loaded")},r.onerror=a=>{n.error("Failed to load external image without crossorigin:",t,a);let o=`https://images.weserv.nl/?url=${encodeURIComponent(t)}`;n.debug("Trying with image proxy service:",o),r.src=o,r.onload=()=>{n.debug("External image loaded successfully via proxy:",o),e.remove(),r.addClass("loaded")},r.onerror=l=>{n.error("All attempts to load image failed:",t,l),e.setText("Image not found - URL: "+t);try{let d=document.createElement("img");d.style.display="none",d.src=t,document.body.appendChild(d),setTimeout(()=>{document.body.contains(d)&&document.body.removeChild(d)},3e3)}catch(d){n.error("Error during final test:",d)}}}}}addPropertyToCard(s,e,t,r){n.debug(`Adding property to card: ${e} = ${t}`),n.debug(`Property type: ${typeof t}`);let i=s.createEl("div",{cls:"datacards-property"});r.propertiesAlign&&i.addClass(`datacards-text-${r.propertiesAlign}`);let a=e;if(r.columnAliases){let o=r.columnAliases.find(l=>l.original===e);o&&(a=o.alias,n.debug(`Using alias "${a}" for property "${e}"`))}if(r.showLabels){let o=i.createEl("div",{cls:"datacards-property-label",text:a});r.propertiesAlign&&o.addClass(`datacards-text-${r.propertiesAlign}`)}if(e.toLowerCase()==="file")this.formatFileProperty(i,t);else{let o=r.propertyFormatters[e];o?this.formatPropertyWithCustomFormatter(i,t,o):this.formatPropertyByType(i,t)}}formatPropertyWithCustomFormatter(s,e,t){let r=s.createEl("div",{cls:"datacards-property-value"});switch(t.type){case"stars":this.formatAsStars(r,e,t.options);break;case"badge":this.formatAsBadge(r,e,t.options);break;case"progress":this.formatAsProgress(r,e,t.options);break;case"date":this.formatAsDate(r,e,t.options);break;case"tags":this.formatAsTags(r,e,t.options);break;default:r.setText(String(e))}}formatPropertyByType(s,e){n.debug("formatPropertyByType called with value:",e),n.debug("Value type:",typeof e),typeof e=="string"&&(n.debug("String value length:",e.length),n.debug("String value exact content:",JSON.stringify(e)));let t=s.createEl("div",{cls:"datacards-property-value"});if(s.hasClass("datacards-text-left")?t.addClass("datacards-text-left"):s.hasClass("datacards-text-center")?t.addClass("datacards-text-center"):s.hasClass("datacards-text-right")&&t.addClass("datacards-text-right"),e==null)t.setText("");else if(Array.isArray(e))t.setText(e.join(", "));else if(typeof e=="boolean"){let r=t.createEl("input",{attr:{type:"checkbox",checked:e?"checked":"",disabled:"disabled"}})}else if(typeof e=="number")t.setText(e.toString());else if(e instanceof Date)this.formatAsDate(t,e);else if(typeof e=="string"){if(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}[+-]\d{2}:\d{2}$/.test(e)||/^\d{4}-\d{2}-\d{2}$/.test(e)){let o=new Date(e);if(!isNaN(o.getTime())){this.formatAsDate(t,o);return}}let i=this.extractImageSource(e);if(i!==e){this.formatPropertyByType(s,i);return}if(typeof e=="string"&&e.includes("[[")&&e.includes("|")&&e.includes("]]")){let o=e.match(/\[\[.*\|(.*?)\]\]/);if(o&&o[1]){t.setText(o[1]);return}}if(e.includes("[[")&&e.includes("]]")){console.log("DATACARDS DEBUG: Found wiki link in property value:",e),n.debug("Found wiki link in property value:",e);let o=/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/,l=e.match(o);if(l){console.log("DATACARDS DEBUG: Wiki link match:",l),n.debug("Wiki link match:",l);let d=l[1],c=l[2]||this.getCleanFilename(d);console.log(`DATACARDS DEBUG: Wiki link path: "${d}", display text: "${c}"`),n.debug(`Wiki link path: "${d}", display text: "${c}"`),console.log("DATACARDS DEBUG: Creating link element for wiki link");let g=t.createEl("a",{cls:"internal-link datacards-file-link",text:c,attr:{href:d,"data-href":d,"data-type":"link"}});console.log("DATACARDS DEBUG: Link element created:",g),this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:g,targetEl:g,linktext:d});return}}let a=e.match(/!\[(.*?)\]\((.*?)\)/);if(a){n.debug("Found markdown image in property value");let o=a[2],l=a[1];t.addClass("loading");let d=t.createEl("img",{cls:"datacards-property-image loading",attr:{src:o,alt:l||"Image",crossorigin:"anonymous"}});d.onload=()=>{n.debug("Property image loaded successfully:",o),d.removeClass("loading")},d.onerror=()=>{n.error("Failed to load property image:",o),d.remove(),t.removeClass("loading"),t.addClass("image-error"),t.setText("Image not found: "+o)};return}if(e.startsWith("[[")&&e.endsWith("]]")){console.log("DATACARDS DEBUG: Processing wiki link that starts and ends with [[]]:",e),n.debug("Processing wiki link that starts and ends with [[]]:",e);let o=/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/,l=e.match(o);if(l){let d=l[1],c=l[2]||this.getCleanFilename(d);console.log(`DATACARDS DEBUG: Wiki link path: "${d}", display text: "${c}"`),n.debug(`Wiki link path: "${d}", display text: "${c}"`),console.log("DATACARDS DEBUG: Creating link element for wiki link (direct match)");let g=t.createEl("a",{cls:"internal-link datacards-file-link",text:c,attr:{href:d,"data-href":d,"data-type":"link"}});console.log("DATACARDS DEBUG: Link element created (direct match):",g),this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:g,targetEl:g,linktext:d})}else{let d=e.substring(2,e.length-2),c=d,g=d;if(d.includes("|")){let x=d.split("|");g=x[0],c=x[1]}else c=this.getCleanFilename(g);n.debug(`Fallback wiki link path: "${g}", display text: "${c}"`);let p=t.createEl("a",{cls:"internal-link datacards-file-link",text:c,attr:{href:g,"data-href":g,"data-type":"link"}});this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:p,targetEl:p,linktext:g})}}else if(e.startsWith("#")){let o=t.createEl("a",{cls:"datacards-tag tag-link",text:e,attr:{href:e,"data-href":e,"data-type":"tag"}})}else/<[ubia]>|<\/[ubia]>||<\/p>|
|
/.test(e)?(console.log("DATACARDS DEBUG: Rendering HTML content:",e),t.innerHTML=e):t.setText(e)}else if(typeof e=="object"&&e!==null){if("path"in e&&"type"in e&&e.type==="file"){console.log("Handling Dataview Link object:",e);let r=e.path,i=e.display||this.getCleanFilename(r);console.log(`Creating link from Dataview Link object: path="${r}", display="${i}"`);let a=t.createEl("a",{cls:"internal-link",text:i,attr:{href:r,"data-href":r,"data-type":"link"}});this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:a,targetEl:a,linktext:r});return}if("ts"in e&&typeof e.ts=="number"){let r=new Date(e.ts);if(!isNaN(r.getTime())){this.formatAsDate(t,r);return}}t.setText(String(e))}else t.setText(String(e))}formatAsStars(s,e,t){let r=(t==null?void 0:t.max)||5,i="\u2605",a="\u2606",o=s.createEl("div",{cls:"datacards-stars"}),l=Math.min(Math.max(0,e),r);for(let d=0;d{let o=a.startsWith("#")?a:`#${a}`,l=r.createEl("a",{cls:"datacards-tag tag-link",text:o,attr:{href:o,"data-href":o,"data-type":"tag"}})})}shouldUseScrollableProperties(s){let e=!1;return(s.preset==="square"||s.preset==="compact")&&(e=!0),this.pluginSettings.scrollableProperties!==void 0&&(e=this.pluginSettings.scrollableProperties),this.isMobileDevice()&&this.pluginSettings.mobileScrollableProperties!==void 0&&(e=this.pluginSettings.mobileScrollableProperties),s.scrollableProperties!==void 0&&(e=s.scrollableProperties),e}getContentHeight(s){let e="200px";return this.pluginSettings.contentHeight&&(e=this.pluginSettings.contentHeight),this.isMobileDevice()&&this.pluginSettings.mobileContentHeight&&(e=this.pluginSettings.mobileContentHeight),s.contentHeight&&(e=s.contentHeight),e}};var S=class{constructor(s){this.plugin=s}isDataviewEnabled(){return this.plugin.app.plugins.plugins.dataview!==void 0}getDataviewApi(){return this.isDataviewEnabled()?this.plugin.app.plugins.plugins.dataview.api:null}async executeQuery(s,e,t){let r=this.getDataviewApi();if(!r)return null;try{return await r.query(s,e,t)}catch(i){throw n.error("Error executing Dataview query:",i),i}}async waitForDataviewReady(){let s=this.getDataviewApi();return s?s.index&&s.index.initialized?(n.debug("Dataview index is already initialized"),!0):(n.debug("Waiting for Dataview index to be ready..."),new Promise(e=>{let t=this.plugin.app,r=t.metadataCache.on("dataview:index-ready",()=>{n.debug("Dataview index is now ready"),t.metadataCache.offref(r),e(!0)});setTimeout(()=>{n.warn("Timed out waiting for Dataview index"),t.metadataCache.offref(r),e(!1)},5e3)})):!1}async executeSafeQuery(s,e,t,r=0){let i=this.getDataviewApi();if(!i)return n.error("Dataview API not found. Make sure Dataview plugin is enabled."),{successful:!1,value:"Dataview plugin is not enabled"};if(!s||s.trim()==="")return n.error("Empty Dataview query"),{successful:!1,value:"Empty query"};n.debug("Executing Dataview query:",s),n.debug("Source path:",e);try{if(typeof i.query=="function"){n.debug("Using api.query method");try{let a=await i.query(s,e,t);return n.debug("Direct query result type:",typeof a),a==null?(n.error("Direct query returned undefined or null"),{successful:!1,value:"No results returned"}):(a&&typeof a=="object"&&("values"in a&&Array.isArray(a.values)&&n.debug("Result contains a values array with length:",a.values.length),"headers"in a&&Array.isArray(a.headers)&&n.debug("Result contains headers:",a.headers)),a&&typeof a=="object"&&"values"in a&&Array.isArray(a.values)&&a.values.length===0&&r<3?(n.debug(`Empty result, retrying (attempt ${r+1}/3)...`),new Promise(o=>{setTimeout(async()=>{let l=await this.executeSafeQuery(s,e,t,r+1);o(l)},500)})):{successful:!0,value:a})}catch(a){return n.error("Error in direct query:",a),{successful:!1,value:a?a.message||String(a):"Error in query execution"}}}else return n.error("Dataview API query method not found."),{successful:!1,value:"Incompatible Dataview API version"}}catch(a){return n.error("Error executing Dataview query:",a),{successful:!1,value:a?a.message||String(a):"Unknown error"}}}};var k=class extends b.Plugin{async onload(){await this.loadSettings(),n.setDebugMode(this.settings.debugMode),this.parserService=new D,this.rendererService=new C(this.app,this.settings),this.dataviewApiUtil=new S(this),this.registerMarkdownCodeBlockProcessor("datacards",this.processDataCardsBlock.bind(this)),this.addSettingTab(new E(this.app,this)),this.addCommand({id:"refresh-datacards",name:"Refresh all DataCards",callback:()=>{this.refreshAllDataCards()}}),n.debug("DataCards plugin loaded")}onunload(){n.debug("DataCards plugin unloaded")}async loadSettings(){this.settings=Object.assign({},v,await this.loadData())}async saveSettings(){await this.saveData(this.settings),n.setDebugMode(this.settings.debugMode),this.rendererService.updateSettings(this.settings),this.refreshAllDataCards()}async processDataCardsBlock(e,t,r){if(n.debug("Processing DataCards block"),!this.dataviewApiUtil.isDataviewEnabled()){n.error("Dataview plugin is not enabled"),t.createEl("div",{cls:"datacards-error",text:"Dataview plugin is required but not enabled"});return}await this.dataviewApiUtil.waitForDataviewReady()||n.warn("Timed out waiting for Dataview to be ready");try{let{query:a,settings:o}=this.parserService.parseDataCardsBlock(e);n.debug("Parsed query:",a),n.debug("Parsed settings:",o);let l=r.sourcePath,d=document.createElement("div");d.style.display="none",document.body.appendChild(d);try{n.debug("Executing Dataview query");let c=await this.dataviewApiUtil.executeSafeQuery(a,l,d);if(document.body.removeChild(d),!c){n.error("Result is undefined or null"),t.createEl("div",{cls:"datacards-error",text:"Error executing Dataview query: undefined result"});return}if(!c.successful){let p=`Error executing Dataview query: ${c.value||"unknown error"}`;n.error(p),t.createEl("div",{cls:"datacards-error",text:p});return}if(c.value&&typeof c.value=="object"&&"successful"in c.value&&c.value.successful===!1){let p=`Error executing Dataview query: ${c.value.error||"unknown error"}`;n.error(p),t.createEl("div",{cls:"datacards-error",text:p});return}if(c.value===void 0||c.value===null){n.error("Dataview returned null or undefined value"),t.createEl("div",{cls:"datacards-error",text:"Dataview returned no results. Make sure your query is correct and returns data."});return}if(Array.isArray(c.value)&&c.value.length===0){n.debug("Dataview returned empty array"),t.createEl("div",{cls:"datacards-info",text:"No files match your query criteria."});return}if(c.value.values&&Array.isArray(c.value.values)&&c.value.values.length===0){n.debug("Dataview returned empty table"),t.createEl("div",{cls:"datacards-info",text:"No files match your query criteria."});return}let g=c.value;g&&typeof g=="object"&&"successful"in g&&"value"in g&&(n.debug("Unwrapping nested result structure"),g=g.value),this.rendererService.renderCards(t,g,o)}catch(c){n.error("Error executing Dataview query:",c),document.body.contains(d)&&document.body.removeChild(d),t.createEl("div",{cls:"datacards-error",text:`Error executing Dataview query: ${c.message||String(c)}`})}}catch(a){n.error("DataCards error:",a),t.createEl("div",{cls:"datacards-error",text:`Error processing DataCards block: ${a.message||String(a)}`})}}refreshAllDataCards(){let e=this.app.workspace.getActiveViewOfType(b.MarkdownView);e?(e.previewMode.rerender(!0),new b.Notice("DataCards refreshed",3e3)):new b.Notice("No active markdown view to refresh",3e3)}}; + `}};var s=class{static setDebugMode(n){this.debugMode=n}static error(n,...e){console.error(`[DataCards] ${n}`,...e)}static warn(n,...e){console.warn(`[DataCards] ${n}`,...e)}static debug(n,...e){this.debugMode&&console.log(`[DataCards] ${n}`,...e)}};s.debugMode=!1;var S=class{parseDataCardsBlock(n){s.debug("Parsing datacards block");let e=/\n-{3,}\n|\n\/\/\s*Settings.*|\n\/\*\s*Settings\s*\*\/.*/,t=n.match(e),a=/^\/\/\s*Settings.*/,r=n.match(a),i,o;t&&t.index!==void 0?(s.debug("Found settings separator at index:",t.index),i=n.substring(0,t.index).trim(),o=n.substring(t.index+t[0].length).trim()):r?(s.debug("Block starts with settings marker"),i="",o=n.substring(r[0].length).trim()):(s.debug("No settings separator found"),i=n.trim(),o=""),s.debug("Extracted query:",i),i=this.ensureQueryType(i);let l=this.parseSettings(o),d=this.extractColumnAliases(i);return d.length>0&&(l.columnAliases=d,s.debug("Extracted column aliases:",d)),{query:i,settings:l}}extractColumnAliases(n){let e=[];if(!n.trim().toUpperCase().startsWith("TABLE"))return e;try{let t=n.match(/TABLE\s+(without\s+id\s+)?([\s\S]*?)(?:\s+FROM|\s+WHERE|\s+SORT|\s+GROUP BY|\s+LIMIT|\s+FLATTEN|$)/i);if(!t||!t[2])return e;let a=t[2].trim();if(s.debug("Extracted columns text:",a),!a)return e;let r=this.splitColumnsPreservingExpressions(a);for(let i of r){let o=i.match(/^(.*?)\s+as\s+(?:"([^"]+)"|'([^']+)'|([^\s,]+))$/i);if(o){let l=o[1].trim(),d=o[2]||o[3]||o[4],c=l;if(/^[a-zA-Z0-9_.-]+$/.test(l))c=l;else{let g=l.match(/\(\s*".*?"\s*\+\s*([a-zA-Z0-9_.-]+)\s*\+\s*".*?"\s*\)/);g&&g[1]&&(c=g[1],s.debug(`Extracted field name from complex expression: ${c}`))}e.push({original:c,alias:d,expression:l}),s.debug(`Found column alias: ${c} as "${d}"`)}}}catch(t){s.error("Error extracting column aliases:",t)}return e}splitColumnsPreservingExpressions(n){let e=[],t="",a=0,r=!1,i=!1;for(let o=0;o=0){let r=this.parseSettings(t.slice(a+1).join(` +`)),i="",o=[];return r.imageProperty&&o.push(r.imageProperty),i="",s.debug("Using simple TABLE query without property list"),i.trim()===""?t[a]="TABLE "+t[a]:t[a]="TABLE"+i+" "+t[a],t.join(` +`)}else return"TABLE "+n}return n}parseSettings(n){if(!n)return{};let e={},t=n.split(` +`);s.debug("Parsing settings from text");for(let a of t){if(a.trim().startsWith("//")||a.trim().startsWith("/*")||!a.trim())continue;let r=a.match(/^\s*([a-zA-Z0-9_]+)\s*:\s*(.+)\s*$/);if(r){let[,i,o]=r;if(s.debug(`Found setting: ${i} = ${o}`),i==="properties"&&o.trim().startsWith("[")&&o.trim().endsWith("]")){s.debug("Detected properties array");let l=o.substring(1,o.length-1).trim();if(l){let d=l.split(",").map(c=>c.trim());e[i]=d}else e[i]=[]}else i==="defaultDateFormat"?e[i]=o.trim():e[i]=this.parseValue(o.trim())}}return e}parseValue(n){s.debug("Parsing value:",n);try{return JSON.parse(n)}catch(e){}if(n.startsWith("[")&&n.endsWith("]")){s.debug("Detected array syntax");let e=n.substring(1,n.length-1).trim();return e?e.split(",").map(a=>a.trim()):[]}return/^-?\d+(\.\d+)?$/.test(n)?Number(n):n.toLowerCase()==="true"?!0:n.toLowerCase()==="false"?!1:n}};var F=require("obsidian");var D=class{constructor(n,e){this.currentSettings=null;this.app=n,this.pluginSettings=e}updateSettings(n){this.pluginSettings=n}isMobileDevice(){return F.Platform.isMobile||this.pluginSettings.forceMobileMode}renderCards(n,e,t){let a=this.isMobileDevice();s.debug("Is mobile device:",a);let r={...this.pluginSettings};s.debug("Initial settings from plugin:",{preset:r.preset,imageHeight:r.imageHeight,mobileColumns:r.mobileColumns,mobilePreset:r.mobilePreset,mobileImageHeight:r.mobileImageHeight}),r={...r,...t},s.debug("After applying block settings:",{preset:r.preset,imageHeight:r.imageHeight,mobileColumns:r.mobileColumns,mobilePreset:r.mobilePreset,mobileImageHeight:r.mobileImageHeight}),a&&(s.debug("Applying mobile settings..."),s.debug(`Using mobile columns: ${r.mobileColumns}`),r.mobilePreset!==void 0&&(s.debug(`Overriding preset: ${r.preset} with mobilePreset: ${r.mobilePreset}`),r.preset=r.mobilePreset),r.mobileImageHeight!==void 0&&(s.debug(`Overriding imageHeight: ${r.imageHeight} with mobileImageHeight: ${r.mobileImageHeight}`),r.imageHeight=r.mobileImageHeight),s.debug("Final settings after applying mobile settings:",{preset:r.preset,imageHeight:r.imageHeight})),this.currentSettings=r;let i=n.createEl("div",{cls:"datacards-container"});i.addClass(`datacards-preset-${r.preset}`),r.enableShadows||i.addClass("datacards-no-shadows"),r.fontSize&&r.fontSize!=="default"?(i.addClass(`datacards-font-${r.fontSize}`),s.debug(`Applied font size class: datacards-font-${r.fontSize}`)):r.preset==="dense"&&(!r.fontSize||r.fontSize==="default")&&(i.addClass("datacards-font-small"),s.debug("Applied small font size for dense preset")),i.style.setProperty("--card-gap",`${r.cardSpacing}px`);let o;if(a)o=r.mobileColumns;else{let d=3;r.preset==="dense"?d=6:r.preset==="compact"||r.preset==="square"?d=4:r.preset==="portrait"&&(d=3),o=t.columns!==void 0?t.columns:d}s.debug(`Using ${o} columns`),i.style.setProperty("--card-columns",o.toString(),"important");let l;if(t.imageHeight!==void 0?l=r.imageHeight:r.preset==="portrait"?l="350px":r.preset==="square"||r.preset==="compact"?l="200px":r.preset==="dense"?l="120px":l="200px",(typeof l=="number"||/^\d+$/.test(l))&&(l=`${l}px`),i.style.setProperty("--image-height",l),t.imageFit!==void 0)i.style.setProperty("--image-fit",r.imageFit);else{let d=r.preset==="portrait"?"contain":"cover";i.style.setProperty("--image-fit",d)}e&&e.values&&Array.isArray(e.values)?(s.debug("Detected table-like results with values array"),this.renderTableResults(i,e,r)):e&&Array.isArray(e)?(s.debug("Detected array results"),this.renderArrayResults(i,e,r)):e&&typeof e=="object"?(s.debug("Detected object results"),this.renderObjectResults(i,e,r)):(s.debug("No valid results detected"),this.renderError(i,"No results or unsupported result type"))}renderError(n,e){let t=n.createEl("div",{cls:"datacards-error",text:e})}renderTableResults(n,e,t){let{values:a,headers:r}=e;s.debug("Rendering table results:"),s.debug("- Headers:",r),s.debug("- Number of rows:",a.length),a.forEach((i,o)=>{s.debug(`Processing row ${o}`);let l=this.createCardElement(n);if(t.imageProperty&&r.includes(t.imageProperty)){let u=r.indexOf(t.imageProperty),y=i[u];s.debug(`Image property '${t.imageProperty}' value:`,y),y&&this.addImageToCard(l,y)}else t.imageProperty&&s.debug(`Image property '${t.imageProperty}' not found in headers:`,r);let d=l.createEl("div",{cls:"datacards-content"});if(r.includes("File")||r.includes("file")){let u=r.findIndex(y=>y.toLowerCase()==="file");if(u>=0){let y=i[u];s.debug("File property value:",y);let f=d.createEl("div",{cls:"datacards-property datacards-file-property-container"});this.formatFileProperty(f,y)}}let c=d.createEl("div",{cls:"datacards-properties-container"});if(this.shouldUseScrollableProperties(t)){c.addClass("datacards-scrollable-properties");let u=this.getContentHeight(t);c.style.setProperty("--content-height",u)}let p=[];t.properties==="all"?(p=[...r],s.debug("Using all headers as properties:",p)):Array.isArray(t.properties)?(p=[...t.properties],s.debug("Using specified properties:",p)):s.debug("No properties specified, using empty array");let x=p.filter(u=>!t.exclude.includes(u)&&u!==t.imageProperty&&u.toLowerCase()!=="file");s.debug("Filtered properties (after excluding file):",x),x.forEach(u=>{if(s.debug(`Checking property '${u}' in headers:`,r.includes(u)),r.includes(u)){let y=r.indexOf(u),f=i[y];if(console.log(`Property '${u}' value:`,f),console.log(`Property '${u}' type:`,typeof f),typeof f=="string"&&f.includes("[[")&&f.includes("]]")){console.log(`Found wiki link in property '${u}':`,f);let P=c.createEl("div",{cls:"datacards-property"});t.showLabels&&P.createEl("div",{cls:"datacards-property-label",text:u});let M=P.createEl("div",{cls:"datacards-property-value"}),T=f.match(/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/);if(T){let w=T[1],L=T[2]||this.getCleanFilename(w);console.log(`Creating direct link for wiki link: path="${w}", display="${L}"`);let H=M.createEl("a",{cls:"internal-link",text:L,attr:{href:w,"data-href":w,"data-type":"link"}});this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:H,targetEl:H,linktext:w})}else M.setText(f)}else this.addPropertyToCard(c,u,f,t)}else s.debug(`Property '${u}' not found in headers`)}),x.length===0&&!r.some(u=>u.toLowerCase()==="file")&&(s.debug("No properties were added to the card"),d.createEl("div",{cls:"datacards-property",text:"No properties to display"}))})}renderArrayResults(n,e,t){e.forEach(a=>{let r=this.createCardElement(n);t.imageProperty&&a[t.imageProperty]&&this.addImageToCard(r,a[t.imageProperty]);let i=r.createEl("div",{cls:"datacards-content"});if("file"in a){let p=i.createEl("div",{cls:"datacards-property datacards-file-property-container"});this.formatFileProperty(p,a.file)}let o=i.createEl("div",{cls:"datacards-properties-container"});if(this.shouldUseScrollableProperties(t)){o.addClass("datacards-scrollable-properties");let p=this.getContentHeight(t);o.style.setProperty("--content-height",p)}let d=Object.keys(a);(t.properties==="all"?d:Array.isArray(t.properties)?t.properties:[]).filter(p=>!t.exclude.includes(p)&&p!==t.imageProperty&&p.toLowerCase()!=="file").forEach(p=>{p in a&&this.addPropertyToCard(o,p,a[p],t)})})}renderObjectResults(n,e,t){let a=this.createCardElement(n);t.imageProperty&&e[t.imageProperty]&&this.addImageToCard(a,e[t.imageProperty]);let r=a.createEl("div",{cls:"datacards-content"});if("file"in e){let g=r.createEl("div",{cls:"datacards-property datacards-file-property-container"});this.formatFileProperty(g,e.file)}let i=r.createEl("div",{cls:"datacards-properties-container"});if(this.shouldUseScrollableProperties(t)){i.addClass("datacards-scrollable-properties");let g=this.getContentHeight(t);i.style.setProperty("--content-height",g)}let l=Object.keys(e);(t.properties==="all"?l:Array.isArray(t.properties)?t.properties:[]).filter(g=>!t.exclude.includes(g)&&g!==t.imageProperty&&g.toLowerCase()!=="file").forEach(g=>{g in e&&this.addPropertyToCard(i,g,e[g],t)})}createCardElement(n){return n.createEl("div",{cls:"datacards-card"})}addImageToCard(n,e){var i;let t=n.createEl("div",{cls:"datacards-image-container"}),a;typeof e=="object"&&e!==null?(s.debug("Image value is an object:",e),"path"in e?(a=e.path,s.debug("Extracted path from Link object:",a)):(a=String(e),s.debug("Converted object to string:",a))):(a=String(e),s.debug("Image value is a string:",a)),a=this.extractImageSource(a),s.debug("After image source extraction:",a);let r=t.createEl("div",{cls:"datacards-image-placeholder",text:"Loading image..."});(i=this.currentSettings)!=null&&i.enableLazyLoading?this.lazyLoadImage(t,r,a):this.loadImage(t,r,a)}extractImageSource(n){if(!n||typeof n!="string")return String(n||"");let e=n.match(/!\[(.*?)\]\((.*?)\)/);if(e){let r=e[2];return s.debug("Extracted URL from markdown image syntax:",r),r.replace(/['",.;:]+$/,"")}let t=n.match(/\[\[(.*?)\]\]/);if(t){let r=`[[${t[1]}]]`;return s.debug("Extracted wiki link:",r),r}let a=n.match(/(https?:\/\/[^\s"'<>[\]{}]+)/);if(a){let r=a[1];return s.debug("Extracted URL:",r),r.replace(/['",.;:]+$/,"")}return n}lazyLoadImage(n,e,t){s.debug("Lazy loading image:",t),new IntersectionObserver((r,i)=>{r.forEach(o=>{o.isIntersecting&&(s.debug("Image container is now visible, loading image:",t),this.loadImage(n,e,t),i.disconnect())})},{rootMargin:"100px",threshold:.1}).observe(n)}loadImage(n,e,t){let a=t.match(/!\[(.*?)\]\((.*?)\)/);if(a){let r=a[2];s.debug("Extracted URL from markdown image syntax:",r),this.loadImage(n,e,r);return}if(t.startsWith("http")||t.startsWith("https")){s.debug("Handling as external URL:",t);let r=t.replace(/['",.;:]+$/,"");s.debug("Cleaned URL:",r),this.loadExternalImage(n,e,r)}else if(t.startsWith("[[")&&t.endsWith("]]")){s.debug("Handling as wiki link");let r=t.substring(2,t.length-2),i=r;r.includes("|")&&(i=r.split("|")[0]);try{let o=this.app.vault.getAbstractFileByPath(i);if(o&&"stat"in o){s.debug("Found file in vault:",o);let l=o,d=this.app.vault.getResourcePath(l);s.debug("Resource path:",d);let c=n.createEl("img",{cls:"datacards-image",attr:{src:d}});c.onload=()=>{e.remove(),c.addClass("loaded")},c.onerror=()=>{e.setText("Image not found")}}else s.debug("File not found in vault or not a file:",i),e.setText("Image not found")}catch(o){s.error("Error loading image:",o),e.setText("Error loading image")}}else{s.debug("Handling as local path");try{let r=this.app.vault.getAbstractFileByPath(t);if(r&&"stat"in r){s.debug("Found file in vault:",r);let i=r,o=this.app.vault.getResourcePath(i);s.debug("Resource path:",o);let l=n.createEl("img",{cls:"datacards-image",attr:{src:o}});l.onload=()=>{e.remove(),l.addClass("loaded")},l.onerror=()=>{e.setText("Image not found")}}else s.debug("File not found in vault:",t),e.setText("Image not found")}catch(r){s.error("Error loading image:",r),e.setText("Error loading image")}}}loadExternalImage(n,e,t){s.debug("Loading external image with URL:",t);let a=n.createEl("img",{cls:"datacards-image",attr:{src:t,crossorigin:"anonymous"}});a.onload=()=>{s.debug("External image loaded successfully:",t),e.remove(),a.addClass("loaded")},a.onerror=r=>{s.error("Failed to load external image with crossorigin attribute:",t,r),s.debug("Trying again without crossorigin attribute"),a.removeAttribute("crossorigin"),a.onload=()=>{s.debug("External image loaded successfully without crossorigin:",t),e.remove(),a.addClass("loaded")},a.onerror=i=>{s.error("Failed to load external image without crossorigin:",t,i);let o=`https://images.weserv.nl/?url=${encodeURIComponent(t)}`;s.debug("Trying with image proxy service:",o),a.src=o,a.onload=()=>{s.debug("External image loaded successfully via proxy:",o),e.remove(),a.addClass("loaded")},a.onerror=l=>{s.error("All attempts to load image failed:",t,l),e.setText("Image not found - URL: "+t);try{let d=document.createElement("img");d.style.display="none",d.src=t,document.body.appendChild(d),setTimeout(()=>{document.body.contains(d)&&document.body.removeChild(d)},3e3)}catch(d){s.error("Error during final test:",d)}}}}}addPropertyToCard(n,e,t,a){s.debug(`Adding property to card: ${e} = ${t}`),s.debug(`Property type: ${typeof t}`);let r=n.createEl("div",{cls:"datacards-property"});a.propertiesAlign&&r.addClass(`datacards-text-${a.propertiesAlign}`);let i=e;if(a.columnAliases){let o=a.columnAliases.find(l=>l.original===e);o&&(i=o.alias,s.debug(`Using alias "${i}" for property "${e}"`))}if(a.showLabels){let o=r.createEl("div",{cls:"datacards-property-label",text:i});a.propertiesAlign&&o.addClass(`datacards-text-${a.propertiesAlign}`)}if(e.toLowerCase()==="file")this.formatFileProperty(r,t);else{let o=a.propertyFormatters[e];o?this.formatPropertyWithCustomFormatter(r,t,o):this.formatPropertyByType(r,t)}}formatPropertyWithCustomFormatter(n,e,t){let a=n.createEl("div",{cls:"datacards-property-value"});switch(t.type){case"stars":this.formatAsStars(a,e,t.options);break;case"badge":this.formatAsBadge(a,e,t.options);break;case"progress":this.formatAsProgress(a,e,t.options);break;case"date":this.formatAsDate(a,e,t.options);break;case"tags":this.formatAsTags(a,e,t.options);break;default:a.setText(String(e))}}formatPropertyByType(n,e){s.debug("formatPropertyByType called with value:",e),s.debug("Value type:",typeof e),typeof e=="string"&&(s.debug("String value length:",e.length),s.debug("String value exact content:",JSON.stringify(e)));let t=n.createEl("div",{cls:"datacards-property-value"});if(n.hasClass("datacards-text-left")?t.addClass("datacards-text-left"):n.hasClass("datacards-text-center")?t.addClass("datacards-text-center"):n.hasClass("datacards-text-right")&&t.addClass("datacards-text-right"),e==null)t.setText("");else if(Array.isArray(e))t.setText(e.join(", "));else if(typeof e=="boolean"){let a=t.createEl("input",{attr:{type:"checkbox",checked:e?"checked":"",disabled:"disabled"}})}else if(typeof e=="number")t.setText(e.toString());else if(e instanceof Date)this.formatAsDate(t,e);else if(typeof e=="string"){if(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}[+-]\d{2}:\d{2}$/.test(e)||/^\d{4}-\d{2}-\d{2}$/.test(e)){let o=new Date(e);if(!isNaN(o.getTime())){this.formatAsDate(t,o);return}}let r=this.extractImageSource(e);if(r!==e){this.formatPropertyByType(n,r);return}if(typeof e=="string"&&e.includes("[[")&&e.includes("|")&&e.includes("]]")){let o=e.match(/\[\[.*\|(.*?)\]\]/);if(o&&o[1]){t.setText(o[1]);return}}if(e.includes("[[")&&e.includes("]]")){console.log("DATACARDS DEBUG: Found wiki link in property value:",e),s.debug("Found wiki link in property value:",e);let o=/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/,l=e.match(o);if(l){console.log("DATACARDS DEBUG: Wiki link match:",l),s.debug("Wiki link match:",l);let d=l[1],c=l[2]||this.getCleanFilename(d);console.log(`DATACARDS DEBUG: Wiki link path: "${d}", display text: "${c}"`),s.debug(`Wiki link path: "${d}", display text: "${c}"`),console.log("DATACARDS DEBUG: Creating link element for wiki link");let g=t.createEl("a",{cls:"internal-link datacards-file-link",text:c,attr:{href:d,"data-href":d,"data-type":"link"}});console.log("DATACARDS DEBUG: Link element created:",g),this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:g,targetEl:g,linktext:d});return}}let i=e.match(/!\[(.*?)\]\((.*?)\)/);if(i){s.debug("Found markdown image in property value");let o=i[2],l=i[1];t.addClass("loading");let d=t.createEl("img",{cls:"datacards-property-image loading",attr:{src:o,alt:l||"Image",crossorigin:"anonymous"}});d.onload=()=>{s.debug("Property image loaded successfully:",o),d.removeClass("loading")},d.onerror=()=>{s.error("Failed to load property image:",o),d.remove(),t.removeClass("loading"),t.addClass("image-error"),t.setText("Image not found: "+o)};return}if(e.startsWith("[[")&&e.endsWith("]]")){console.log("DATACARDS DEBUG: Processing wiki link that starts and ends with [[]]:",e),s.debug("Processing wiki link that starts and ends with [[]]:",e);let o=/\[\[([^\]|]+)(?:\|([^\]]+))?\]\]/,l=e.match(o);if(l){let d=l[1],c=l[2]||this.getCleanFilename(d);console.log(`DATACARDS DEBUG: Wiki link path: "${d}", display text: "${c}"`),s.debug(`Wiki link path: "${d}", display text: "${c}"`),console.log("DATACARDS DEBUG: Creating link element for wiki link (direct match)");let g=t.createEl("a",{cls:"internal-link datacards-file-link",text:c,attr:{href:d,"data-href":d,"data-type":"link"}});console.log("DATACARDS DEBUG: Link element created (direct match):",g),this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:g,targetEl:g,linktext:d})}else{let d=e.substring(2,e.length-2),c=d,g=d;if(d.includes("|")){let x=d.split("|");g=x[0],c=x[1]}else c=this.getCleanFilename(g);s.debug(`Fallback wiki link path: "${g}", display text: "${c}"`);let p=t.createEl("a",{cls:"internal-link datacards-file-link",text:c,attr:{href:g,"data-href":g,"data-type":"link"}});this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:p,targetEl:p,linktext:g})}}else if(e.startsWith("#")){let o=t.createEl("a",{cls:"datacards-tag tag-link",text:e,attr:{href:e,"data-href":e,"data-type":"tag"}})}else/<[ubia]>|<\/[ubia]>||<\/p>|
|
/.test(e)?(console.log("DATACARDS DEBUG: Rendering HTML content:",e),t.innerHTML=e):t.setText(e)}else if(typeof e=="object"&&e!==null){if("path"in e&&"type"in e&&e.type==="file"){console.log("Handling Dataview Link object:",e);let a=e.path,r=e.display||this.getCleanFilename(a);console.log(`Creating link from Dataview Link object: path="${a}", display="${r}"`);let i=t.createEl("a",{cls:"internal-link",text:r,attr:{href:a,"data-href":a,"data-type":"link"}});this.app.workspace.trigger("hover-link",{event:new MouseEvent("mouseover"),source:"preview",hoverEl:i,targetEl:i,linktext:a});return}if("ts"in e&&typeof e.ts=="number"){let a=new Date(e.ts);if(!isNaN(a.getTime())){this.formatAsDate(t,a);return}}t.setText(String(e))}else t.setText(String(e))}formatAsStars(n,e,t){let a=(t==null?void 0:t.max)||5,r="\u2605",i="\u2606",o=n.createEl("div",{cls:"datacards-stars"}),l=Math.min(Math.max(0,e),a);for(let d=0;d{let o=i.startsWith("#")?i:`#${i}`,l=a.createEl("a",{cls:"datacards-tag tag-link",text:o,attr:{href:o,"data-href":o,"data-type":"tag"}})})}shouldUseScrollableProperties(n){let e=!1;return(n.preset==="square"||n.preset==="compact")&&(e=!0),this.pluginSettings.scrollableProperties!==void 0&&(e=this.pluginSettings.scrollableProperties),this.isMobileDevice()&&this.pluginSettings.mobileScrollableProperties!==void 0&&(e=this.pluginSettings.mobileScrollableProperties),n.scrollableProperties!==void 0&&(e=n.scrollableProperties),e}getContentHeight(n){let e="200px";return this.pluginSettings.contentHeight&&(e=this.pluginSettings.contentHeight),this.isMobileDevice()&&this.pluginSettings.mobileContentHeight&&(e=this.pluginSettings.mobileContentHeight),n.contentHeight&&(e=n.contentHeight),e}};var C=class{constructor(n){this.plugin=n}isDataviewEnabled(){return this.plugin.app.plugins.plugins.dataview!==void 0}getDataviewApi(){return this.isDataviewEnabled()?this.plugin.app.plugins.plugins.dataview.api:null}async executeQuery(n,e,t){let a=this.getDataviewApi();if(!a)return null;try{return await a.query(n,e,t)}catch(r){throw s.error("Error executing Dataview query:",r),r}}async waitForDataviewReady(){let n=this.getDataviewApi();return n?n.index&&n.index.initialized?(s.debug("Dataview index is already initialized"),!0):(s.debug("Waiting for Dataview index to be ready..."),new Promise(e=>{let t=this.plugin.app,a=t.metadataCache.on("dataview:index-ready",()=>{s.debug("Dataview index is now ready"),t.metadataCache.offref(a),e(!0)});setTimeout(()=>{s.warn("Timed out waiting for Dataview index"),t.metadataCache.offref(a),e(!1)},5e3)})):!1}async executeSafeQuery(n,e,t,a=0){let r=this.getDataviewApi();if(!r)return s.error("Dataview API not found. Make sure Dataview plugin is enabled."),{successful:!1,value:"Dataview plugin is not enabled"};if(!n||n.trim()==="")return s.error("Empty Dataview query"),{successful:!1,value:"Empty query"};s.debug("Executing Dataview query:",n),s.debug("Source path:",e);try{if(typeof r.query=="function"){s.debug("Using api.query method");try{let i=await r.query(n,e,t);return s.debug("Direct query result type:",typeof i),i==null?(s.error("Direct query returned undefined or null"),{successful:!1,value:"No results returned"}):(i&&typeof i=="object"&&("values"in i&&Array.isArray(i.values)&&s.debug("Result contains a values array with length:",i.values.length),"headers"in i&&Array.isArray(i.headers)&&s.debug("Result contains headers:",i.headers)),i&&typeof i=="object"&&"values"in i&&Array.isArray(i.values)&&i.values.length===0&&a<3?(s.debug(`Empty result, retrying (attempt ${a+1}/3)...`),new Promise(o=>{setTimeout(async()=>{let l=await this.executeSafeQuery(n,e,t,a+1);o(l)},500)})):{successful:!0,value:i})}catch(i){return s.error("Error in direct query:",i),{successful:!1,value:i?i.message||String(i):"Error in query execution"}}}else return s.error("Dataview API query method not found."),{successful:!1,value:"Incompatible Dataview API version"}}catch(i){return s.error("Error executing Dataview query:",i),{successful:!1,value:i?i.message||String(i):"Unknown error"}}}};var k=class extends b.Plugin{async onload(){await this.loadSettings(),s.setDebugMode(this.settings.debugMode),this.parserService=new S,this.rendererService=new D(this.app,this.settings),this.dataviewApiUtil=new C(this),this.registerMarkdownCodeBlockProcessor("datacards",this.processDataCardsBlock.bind(this)),this.addSettingTab(new E(this.app,this)),this.addCommand({id:"refresh-datacards",name:"Refresh all DataCards",callback:()=>{this.refreshAllDataCards()}}),s.debug("DataCards plugin loaded")}onunload(){s.debug("DataCards plugin unloaded")}async loadSettings(){this.settings=Object.assign({},v,await this.loadData())}async saveSettings(){await this.saveData(this.settings),s.setDebugMode(this.settings.debugMode),this.rendererService.updateSettings(this.settings),this.refreshAllDataCards()}async processDataCardsBlock(e,t,a){if(s.debug("Processing DataCards block"),!this.dataviewApiUtil.isDataviewEnabled()){s.error("Dataview plugin is not enabled"),t.createEl("div",{cls:"datacards-error",text:"Dataview plugin is required but not enabled"});return}await this.dataviewApiUtil.waitForDataviewReady()||s.warn("Timed out waiting for Dataview to be ready");try{let{query:i,settings:o}=this.parserService.parseDataCardsBlock(e);s.debug("Parsed query:",i),s.debug("Parsed settings:",o);let l=a.sourcePath,d=document.createElement("div");d.style.display="none",document.body.appendChild(d);try{s.debug("Executing Dataview query");let c=await this.dataviewApiUtil.executeSafeQuery(i,l,d);if(document.body.removeChild(d),!c){s.error("Result is undefined or null"),t.createEl("div",{cls:"datacards-error",text:"Error executing Dataview query: undefined result"});return}if(!c.successful){let p=`Error executing Dataview query: ${c.value||"unknown error"}`;s.error(p),t.createEl("div",{cls:"datacards-error",text:p});return}if(c.value&&typeof c.value=="object"&&"successful"in c.value&&c.value.successful===!1){let p=`Error executing Dataview query: ${c.value.error||"unknown error"}`;s.error(p),t.createEl("div",{cls:"datacards-error",text:p});return}if(c.value===void 0||c.value===null){s.error("Dataview returned null or undefined value"),t.createEl("div",{cls:"datacards-error",text:"Dataview returned no results. Make sure your query is correct and returns data."});return}if(Array.isArray(c.value)&&c.value.length===0){s.debug("Dataview returned empty array"),t.createEl("div",{cls:"datacards-info",text:"No files match your query criteria."});return}if(c.value.values&&Array.isArray(c.value.values)&&c.value.values.length===0){s.debug("Dataview returned empty table"),t.createEl("div",{cls:"datacards-info",text:"No files match your query criteria."});return}let g=c.value;g&&typeof g=="object"&&"successful"in g&&"value"in g&&(s.debug("Unwrapping nested result structure"),g=g.value),this.rendererService.renderCards(t,g,o)}catch(c){s.error("Error executing Dataview query:",c),document.body.contains(d)&&document.body.removeChild(d),t.createEl("div",{cls:"datacards-error",text:`Error executing Dataview query: ${c.message||String(c)}`})}}catch(i){s.error("DataCards error:",i),t.createEl("div",{cls:"datacards-error",text:`Error processing DataCards block: ${i.message||String(i)}`})}}refreshAllDataCards(){let e=this.app.workspace.getActiveViewOfType(b.MarkdownView);e?(e.previewMode.rerender(!0),new b.Notice("DataCards refreshed",3e3)):new b.Notice("No active markdown view to refresh",3e3)}}; diff --git a/src/models/settings.ts b/src/models/settings.ts index 6c7f158..ec1b8e8 100644 --- a/src/models/settings.ts +++ b/src/models/settings.ts @@ -7,6 +7,11 @@ */ export type CardPreset = 'grid' | 'portrait' | 'square' | 'compact' | 'dense'; +/** + * Font size options + */ +export type FontSize = 'larger' | 'large' | 'default' | 'small' | 'smaller'; + /** * Image fitting options */ @@ -49,6 +54,7 @@ export interface DataCardsSettings { enableShadows: boolean; propertiesAlign: 'left' | 'center' | 'right'; // Alignment for properties and labels titleAlign: 'left' | 'center' | 'right'; // Alignment for the title (filename) + fontSize: FontSize; // Font size for all text elements // Formatting settings defaultDateFormat: string; @@ -98,6 +104,7 @@ export const DEFAULT_SETTINGS: DataCardsSettings = { enableShadows: true, propertiesAlign: 'left', // Default to left alignment titleAlign: 'left', // Default to left alignment + fontSize: 'default', // Default font size // Formatting settings defaultDateFormat: 'YYYY-MM-DD', diff --git a/src/services/renderer.ts b/src/services/renderer.ts index bdd6c79..2322559 100644 --- a/src/services/renderer.ts +++ b/src/services/renderer.ts @@ -108,6 +108,16 @@ export class RendererService { cardsContainer.addClass('datacards-no-shadows'); } + // Apply font size class if specified + if (settings.fontSize && settings.fontSize !== 'default') { + cardsContainer.addClass(`datacards-font-${settings.fontSize}`); + Logger.debug(`Applied font size class: datacards-font-${settings.fontSize}`); + } else if (settings.preset === 'dense' && (!settings.fontSize || settings.fontSize === 'default')) { + // For dense preset, automatically use small font size if not explicitly overridden + cardsContainer.addClass('datacards-font-small'); + Logger.debug('Applied small font size for dense preset'); + } + // Set only the non-preset specific CSS variables // This allows the preset class to control preset-specific variables cardsContainer.style.setProperty('--card-gap', `${settings.cardSpacing}px`); diff --git a/src/ui/settings-tab.ts b/src/ui/settings-tab.ts index fbd1145..503b9f3 100644 --- a/src/ui/settings-tab.ts +++ b/src/ui/settings-tab.ts @@ -118,6 +118,21 @@ export class DataCardsSettingTab extends PluginSettingTab { this.plugin.settings.titleAlign = value as any; await this.plugin.saveSettings(); })); + + new Setting(containerEl) + .setName('Font Size') + .setDesc('Text size for all card elements (properties, labels, and title)') + .addDropdown(dropdown => dropdown + .addOption('larger', 'Larger (120%)') + .addOption('large', 'Large (110%)') + .addOption('default', 'Default (100%)') + .addOption('small', 'Small (90% - similar to dense preset)') + .addOption('smaller', 'Smaller (80%)') + .setValue(this.plugin.settings.fontSize) + .onChange(async (value: string) => { + this.plugin.settings.fontSize = value as any; + await this.plugin.saveSettings(); + })); // Card Content Settings containerEl.createEl('h3', { text: 'Card Content Settings' }); diff --git a/styles.css b/styles.css index fa4491a..70e092c 100644 --- a/styles.css +++ b/styles.css @@ -317,6 +317,59 @@ a.datacards-tag:hover { text-decoration: none; } +/* Font size variations */ +/* Larger - 120% of default */ +.datacards-font-larger .datacards-property { + font-size: 1.2em; +} + +.datacards-font-larger .datacards-property-label { + font-size: 0.96em; +} + +.datacards-font-larger .datacards-file-property .internal-link { + font-size: 1.44em; +} + +/* Large - 110% of default */ +.datacards-font-large .datacards-property { + font-size: 1.1em; +} + +.datacards-font-large .datacards-property-label { + font-size: 0.88em; +} + +.datacards-font-large .datacards-file-property .internal-link { + font-size: 1.32em; +} + +/* Small - 90% of default (similar to dense preset) */ +.datacards-font-small .datacards-property { + font-size: 0.9em; +} + +.datacards-font-small .datacards-property-label { + font-size: 0.72em; +} + +.datacards-font-small .datacards-file-property .internal-link { + font-size: 1.08em; +} + +/* Smaller - 80% of default */ +.datacards-font-smaller .datacards-property { + font-size: 0.8em; +} + +.datacards-font-smaller .datacards-property-label { + font-size: 0.64em; +} + +.datacards-font-smaller .datacards-file-property .internal-link { + font-size: 0.96em; +} + .datacards-file-property .internal-link:hover { text-decoration: underline; } @@ -501,21 +554,12 @@ a.datacards-tag:hover { .datacards-preset-dense .datacards-property { margin-bottom: 4px; - font-size: 0.9em; -} - -.datacards-preset-dense .datacards-property-label { - font-size: 0.7em; } .datacards-preset-dense .datacards-file-property { margin-bottom: 6px; } -.datacards-preset-dense .datacards-file-property .internal-link { - font-size: 1em; -} - /* Responsive adjustments - these are now handled by the mobile settings in the plugin */ /* These media queries serve as fallbacks for blocks without explicit settings */ @media (max-width: 1200px) {