From 8f3ad0eb0ac6b78ada89c1ffdf2adf2fafe0e6a1 Mon Sep 17 00:00:00 2001 From: gearheaded Date: Wed, 10 Jun 2026 15:07:58 -0400 Subject: [PATCH] Removed year and month toggle from panel and fixed fit mode. Also truncated recent repo. Small other fixes --- main.js | 45 +++++++----------------- manifest.json | 2 +- obsidiangraphfiles2.zip | Bin 0 -> 19692 bytes src/main.ts | 75 +++++++++++++++++----------------------- 4 files changed, 46 insertions(+), 76 deletions(-) create mode 100644 obsidiangraphfiles2.zip diff --git a/main.js b/main.js index 19bef15..3680e8b 100644 --- a/main.js +++ b/main.js @@ -330,9 +330,8 @@ var ContributionsView = class extends import_obsidian.ItemView { if (preset !== "fit") return PRESET_SIZES[preset]; const cols = this.viewMode === "year" ? 53 : 7; - const padding = 20; const gap = 2; - const available = (this.panelWidth || 240) - padding; + const available = Math.max(100, (this.panelWidth || 260) - 28); const cell = Math.max(5, Math.floor((available - gap * (cols - 1)) / cols)); return { cell, gap }; } @@ -384,24 +383,8 @@ var ContributionsView = class extends import_obsidian.ItemView { renderHeader(container) { const s = this.plugin.settings; const header = container.createDiv({ cls: "gh-header" }); - const left = header.createDiv({ cls: "gh-header-left" }); if (s.githubUsername) - left.createEl("span", { cls: "gh-username", text: s.githubUsername }); - const viewToggle = left.createDiv({ cls: "gh-view-toggle" }); - const yearBtn = viewToggle.createEl("button", { cls: "gh-toggle-btn", text: "Year" }); - const monthBtn = viewToggle.createEl("button", { cls: "gh-toggle-btn", text: "Month" }); - if (this.viewMode === "year") - yearBtn.addClass("gh-toggle-btn--active"); - else - monthBtn.addClass("gh-toggle-btn--active"); - yearBtn.onclick = async () => { - this.viewMode = "year"; - await this.render(); - }; - monthBtn.onclick = async () => { - this.viewMode = "month"; - await this.render(); - }; + header.createEl("span", { cls: "gh-username", text: s.githubUsername }); const nav = header.createDiv({ cls: "gh-nav" }); const currentYear = new Date().getFullYear(); if (this.viewMode === "year") { @@ -456,8 +439,11 @@ var ContributionsView = class extends import_obsidian.ItemView { this.pill(stats, String(info.sinceCommit) + "d", "since commit"); } if (info.recentRepo) { + const maxLen = 16; + const name = info.recentRepo.length > maxLen ? info.recentRepo.slice(0, maxLen - 1) + "\u2026" : info.recentRepo; const pill = stats.createDiv({ cls: "gh-stat gh-stat--wide" }); - pill.createEl("span", { cls: "gh-stat-val", text: info.recentRepo }); + pill.title = info.recentRepo; + pill.createEl("span", { cls: "gh-stat-val", text: name }); pill.createEl("span", { cls: "gh-stat-lbl", text: "recent repo" }); } } @@ -496,18 +482,18 @@ var ContributionsView = class extends import_obsidian.ItemView { renderMonthGrid(container, weeks) { const { cell, gap } = this.getCellSize(); const graphWrap = container.createDiv({ cls: "gh-graph-wrap" }); + const colTemplate = `repeat(7,${cell}px)`; const dowRow = graphWrap.createDiv({ cls: "gh-dow-row" }); - dowRow.style.cssText = `display:grid;grid-template-columns:repeat(7,${cell}px);gap:${gap}px;margin-bottom:3px`; + dowRow.style.cssText = `display:grid;grid-template-columns:${colTemplate};gap:${gap}px;margin-bottom:4px`; ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"].forEach((d) => { - const lbl = dowRow.createEl("span", { cls: "gh-month-lbl", text: d }); - lbl.style.fontSize = Math.max(8, cell - 2) + "px"; - lbl.style.textAlign = "center"; + const lbl = dowRow.createEl("span", { cls: "gh-dow-lbl", text: d }); + lbl.style.cssText = `font-size:10px;color:var(--text-faint);text-align:center;overflow:hidden`; }); const grid = graphWrap.createDiv({ cls: "gh-month-grid" }); grid.style.cssText = `display:flex;flex-direction:column;gap:${gap}px`; weeks.forEach((week) => { const row = grid.createDiv({ cls: "gh-month-row-cells" }); - row.style.cssText = `display:flex;gap:${gap}px`; + row.style.cssText = `display:grid;grid-template-columns:${colTemplate};gap:${gap}px`; week.forEach((day) => this.renderCell(row, day, cell)); }); } @@ -758,13 +744,8 @@ var GitHubContributionsPlugin = class extends import_obsidian.Plugin { style.id = "gh-contributions-styles"; style.textContent = ` .gh-contributions-view{padding:12px 10px 16px;overflow-y:auto;overflow-x:hidden;user-select:none} -.gh-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:8px;gap:6px} -.gh-header-left{display:flex;flex-direction:column;gap:4px;min-width:0} -.gh-username{font-size:13px;font-weight:600;color:var(--text-normal);overflow:hidden;text-overflow:ellipsis;white-space:nowrap} -.gh-view-toggle{display:flex;gap:2px} -.gh-toggle-btn{background:none;border:1px solid var(--background-modifier-border);border-radius:4px;color:var(--text-muted);cursor:pointer;font-size:11px;padding:2px 7px;transition:background .15s} -.gh-toggle-btn:hover{background:var(--background-modifier-hover);color:var(--text-normal)} -.gh-toggle-btn--active{background:var(--interactive-accent)!important;color:var(--text-on-accent)!important;border-color:var(--interactive-accent)!important} +.gh-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;gap:6px} +.gh-username{font-size:13px;font-weight:600;color:var(--text-normal);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0} .gh-nav{display:flex;align-items:center;gap:3px;flex-shrink:0} .gh-nav-label{font-size:12px;color:var(--text-muted);min-width:52px;text-align:center;white-space:nowrap} .gh-nav-btn{background:none;border:1px solid var(--background-modifier-border);border-radius:4px;color:var(--text-muted);cursor:pointer;font-size:14px;line-height:1;padding:1px 6px;transition:background .15s} diff --git a/manifest.json b/manifest.json index c944361..32e721f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "github-contributions", "name": "GitHub Contributions", - "version": "1.1.0", + "version": "1.5.0", "minAppVersion": "0.15.0", "description": "Display your GitHub contribution graph in the Obsidian sidebar with streak tracking, tooltips, and daily note integration.", "author": "gearheaded", diff --git a/obsidiangraphfiles2.zip b/obsidiangraphfiles2.zip new file mode 100644 index 0000000000000000000000000000000000000000..346282fc3dc469da9cfc5ae2f2b2f29c16e2cff6 GIT binary patch literal 19692 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 literal 0 HcmV?d00001 diff --git a/src/main.ts b/src/main.ts index 71a8642..a1029f2 100644 --- a/src/main.ts +++ b/src/main.ts @@ -10,13 +10,13 @@ import { TFile, } from "obsidian"; -// ## Constants ################################################################ +// ── Constants ──────────────────────────────────────────────────────────────── const VIEW_TYPE = "github-contributions"; const GITHUB_GRAPHQL = "https://api.github.com/graphql"; const MONTHS = ["January","February","March","April","May","June","July","August","September","October","November","December"]; const MONTHS_SHORT = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; -// ## Types #################################################################### +// ── Types ──────────────────────────────────────────────────────────────────── type SizePreset = "ultra-compact" | "compact" | "medium" | "large" | "fit"; type ViewMode = "year" | "month"; type DataSource = "github" | "local" | "both"; @@ -79,7 +79,7 @@ const PRESET_SIZES: Record = { "fit": { cell: 0, gap: 2 }, // calculated at render time }; -// ## GitHub API ############################################################### +// ── GitHub API ─────────────────────────────────────────────────────────────── async function fetchGitHubContributions( username: string, token: string, @@ -107,7 +107,7 @@ async function fetchGitHubContributions( return map; } -// ## Local Git ################################################################ +// ── Local Git ──────────────────────────────────────────────────────────────── // Use Obsidian's adapter to run shell commands (desktop only via child_process via require) // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -181,7 +181,7 @@ function fetchLocalCommits(repo: LocalRepo, year: number): Map { return map; } -// ## Build unified day map #################################################### +// ── Build unified day map ──────────────────────────────────────────────────── async function buildDayMap( settings: GitHubContributionsSettings, year: number, @@ -226,7 +226,7 @@ async function buildDayMap( return { days, totalGH, totalLocal, repoList: repos }; } -// ## Generate full year week structure ######################################## +// ── Generate full year week structure ──────────────────────────────────────── function buildYearWeeks(year: number, days: Map): DayData[][] { // Build array of all dates in the year, padded to start on Sunday const jan1 = new Date(year, 0, 1); @@ -274,7 +274,7 @@ function buildMonthDays(year: number, month: number, days: Map) return weeks; } -// ## Streaks ################################################################## +// ── Streaks ────────────────────────────────────────────────────────────────── function calculateStreaks(days: Map, year: number): StreakInfo { const isLeap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; const daysInYear = isLeap ? 366 : 365; @@ -321,7 +321,7 @@ function mostRecentRepo(repos: LocalRepo[]): string | null { return sorted[0]?.name ?? null; } -// ## View ##################################################################### +// ── View ───────────────────────────────────────────────────────────────────── export class ContributionsView extends ItemView { plugin: GitHubContributionsPlugin; displayYear: number; @@ -375,9 +375,9 @@ export class ContributionsView extends ItemView { // Fit: calculate based on panel width // Year view: 53 columns. Month view: 7 columns. const cols = this.viewMode === "year" ? 53 : 7; - const padding = 20; const gap = 2; - const available = (this.panelWidth || 240) - padding; + // Account for container padding (10px each side) + scrollbar (~8px) + const available = Math.max(100, (this.panelWidth || 260) - 28); const cell = Math.max(5, Math.floor((available - gap * (cols - 1)) / cols)); return { cell, gap }; } @@ -441,19 +441,10 @@ export class ContributionsView extends ItemView { const s = this.plugin.settings; const header = container.createDiv({ cls: "gh-header" }); - // Left: username + view toggle - const left = header.createDiv({ cls: "gh-header-left" }); - if (s.githubUsername) left.createEl("span", { cls: "gh-username", text: s.githubUsername }); + // Left: username + if (s.githubUsername) header.createEl("span", { cls: "gh-username", text: s.githubUsername }); - const viewToggle = left.createDiv({ cls: "gh-view-toggle" }); - const yearBtn = viewToggle.createEl("button", { cls: "gh-toggle-btn", text: "Year" }); - const monthBtn = viewToggle.createEl("button", { cls: "gh-toggle-btn", text: "Month" }); - if (this.viewMode === "year") yearBtn.addClass("gh-toggle-btn--active"); - else monthBtn.addClass("gh-toggle-btn--active"); - yearBtn.onclick = async () => { this.viewMode = "year"; await this.render(); }; - monthBtn.onclick = async () => { this.viewMode = "month"; await this.render(); }; - - // Right: nav + // Right: nav only const nav = header.createDiv({ cls: "gh-nav" }); const currentYear = new Date().getFullYear(); @@ -501,8 +492,11 @@ export class ContributionsView extends ItemView { } if (info.recentRepo) { + const maxLen = 16; + const name = info.recentRepo.length > maxLen ? info.recentRepo.slice(0, maxLen - 1) + "\u2026" : info.recentRepo; const pill = stats.createDiv({ cls: "gh-stat gh-stat--wide" }); - pill.createEl("span", { cls: "gh-stat-val", text: info.recentRepo }); + pill.title = info.recentRepo; + pill.createEl("span", { cls: "gh-stat-val", text: name }); pill.createEl("span", { cls: "gh-stat-lbl", text: "recent repo" }); } } @@ -548,22 +542,22 @@ export class ContributionsView extends ItemView { private renderMonthGrid(container: HTMLElement, weeks: DayData[][]) { const { cell, gap } = this.getCellSize(); const graphWrap = container.createDiv({ cls: "gh-graph-wrap" }); + const colTemplate = `repeat(7,${cell}px)`; - // Day-of-week headers + // Day-of-week headers - use same grid columns as cells so they align const dowRow = graphWrap.createDiv({ cls: "gh-dow-row" }); - dowRow.style.cssText = `display:grid;grid-template-columns:repeat(7,${cell}px);gap:${gap}px;margin-bottom:3px`; + dowRow.style.cssText = `display:grid;grid-template-columns:${colTemplate};gap:${gap}px;margin-bottom:4px`; ["Su","Mo","Tu","We","Th","Fr","Sa"].forEach(d => { - const lbl = dowRow.createEl("span", { cls: "gh-month-lbl", text: d }); - lbl.style.fontSize = Math.max(8, cell - 2) + "px"; - lbl.style.textAlign = "center"; + const lbl = dowRow.createEl("span", { cls: "gh-dow-lbl", text: d }); + lbl.style.cssText = `font-size:10px;color:var(--text-faint);text-align:center;overflow:hidden`; }); - // Grid - rows are weeks + // Grid - rows are weeks, also grid for perfect alignment const grid = graphWrap.createDiv({ cls: "gh-month-grid" }); grid.style.cssText = `display:flex;flex-direction:column;gap:${gap}px`; weeks.forEach(week => { const row = grid.createDiv({ cls: "gh-month-row-cells" }); - row.style.cssText = `display:flex;gap:${gap}px`; + row.style.cssText = `display:grid;grid-template-columns:${colTemplate};gap:${gap}px`; week.forEach(day => this.renderCell(row, day, cell)); }); } @@ -697,7 +691,7 @@ export class ContributionsView extends ItemView { } } -// ## Helpers ################################################################## +// ── Helpers ────────────────────────────────────────────────────────────────── function countToLevel(n: number): number { if (n === 0) return 0; if (n <= 2) return 1; @@ -706,7 +700,7 @@ function countToLevel(n: number): number { return 4; } -// ## Settings Tab ############################################################# +// ── Settings Tab ───────────────────────────────────────────────────────────── class GitHubContributionsSettingTab extends PluginSettingTab { plugin: GitHubContributionsPlugin; constructor(app: App, plugin: GitHubContributionsPlugin) { @@ -719,7 +713,7 @@ class GitHubContributionsSettingTab extends PluginSettingTab { containerEl.empty(); containerEl.createEl("h2", { text: "GitHub Contributions" }); - // ## Data Sources + // ── Data Sources containerEl.createEl("h3", { text: "Data Sources" }); new Setting(containerEl) @@ -759,7 +753,7 @@ class GitHubContributionsSettingTab extends PluginSettingTab { .onChange(async v => { this.plugin.settings.localRepoRoot = v.trim(); await this.plugin.saveSettings(); })); } - // ## Display + // ── Display containerEl.createEl("h3", { text: "Display" }); new Setting(containerEl) @@ -797,7 +791,7 @@ class GitHubContributionsSettingTab extends PluginSettingTab { } })); - // ## Daily Notes + // ── Daily Notes containerEl.createEl("h3", { text: "Daily Notes" }); new Setting(containerEl) @@ -814,7 +808,7 @@ class GitHubContributionsSettingTab extends PluginSettingTab { } } -// ## Plugin ################################################################### +// ── Plugin ─────────────────────────────────────────────────────────────────── export default class GitHubContributionsPlugin extends Plugin { settings: GitHubContributionsSettings = { ...DEFAULT_SETTINGS }; @@ -860,13 +854,8 @@ export default class GitHubContributionsPlugin extends Plugin { style.id = "gh-contributions-styles"; style.textContent = ` .gh-contributions-view{padding:12px 10px 16px;overflow-y:auto;overflow-x:hidden;user-select:none} -.gh-header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:8px;gap:6px} -.gh-header-left{display:flex;flex-direction:column;gap:4px;min-width:0} -.gh-username{font-size:13px;font-weight:600;color:var(--text-normal);overflow:hidden;text-overflow:ellipsis;white-space:nowrap} -.gh-view-toggle{display:flex;gap:2px} -.gh-toggle-btn{background:none;border:1px solid var(--background-modifier-border);border-radius:4px;color:var(--text-muted);cursor:pointer;font-size:11px;padding:2px 7px;transition:background .15s} -.gh-toggle-btn:hover{background:var(--background-modifier-hover);color:var(--text-normal)} -.gh-toggle-btn--active{background:var(--interactive-accent)!important;color:var(--text-on-accent)!important;border-color:var(--interactive-accent)!important} +.gh-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;gap:6px} +.gh-username{font-size:13px;font-weight:600;color:var(--text-normal);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0} .gh-nav{display:flex;align-items:center;gap:3px;flex-shrink:0} .gh-nav-label{font-size:12px;color:var(--text-muted);min-width:52px;text-align:center;white-space:nowrap} .gh-nav-btn{background:none;border:1px solid var(--background-modifier-border);border-radius:4px;color:var(--text-muted);cursor:pointer;font-size:14px;line-height:1;padding:1px 6px;transition:background .15s}