Skip to content

Instantly share code, notes, and snippets.

@IAmStoxe
Created March 20, 2025 19:26
Show Gist options
  • Save IAmStoxe/c8a7715e729d4f4b5597cf80bec2f96e to your computer and use it in GitHub Desktop.
Save IAmStoxe/c8a7715e729d4f4b5597cf80bec2f96e to your computer and use it in GitHub Desktop.

Recent Files Tracker for Obsidian

Track and display recently modified files across your Obsidian vault.

Features

  • Monitor files from specific folders
  • Group by subfolders
  • Customizable time periods and status indicators
  • Sort by priority

Installation

  1. Copy the script into a Dataview JS code block in any Obsidian note
  2. Customize the CONFIG section
  3. Run the script

Usage

The script generates tables of recent files organized by folder, with timestamps and status indicators.

/**
 * ```dataviewjs
 * // Paste script here
 * ```
 */

Configuration

Modify the CONFIG object with your settings:

const CONFIG = {
  // Required: Folders to track
  folders: [
    { path: "Projects", displayName: "Projects", icon: "πŸ“Š", extractSubfolders: true },
    { path: "Meetings", displayName: "Meetings", icon: "πŸ—£οΈ", extractSubfolders: false }
  ],
  
  // Time settings (all in hours/days)
  recentDays: 14,      // How far back to look
  hoursRecent: 8,      // "Recent" threshold
  hoursToday: 24,      // "Today" threshold
  
  // Display settings
  maxFilesPerGroup: 5, // Max files per section
  dateFormat: "MMM d", // Format for older dates
  
  // Status labels
  status: {
    recent: "πŸ”΅ Recent",
    today: "🟒 Today",
    earlier: "🟠 Earlier"
  },
  
  prioritizeProjects: true, // Show projects first
  defaultIcon: "πŸ“„"        // Default folder icon
};

Requirements

  • Obsidian
  • Dataview plugin

License

MIT

/**
* Recent Files Tracker for Obsidian
*
* Displays recently modified files from configurable folders.
*
* Features:
* - Track multiple folders with custom icons
* - Group by subfolders
* - Configurable time periods and status indicators
*
* Usage:
* 1. Copy this code into a Dataview JS code block
* 2. Modify the USER_CONFIG section to match your needs
* 3. Run the script
*/
// User configuration - Required
const CONFIG = {
// REQUIRED: Folders to track
folders: [
// Examples (replace with your own):
{ path: "Projects", displayName: "Projects", icon: "πŸ“Š", extractSubfolders: true },
{ path: "Meetings", displayName: "Meeting Notes", icon: "πŸ—£οΈ", extractSubfolders: false },
{ path: "Daily Notes", displayName: "Daily Notes", icon: "πŸ“", extractSubfolders: false }
],
// Time settings
recentDays: 14, // How far back to look
hoursRecent: 8, // "Recent" threshold in hours
hoursToday: 24, // "Today" threshold in hours
// Display settings
maxFilesPerGroup: 5, // Max files per folder
dateFormat: "MMM d", // Date format for older files
// Status labels
status: {
recent: "πŸ”΅ Recent",
today: "🟒 Today",
earlier: "🟠 Earlier"
},
prioritizeProjects: true, // Show projects first
defaultIcon: "πŸ“„" // Icon for unlisted folders
};
// Time constants
const TIME = {
MS: { MINUTE: 60000, HOUR: 3600000, DAY: 86400000 },
FORMAT_THRESHOLD_DAYS: 7
};
// Get human-readable relative time
function getRelativeTime(timestamp) {
const diffMs = new Date() - new Date(timestamp);
const diffMins = Math.floor(diffMs / TIME.MS.MINUTE);
const diffHours = Math.floor(diffMs / TIME.MS.HOUR);
const diffDays = Math.floor(diffMs / TIME.MS.DAY);
if (diffMins < 1) return "Just now";
if (diffMins < 60) return `${diffMins}m ago`;
if (diffHours < 24) return `${diffHours}h ago`;
if (diffDays === 1) return "Yesterday";
if (diffDays < TIME.FORMAT_THRESHOLD_DAYS) return `${diffDays} days ago`;
return dv.date(timestamp).toFormat(CONFIG.dateFormat);
}
// Get folder configuration by path
function getFolderConfig(path) {
return CONFIG.folders.find(folder => path.includes(folder.path)) || null;
}
// Get status based on modification time
function getStatus(mtime) {
const now = dv.date("today");
if (mtime >= now.minus({hours: CONFIG.hoursRecent})) return CONFIG.status.recent;
if (mtime >= now.minus({hours: CONFIG.hoursToday})) return CONFIG.status.today;
return CONFIG.status.earlier;
}
// Build query and get recent files
const folderQuery = CONFIG.folders.map(f => `"${f.path}"`).join(" OR ");
const recentFiles = dv.pages(folderQuery)
.where(p => p.file.mtime >= dv.date("today").minus({days: CONFIG.recentDays}));
// Group files by folder/subfolder
const fileGroups = recentFiles.groupBy(p => {
for (const folder of CONFIG.folders) {
if (p.file.path.includes(`${folder.path}/`)) {
if (folder.extractSubfolders) {
const match = p.file.path.match(new RegExp(`${folder.path}\/([^\/]+)`));
return match ? `${folder.path}/${match[1]}` : p.file.folder;
}
return folder.path;
}
}
return p.file.folder;
});
// Sort groups by priority
const sortedGroups = fileGroups.sort((a, b) => {
const aKey = a?.key || '';
const bKey = b?.key || '';
// Prioritize projects if configured
if (CONFIG.prioritizeProjects) {
const projectPath = (CONFIG.folders.find(f => f.path.toLowerCase().includes("projects"))?.path || "Projects").toLowerCase();
const aIsProject = aKey.toLowerCase().includes(projectPath);
const bIsProject = bKey.toLowerCase().includes(projectPath);
if (aIsProject && !bIsProject) return -1;
if (!aIsProject && bIsProject) return 1;
}
// Preserve folder order from config
for (const folder of CONFIG.folders) {
const aMatches = aKey.startsWith(folder.path);
const bMatches = bKey.startsWith(folder.path);
if (aMatches && !bMatches) return -1;
if (!aMatches && bMatches) return 1;
if (aMatches && bMatches) return aKey.localeCompare(bKey);
}
return aKey.localeCompare(bKey);
});
// Display each group
for (const group of sortedGroups) {
let folderName = group.key;
let icon = CONFIG.defaultIcon + " ";
const folderConfig = getFolderConfig(group.key);
if (folderConfig) {
if (folderConfig.extractSubfolders && group.key !== folderConfig.path) {
const subfolderName = group.key.split('/').pop();
folderName = `${folderConfig.displayName}: ${subfolderName}`;
} else {
folderName = folderConfig.displayName;
}
icon = folderConfig.icon + " ";
} else {
folderName = group.key.split('/').pop();
}
// Display header and table
dv.header(3, `${icon}${folderName}`);
dv.table(
["Modified", "Item", "Status"],
group.rows
.sort(p => p.file.mtime, 'desc')
.slice(0, CONFIG.maxFilesPerGroup)
.map(p => [getRelativeTime(p.file.mtime), p.file.link, getStatus(p.file.mtime)])
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment