DatacoreJS & Supercharged Links: Coloring And Shorter Code

by Elias Adebayo 59 views

Hey guys! Today, we're diving into a common issue faced when using DatacoreJS with the Supercharged Links plugin: getting those awesome link colors to show up. We'll also explore how to write shorter DatacoreJS code, similar to Dataview's DQL. Let's get started!

The Problem: Supercharged Links Not Coloring in DatacoreJS

So, you've got this fantastic Supercharged Links plugin, which adds color and formatting to your Obsidian links, making your notes look super organized and visually appealing. You're also using DatacoreJS to create dynamic tables and lists. But, when you try to combine them, the Supercharged Links' coloring disappears! This can be frustrating, especially when you're used to seeing those visual cues that help you navigate your notes.

Understanding Why It Happens

The issue arises because DatacoreJS renders the links programmatically. The Supercharged Links plugin typically works by directly modifying the rendered HTML of your notes. When DatacoreJS generates the HTML for the links, it doesn't automatically trigger the Supercharged Links plugin to apply its magic. This is why you see plain, uncolored links in your DatacoreJS outputs. To fix this, we need to make sure the links generated by DatacoreJS are properly recognized by the Supercharged Links plugin.

The Code Example

Let's take a look at the code example provided to understand the problem better. The user has a Dataview query that displays recent notes with their creation and modification dates:

TABLE WITHOUT ID
file.link AS "Notizen",
dateformat(erstellt, "dd.MM.yyyy, HH:mm 'Uhr'") AS "Erstellt",
dateformat(geƤndert, "dd.MM.yyyy, HH:mm 'Uhr'") AS "Letzte Ƅnderung",
(date(now) - geƤndert) AS "das war vor"
WHERE 
geƤndert AND 
geƤndert >= (date(today) - dur(2 days))
SORT geƤndert DESC

This Dataview code works perfectly, and the links are colored as expected. However, when the user tries to replicate the same functionality using DatacoreJS, the Supercharged Links coloring is gone. The DatacoreJS code looks like this:

return function View() {
    const pages = dc.useQuery("@page and geƤndert");
    const now = new Date();

    // Nur Notizen mit Ƅnderung in den letzten 2 Tagen
    const recent = pages.filter(page => {
        const changed = new Date(page.value("geƤndert"));
        return !isNaN(changed) && (now - changed) <= 2 * 24 * 60 * 60 * 1000;
    });

    // Neueste zuerst
    recent.sort((a, b) =>
        new Date(b.value("geƤndert")) - new Date(a.value("geƤndert"))
    );

    function formatDate(dstr) {
        if (!dstr) return "";
        const d = new Date(dstr);
        const pad = n => n < 10 ? "0" + n : n;
        return `${pad(d.getDate())}.${pad(d.getMonth() + 1)}.${d.getFullYear()}, ${pad(d.getHours())}:${pad(d.getMinutes())} Uhr`;
    }

    function formatDiff(dateStr) {
        if (!dateStr) return "";
        let ms = now - new Date(dateStr);
        const d = Math.floor(ms / (1000 * 60 * 60 * 24)); ms -= d * 24 * 60 * 60 * 1000;
        const h = Math.floor(ms / (1000 * 60 * 60)); ms -= h * 60 * 60 * 1000;
        const m = Math.floor(ms / (1000 * 60)); ms -= m * 60 * 1000;
        const s = Math.floor(ms / 1000); ms -= s * 1000;
        let parts = [];
        if (d) parts.push(`${d} Tage`);
        if (h) parts.push(`${h} Stunden`);
        if (m) parts.push(`${m} Minuten`);
        parts.push(`${s} Sekunden und ${ms} Millisekunden`);
        return parts.join(', ');
    }

    function fileName(page) {
        const raw = page.file?.name || page.file?.path || page.$path || "";
        return raw.replace(/^.*[\\/]/, '').replace(/\.md$/i, '');
    }

    function filePath(page) {
        return page.file?.path || page.$path || "";
    }

    return (
      <div>
        <table>
          <thead>
            <tr>
              <th>Notizen ({recent.length})</th>
              <th>Erstellt</th>
              <th>Letzte Ƅnderung</th>
              <th>das war vor</th>
            </tr>
          </thead>
          <tbody>
            {recent.length === 0 ? (
              <tr>
                <td colSpan={4}><em>Keine Ƅnderungen in den letzten 2 Tagen</em></td>
              </tr>
            ) : recent.map(page => {
                const erstellt = page.value("erstellt");
                const geaendert = page.value("geƤndert");
                const name = fileName(page);
                const relPath = filePath(page);
                return (
                  <tr key={page.$path}>
                    <td>
                      <a
                        className="internal-link supercharged-link"
                        href={relPath}
                        data-href={name}
                      >
                        {name}
                      </a>
                    </td>
                    <td>{formatDate(erstellt)}</td>
                    <td>{formatDate(geaendert)}</td>
                    <td>{formatDiff(geaendert)}</td>
                  </tr>
                );
            })}
          </tbody>
        </table>
      </div>
    );
}

The Solution: Triggering Supercharged Links

To get the Supercharged Links plugin to color these links, you need to manually trigger its functionality after DatacoreJS renders the table. One way to do this is by using the MarkdownRenderer.render function provided by Obsidian. This function tells Obsidian to re-render a specific HTML element, allowing plugins like Supercharged Links to apply their modifications.

  1. Get the Table Element: First, you need to get a reference to the table element that DatacoreJS has rendered. You can do this using JavaScript's querySelector or getElementById methods.
  2. Trigger Rendering: Once you have the table element, you can use MarkdownRenderer.render to re-render it. This will cause the Supercharged Links plugin to recognize the links and apply the coloring.

Here’s a simplified example of how you might implement this:

import { MarkdownRenderer } from 'obsidian';

function triggerSuperchargedLinks(element) {
  MarkdownRenderer.render(app, '', element, '', this);
}

// After DatacoreJS renders the table
const tableElement = document.querySelector('table');
if (tableElement) {
  triggerSuperchargedLinks(tableElement);
}

This code snippet shows the basic idea. You'll need to adapt it to your specific DatacoreJS setup. You might use a useEffect hook in React (if you're using JSX) to run this code after the component has rendered.

Shorter DatacoreJS Code: Is It Possible?

The second part of the question is about writing shorter DatacoreJS code, similar to Dataview's DQL. Dataview's DQL is known for its concise and readable syntax, making it easy to query and display data. DatacoreJS, being more flexible and JavaScript-based, can sometimes require more code to achieve the same result.

Leveraging DatacoreJS Features

While DatacoreJS might not have a direct equivalent to DQL's syntax, there are ways to make your code more concise and readable:

  1. Helper Functions: As seen in the original code, using helper functions like formatDate and formatDiff can make your code cleaner. You can create more helper functions to handle common tasks, reducing redundancy.
  2. Array Methods: JavaScript's array methods like map, filter, and sort are your best friends. Use them to manipulate and transform your data in a functional and readable way.
  3. Destructuring: Use destructuring to extract values from objects and arrays, making your code less verbose.
  4. Custom Hooks: If you find yourself repeating certain logic, consider creating custom React hooks to encapsulate that logic. This can make your components cleaner and easier to maintain.

Example of Code Shortening

Let's look at the original code and see how we can shorten it:

function formatDate(dstr) {
    if (!dstr) return "";
    const d = new Date(dstr);
    const pad = n => n < 10 ? "0" + n : n;
    return `${pad(d.getDate())}.${pad(d.getMonth() + 1)}.${d.getFullYear()}, ${pad(d.getHours())}:${pad(d.getMinutes())} Uhr`;
}

function formatDiff(dateStr) {
    if (!dateStr) return "";
    let ms = now - new Date(dateStr);
    const d = Math.floor(ms / (1000 * 60 * 60 * 24)); ms -= d * 24 * 60 * 60 * 1000;
    const h = Math.floor(ms / (1000 * 60 * 60)); ms -= h * 60 * 60 * 1000;
    const m = Math.floor(ms / (1000 * 60)); ms -= m * 60 * 1000;
    const s = Math.floor(ms / 1000); ms -= s * 1000;
    let parts = [];
    if (d) parts.push(`${d} Tage`);
    if (h) parts.push(`${h} Stunden`);
    if (m) parts.push(`${m} Minuten`);
    parts.push(`${s} Sekunden und ${ms} Millisekunden`);
    return parts.join(', ');
}

We can make the formatDiff function more concise using template literals and a more functional approach:

function formatDiff(dateStr) {
    if (!dateStr) return "";
    const ms = Date.now() - new Date(dateStr).getTime();
    const seconds = Math.floor(ms / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);
    const days = Math.floor(hours / 24);
    
    const parts = [];
    if (days) parts.push(`${days} Tage`);
    if (hours % 24) parts.push(`${hours % 24} Stunden`);
    if (minutes % 60) parts.push(`${minutes % 60} Minuten`);
    parts.push(`${seconds % 60} Sekunden`);
    
    return parts.join(', ');
}

This version is more readable and achieves the same result with fewer lines of code.

Using Libraries

Consider using libraries like date-fns or moment.js for date formatting and manipulation. These libraries provide powerful and flexible functions that can simplify your code.

Conclusion

Getting Supercharged Links to work with DatacoreJS requires a bit of extra effort, but it's definitely achievable. By triggering the plugin's rendering manually, you can bring those beautiful colors back to your dynamic tables. And while DatacoreJS might require more code than Dataview's DQL, using helper functions, array methods, and other JavaScript techniques can help you write cleaner and more concise code. Keep experimenting and happy coding!