From 9f790cd95a208e0bea762a29a788eaa37f5a4be3 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 12 May 2026 16:21:05 +0300 Subject: [PATCH] display folder size --- admin/admin.v | 4 +- admin/admin_routes.v | 5 +- database_d_sqlite.v | 14 +++++ database_notd_sqlite.v | 10 +++ gitly.v | 14 +++++ repo/file.v | 21 ++++++- repo/repo.v | 91 +++++++++++++++++++++++++-- repo/repo_routes.v | 12 ++++ repo/repo_template.v | 14 ++--- settings.v | 22 ++++--- static/assets/version | 2 +- static/css/files.scss | 18 +++++- static/css/langs.scss | 19 ++++-- static/css/tree.scss | 106 ++++++++++++++++---------------- static/js/tree.js | 99 ++++++++++++++++++----------- templates/admin/settings.html | 8 +++ templates/layout/repo_menu.html | 41 ++++++------ templates/tree.html | 21 ++++++- 18 files changed, 376 insertions(+), 145 deletions(-) diff --git a/admin/admin.v b/admin/admin.v index 5313f9d..653fc60 100644 --- a/admin/admin.v +++ b/admin/admin.v @@ -34,8 +34,8 @@ pub fn (mut app App) remove_admin(user_id int) ! { app.set_user_admin_status(user_id, false)! } -pub fn (mut app App) update_gitly_settings(oauth_client_id string, oauth_client_secret string) ! { - app.update_settings(oauth_client_id, oauth_client_secret)! +pub fn (mut app App) update_gitly_settings(oauth_client_id string, oauth_client_secret string, tree_folder_size_enabled bool) ! { + app.update_settings(oauth_client_id, oauth_client_secret, tree_folder_size_enabled)! app.load_settings() } diff --git a/admin/admin_routes.v b/admin/admin_routes.v index 7cfbd40..8ed2e3f 100644 --- a/admin/admin_routes.v +++ b/admin/admin_routes.v @@ -21,7 +21,10 @@ pub fn (mut app App) handle_admin_update_settings(oauth_client_id string, oauth_ return ctx.redirect_to_index() } - app.update_gitly_settings(oauth_client_id, oauth_client_secret) or { app.info(err.str()) } + tree_folder_size_enabled := 'tree_folder_size_enabled' in ctx.form + app.update_gitly_settings(oauth_client_id, oauth_client_secret, tree_folder_size_enabled) or { + app.info(err.str()) + } return ctx.redirect('/admin') } diff --git a/database_d_sqlite.v b/database_d_sqlite.v index cd888d5..f44f282 100644 --- a/database_d_sqlite.v +++ b/database_d_sqlite.v @@ -24,6 +24,20 @@ fn db_exec_values(db &GitlyDb, query string) ![][]string { return values } +fn db_column_exists(db &GitlyDb, table_name string, column_name string) !bool { + rows := db_exec_values(db, 'pragma table_info(${sql_table(table_name)})')! + for row in rows { + if row.len > 1 && row[1] == column_name { + return true + } + } + return false +} + +fn db_bool_column_type() string { + return 'INTEGER NOT NULL DEFAULT 0' +} + fn first_env(keys []string, fallback string) string { for key in keys { value := os.getenv(key) diff --git a/database_notd_sqlite.v b/database_notd_sqlite.v index bb90d52..99937da 100644 --- a/database_notd_sqlite.v +++ b/database_notd_sqlite.v @@ -32,6 +32,16 @@ fn db_exec_values(db &GitlyDb, query string) ![][]string { return values } +fn db_column_exists(db &GitlyDb, table_name string, column_name string) !bool { + rows := db_exec_values(db, + 'select column_name from information_schema.columns where table_name = ${sql_literal(table_name.to_lower())} and column_name = ${sql_literal(column_name)}')! + return rows.len > 0 +} + +fn db_bool_column_type() string { + return 'BOOLEAN NOT NULL DEFAULT false' +} + fn first_env(keys []string, fallback string) string { for key in keys { value := os.getenv(key) diff --git a/gitly.v b/gitly.v index 944b8a5..cfccb69 100644 --- a/gitly.v +++ b/gitly.v @@ -68,6 +68,7 @@ fn new_app() !&App { set_rand_crypto_safe_seed() app.create_tables()! + app.migrate_tables()! create_directory_if_not_exists('logs') @@ -254,6 +255,19 @@ fn (mut app App) create_tables() ! { }! } +fn (mut app App) migrate_tables() ! { + app.add_missing_column('File', 'is_size_calculated', db_bool_column_type())! + app.add_missing_column('Settings', 'disable_tree_folder_size', db_bool_column_type())! +} + +fn (mut app App) add_missing_column(table_name string, column_name string, column_type string) ! { + if db_column_exists(app.db, table_name, column_name)! { + return + } + + app.db.exec('alter table ${sql_table(table_name)} add column ${sql_table(column_name)} ${column_type}')! +} + fn (mut ctx Context) json_success[T](result T) veb.Result { response := api.ApiSuccessResponse[T]{ success: true diff --git a/repo/file.v b/repo/file.v index af77ec5..9992395 100644 --- a/repo/file.v +++ b/repo/file.v @@ -14,6 +14,7 @@ struct File { contributors_count int last_hash string size int + is_size_calculated bool views_count int mut: last_msg string @@ -47,11 +48,26 @@ fn (f File) pretty_last_time() string { } fn (f File) pretty_size() string { + if f.size == 0 { + return 'n/a' + } + + return pretty_size_bytes(f.size) +} + +fn (f File) pretty_tree_size() string { + if !f.is_dir || !f.is_size_calculated { + return '' + } + + return pretty_size_bytes(f.size) +} + +fn pretty_size_bytes(size_in_bytes int) string { sizes := ['bytes', 'KB', 'MB', 'GB', 'TB'] - size_in_bytes := f.size if size_in_bytes == 0 { - return 'n/a' + return '0 bytes' } index := int(math.floor(math.log(size_in_bytes) / math.log(1024))) @@ -70,6 +86,7 @@ struct FileInfo { last_msg string last_hash string last_time string + size string } fn calculate_lines_of_code(source string) (int, int) { diff --git a/repo/repo.v b/repo/repo.v index 4987c32..304892c 100644 --- a/repo/repo.v +++ b/repo/repo.v @@ -607,12 +607,13 @@ fn (r &Repo) parse_ls(ls_line string, branch string) ?File { } return File{ - name: item_name - parent_path: parent_path - repo_id: r.id - branch: branch - is_dir: item_type == 'tree' - size: if item_type == 'blob' { item_size.int() } else { 0 } + name: item_name + parent_path: parent_path + repo_id: r.id + branch: branch + is_dir: item_type == 'tree' + size: if item_type == 'blob' { item_size.int() } else { 0 } + is_size_calculated: item_type == 'blob' } } @@ -691,6 +692,78 @@ fn (mut app App) slow_fetch_files_info(mut repo Repo, branch string, path string } } +fn (mut app App) slow_fetch_folder_sizes(mut repo Repo, branch string, path string) ! { + files := app.find_repository_items(repo.id, branch, path) + dirs := files.filter(it.is_dir && !it.is_size_calculated) + if dirs.len == 0 { + return + } + + dir_names := dirs.map(it.name) + sizes := repo.calculate_child_folder_sizes(branch, path, dir_names) + + for dir in dirs { + size := sizes[dir.name] or { 0 } + app.update_file_size(dir.id, size, true)! + } +} + +fn (r &Repo) calculate_child_folder_sizes(branch string, path string, dir_names []string) map[string]int { + mut sizes := map[string]int{} + for dir_name in dir_names { + sizes[dir_name] = 0 + } + if dir_names.len == 0 { + return sizes + } + + normalized_path := normalize_tree_path(path) + mut args := ['ls-tree', '-r', '--full-name', '--long', branch] + if normalized_path != '' { + args << '--' + args << normalized_path + } + + result := git.Git.exec_in_dir(r.git_dir, args) + if result.exit_code != 0 { + eprintln('git ls-tree error while calculating folder sizes: ${result.output}') + return sizes + } + + prefix := if normalized_path == '' { '' } else { '${normalized_path}/' } + for line in result.output.split_into_lines() { + tab_pos := line.index('\t') or { continue } + meta := line[..tab_pos] + item_path := line[tab_pos + 1..] + meta_parts := meta.fields() + if meta_parts.len < 4 || meta_parts[1] != 'blob' { + continue + } + + mut relative_path := item_path + if prefix != '' { + if !item_path.starts_with(prefix) { + continue + } + relative_path = item_path[prefix.len..] + } + + slash_pos := relative_path.index('/') or { continue } + child_dir := relative_path[..slash_pos] + if child_dir !in sizes { + continue + } + + sizes[child_dir] = sizes[child_dir] + meta_parts[3].int() + } + + return sizes +} + +fn normalize_tree_path(path string) string { + return path.trim_string_left('/').trim_string_right('/') +} + fn (r Repo) get_last_branch_commit_hash(branch_name string) string { git_result := git.Git.exec_in_dir(r.git_dir, ['log', '-n', '1', branch_name, '--pretty=format:%h']) @@ -786,6 +859,12 @@ fn (mut app App) fetch_file_info(r &Repo, file &File) ! { }! } +fn (mut app App) update_file_size(file_id int, size int, is_size_calculated bool) ! { + sql app.db { + update File set size = size, is_size_calculated = is_size_calculated where id == file_id + }! +} + fn (mut app App) update_repo_primary_branch(repo_id int, branch string) ! { sql app.db { update Repo set primary_branch = branch where id == repo_id diff --git a/repo/repo_routes.v b/repo/repo_routes.v index 4f66622..819c983 100644 --- a/repo/repo_routes.v +++ b/repo/repo_routes.v @@ -307,9 +307,15 @@ fn bg_fetch_files_info(repo_ Repo, branch string, path string, conf config.Confi } config: conf } + app.load_settings() app.slow_fetch_files_info(mut repo, branch, path) or { eprintln('bg_fetch_files_info error: ${err}') } + if app.settings.tree_folder_size_enabled() { + app.slow_fetch_folder_sizes(mut repo, branch, path) or { + eprintln('bg_fetch_folder_sizes error: ${err}') + } + } app.db.close() or {} } @@ -399,6 +405,8 @@ pub fn (mut app App) tree(mut ctx Context, username string, repo_name string, br app.info('${log_prefix}: ${items.len} items found in branch ${branch_name}') + show_folder_size := app.settings.tree_folder_size_enabled() + if items.len == 0 { // No files in the db, fetch them from git and cache in db app.info('${log_prefix}: caching items in repository with ${repo_id}') @@ -412,6 +420,9 @@ pub fn (mut app App) tree(mut ctx Context, username string, repo_name string, br } else if items.any(it.last_msg == '') { // Some files still need commit info — fetch in background spawn bg_fetch_files_info(repo, branch_name, ctx.current_path, app.config) + } else if show_folder_size && items.any(it.is_dir && !it.is_size_calculated) { + // Some folders still need size info, fetch in background + spawn bg_fetch_files_info(repo, branch_name, ctx.current_path, app.config) } // Fetch last commit message for this directory, printed at the top of the tree @@ -555,6 +566,7 @@ pub fn (mut app App) handle_api_repo_files(mut ctx Context, repo_id_str string) last_msg: item.last_msg last_hash: item.last_hash last_time: item.pretty_last_time() + size: item.pretty_tree_size() } } diff --git a/repo/repo_template.v b/repo/repo_template.v index 99c5920..0f8a082 100644 --- a/repo/repo_template.v +++ b/repo/repo_template.v @@ -14,27 +14,27 @@ fn (mut app App) format_commits_count(repo Repo, branch_name string) veb.RawHtml branch := app.find_repo_branch_by_name(repo.id, branch_name) nr_commits := app.get_repo_commit_count(repo.id, branch.id) - return get_declension_form(nr_commits, 'Commit', 'Commits') + return get_declension_form(nr_commits, 'commit', 'commits') } fn (r &Repo) format_nr_branches() veb.RawHtml { - return get_declension_form(r.nr_branches, 'Branch', 'Branches') + return get_declension_form(r.nr_branches, 'branch', 'branches') } fn (r &Repo) format_nr_tags() veb.RawHtml { - return get_declension_form(r.nr_tags, 'Branch', 'Branches') + return get_declension_form(r.nr_tags, 'tag', 'tags') } fn (r &Repo) format_nr_open_prs() veb.RawHtml { - return get_declension_form(r.nr_open_prs, 'Pull request', 'Pull requests') + return get_declension_form(r.nr_open_prs, 'pull request', 'pull requests') } fn (r &Repo) format_nr_open_issues() veb.RawHtml { - return get_declension_form(r.nr_open_issues, 'Issue', 'Issues') + return get_declension_form(r.nr_open_issues, 'issue', 'issues') } fn (r &Repo) format_nr_contributors() veb.RawHtml { - return get_declension_form(r.nr_contributors, 'Contributor', 'Contributors') + return get_declension_form(r.nr_contributors, 'contributor', 'contributors') } fn (r &Repo) format_nr_topics() veb.RawHtml { @@ -42,5 +42,5 @@ fn (r &Repo) format_nr_topics() veb.RawHtml { } fn (r &Repo) format_nr_releases() veb.RawHtml { - return get_declension_form(r.nr_releases, 'Release', 'Releases') + return get_declension_form(r.nr_releases, 'release', 'releases') } diff --git a/settings.v b/settings.v index 7a4f098..d882033 100644 --- a/settings.v +++ b/settings.v @@ -5,8 +5,13 @@ module main struct Settings { id int @[primary; sql: serial] mut: - oauth_client_id string - oauth_client_secret string + oauth_client_id string + oauth_client_secret string + disable_tree_folder_size bool +} + +fn (s Settings) tree_folder_size_enabled() bool { + return !s.disable_tree_folder_size } fn (mut app App) load_settings() { @@ -21,7 +26,7 @@ fn (mut app App) load_settings() { } } -fn (mut app App) update_settings(oauth_client_id string, oauth_client_secret string) ! { +fn (mut app App) update_settings(oauth_client_id string, oauth_client_secret string, tree_folder_size_enabled bool) ! { settings_result := sql app.db { select from Settings limit 1 } or { [] } @@ -44,10 +49,13 @@ fn (mut app App) update_settings(oauth_client_id string, oauth_client_secret str old_settings.oauth_client_secret } + disable_tree_folder_size := !tree_folder_size_enabled + if old_settings.id == 0 { new_settings := Settings{ - oauth_client_id: github_oauth_client_id - oauth_client_secret: github_oauth_client_secret + oauth_client_id: github_oauth_client_id + oauth_client_secret: github_oauth_client_secret + disable_tree_folder_size: disable_tree_folder_size } sql app.db { @@ -55,8 +63,8 @@ fn (mut app App) update_settings(oauth_client_id string, oauth_client_secret str }! } else { sql app.db { - update Settings set oauth_client_id = github_oauth_client_id, oauth_client_secret = github_oauth_client_secret - where id == old_settings.id + update Settings set oauth_client_id = github_oauth_client_id, oauth_client_secret = github_oauth_client_secret, + disable_tree_folder_size = disable_tree_folder_size where id == old_settings.id }! } } diff --git a/static/assets/version b/static/assets/version index 2a4f6ba..61971c2 100644 --- a/static/assets/version +++ b/static/assets/version @@ -1 +1 @@ -17d5bf8 \ No newline at end of file +1fbeec1 \ No newline at end of file diff --git a/static/css/files.scss b/static/css/files.scss index d8f4679..66ac31b 100644 --- a/static/css/files.scss +++ b/static/css/files.scss @@ -69,13 +69,20 @@ } } +.files--with-size .file { + grid-template-columns: 20px minmax(150px, 25%) 90px 1fr 140px; +} + /* Responsive Grid for Mobile */ @media (max-width: 768px) { .file { grid-template-columns: 20px 1fr; gap: 5px; } - .file-msg, .file-time { display: none; } + .files--with-size .file { + grid-template-columns: 20px 1fr; + } + .file-msg, .file-size, .file-time { display: none; } } /* Icon */ @@ -124,6 +131,15 @@ } } +/* Folder size */ +.file-size { + color: #6a737d !important; + text-align: right; + font-size: 13px; + white-space: nowrap; + padding-right: 10px; +} + /* Time */ .file-time { color: #6a737d !important; diff --git a/static/css/langs.scss b/static/css/langs.scss index 28e674d..e98d6e0 100644 --- a/static/css/langs.scss +++ b/static/css/langs.scss @@ -1,17 +1,21 @@ .langs { - display: flex; - justify-content: space-around; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(145px, 1fr)); + align-items: center; + background: #ffffff; } .lang-stats-header { - border: 1px solid $gray; - border-radius: $medium-radius; - margin: 10px 0 10px 0; + border: 1px solid #d8dee4; + border-radius: 5px; + margin: 0 0 18px; overflow: hidden; // rounded corners } .lang-stats-bar { display: flex; + height: 5px; + div { height: 5px; } @@ -20,7 +24,10 @@ .lang-stat { display: flex; align-items: center; - margin: 9px 5px 7px 5px; + justify-content: center; + margin: 9px 6px 8px; + min-width: 0; + white-space: nowrap; } .lang-stat * { diff --git a/static/css/tree.scss b/static/css/tree.scss index 1864016..a818264 100644 --- a/static/css/tree.scss +++ b/static/css/tree.scss @@ -11,45 +11,64 @@ margin-bottom: 20px; } -/* 1. The Tab Bar (Issues, Contributors, etc.) */ +.repo-title-bar { + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0 6px; +} + +.repo-settings-link { + margin-left: 6px; + font-size: 13px; +} + +/* 1. The repo stats panel */ .repo-stats { + display: grid; + grid-template-columns: repeat(6, minmax(0, 1fr)); + align-items: center; + border: 1px solid #d8dee4; + border-radius: 5px; + background: #ffffff; + margin: 8px 0 10px; + min-height: 36px; + overflow: hidden; +} + +.repo-stat-item { display: flex; - border-bottom: 1px solid #e1e4e8; - margin-bottom: 20px; - margin-top: 10px; + align-items: center; + justify-content: center; + gap: 5px; + color: #111111 !important; + font-size: 14px !important; + font-weight: 600; + line-height: 20px; + min-width: 0; + padding: 7px 8px; + white-space: nowrap; - a.menu { - display: flex; - align-items: center; - padding: 8px 16px; - color: #24292e !important; - font-size: 14px; - border-bottom: 2px solid transparent; - transition: border-bottom 0.2s; - - &:hover { - border-bottom: 2px solid #d1d5da; - text-decoration: none; - } + b { + font-weight: 700; + } - /* Active state simulation */ - &.active { - border-bottom: 2px solid #f9826c; - font-weight: 600; - } + svg { + color: #111111; + flex: 0 0 auto; + height: 15px; + width: 15px; + } +} - svg { - margin-right: 8px; - fill: #959da5; - } +a.repo-stat-item:hover { + background: #f6f8fa; + text-decoration: none; +} - b { - margin-left: 5px; - background: rgba(209, 213, 218, 0.5); - padding: 0 6px; - border-radius: 20px; - font-size: 12px; - } +@media (max-width: 760px) { + .repo-stats { + grid-template-columns: repeat(2, minmax(0, 1fr)); } } @@ -110,27 +129,6 @@ background-size: 10px; } -/* Commits Link */ -.branch-specific-item { - a { - color: #586069 !important; - font-size: 13px !important; - font-weight: 600; - display: flex; - align-items: center; - - &:hover { - color: #0366d6 !important; - text-decoration: none; - } - - svg { - margin-right: 4px; - fill: #959da5; - } - } -} - /* --- Action Buttons (Code, Star, Watch) --- */ .repo-code-container { diff --git a/static/js/tree.js b/static/js/tree.js index 23f571a..a23d461 100644 --- a/static/js/tree.js +++ b/static/js/tree.js @@ -30,26 +30,30 @@ async function starRepo(repoId) { } } -starButtonEl.addEventListener("click", () => { - starRepo(REPO_ID) - .then(() => { - location.reload() - }) - .catch((error) => { - alert(error.toString()); - }) -}); +if (starButtonEl) { + starButtonEl.addEventListener("click", () => { + starRepo(REPO_ID) + .then(() => { + location.reload() + }) + .catch((error) => { + alert(error.toString()); + }) + }); +} const copyCloneURLButton = document.querySelector(".copy-clone-url-button"); -copyCloneURLButton.addEventListener("click", async () => { - const url = document.querySelector(".clone-input-group > input").value; +if (copyCloneURLButton) { + copyCloneURLButton.addEventListener("click", async () => { + const url = document.querySelector(".clone-input-group > input").value; - if (navigator && navigator.clipboard && navigator.clipboard.writeText) { - return navigator.clipboard.writeText(url); - } + if (navigator && navigator.clipboard && navigator.clipboard.writeText) { + return navigator.clipboard.writeText(url); + } - alert("The Clipboard API is not available."); -}); + alert("The Clipboard API is not available."); + }); +} const watchButtonEl = document.querySelector(".watch-button"); @@ -67,25 +71,41 @@ async function watchRepo(repoId) { } } -watchButtonEl.addEventListener("click", () => { - watchRepo(REPO_ID) - .then(() => { - location.reload() - }) - .catch((error) => { - alert(error.toString()); - }) -}); +if (watchButtonEl) { + watchButtonEl.addEventListener("click", () => { + watchRepo(REPO_ID) + .then(() => { + location.reload() + }) + .catch((error) => { + alert(error.toString()); + }) + }); +} // Poll for file commit info (last_msg, last_hash, last_time) that may still be loading (function() { - // Check if any file rows are missing commit info + function findDataEl(attr, value) { + const els = document.querySelectorAll("[" + attr + "]"); + for (const el of els) { + if (el.getAttribute(attr) === value) return el; + } + return null; + } + + // Check if any file rows are missing delayed info function hasMissingInfo() { const msgEls = document.querySelectorAll("[data-msg-for]"); for (const el of msgEls) { const link = el.querySelector("a"); if (!link || link.textContent.trim() === "") return true; } + if (TREE_FOLDER_SIZE_ENABLED) { + const sizeEls = document.querySelectorAll("[data-size-for]"); + for (const el of sizeEls) { + if (el.textContent.trim() === "") return true; + } + } return false; } @@ -107,21 +127,28 @@ watchButtonEl.addEventListener("click", () => { let stillMissing = false; for (const file of data.result) { - if (!file.last_msg) { + const sizeEl = TREE_FOLDER_SIZE_ENABLED ? findDataEl("data-size-for", file.name) : null; + if (!file.last_msg || (sizeEl && !file.size)) { stillMissing = true; - continue; } - const msgEl = document.querySelector('[data-msg-for="' + file.name + '"]'); - if (msgEl) { - const link = msgEl.querySelector("a"); - if (link && link.textContent.trim() === "") { - link.textContent = file.last_msg; - if (file.last_hash) { - link.href = "/" + REPO_USER + "/" + REPO_NAME + "/commit/" + file.last_hash; + if (file.last_msg) { + const msgEl = findDataEl("data-msg-for", file.name); + if (msgEl) { + const link = msgEl.querySelector("a"); + if (link && link.textContent.trim() === "") { + link.textContent = file.last_msg; + if (file.last_hash) { + link.href = "/" + REPO_USER + "/" + REPO_NAME + "/commit/" + file.last_hash; + } } } } - const timeEl = document.querySelector('[data-time-for="' + file.name + '"]'); + if (sizeEl && file.size) { + if (sizeEl && sizeEl.textContent.trim() === "") { + sizeEl.textContent = file.size; + } + } + const timeEl = findDataEl("data-time-for", file.name); if (timeEl && timeEl.textContent.trim() === "" && file.last_time) { timeEl.textContent = file.last_time; } diff --git a/templates/admin/settings.html b/templates/admin/settings.html index c2b1140..2a4d194 100644 --- a/templates/admin/settings.html +++ b/templates/admin/settings.html @@ -26,6 +26,14 @@ +
+ + +
diff --git a/templates/layout/repo_menu.html b/templates/layout/repo_menu.html index d08838e..0c87b99 100644 --- a/templates/layout/repo_menu.html +++ b/templates/layout/repo_menu.html @@ -1,4 +1,4 @@ -
+
@if repo.user_name != '' @repo.user_name

/

@@ -10,36 +10,37 @@ @else Private @end + + @if repo.user_id == ctx.user.id + + Settings + + @end
diff --git a/templates/tree.html b/templates/tree.html index 7fa2a94..274d6b8 100644 --- a/templates/tree.html +++ b/templates/tree.html @@ -14,6 +14,7 @@ const CURRENT_PATH = "@ctx.current_path"; const REPO_USER = "@repo.user_name"; const REPO_NAME = "@repo.name"; + const TREE_FOLDER_SIZE_ENABLED = "@{show_folder_size}" === "true";
@@ -118,7 +119,11 @@ @end @if true || has_commits - .files { + @if show_folder_size +
+ @else +
+ @end .last_commit { @last_commit.author span.last_commit_message { @@ -143,6 +148,9 @@ span.file-name { .. } + @if show_folder_size + + @end } @end @for file in items @@ -157,6 +165,15 @@ span.file-name { @file.name } + @if show_folder_size + @if file.is_dir + + @file.pretty_tree_size() + + @else + + @end + @end @file.format_commit_message() @@ -165,7 +182,7 @@
@end - } +
@if readme.len > 0
-- 2.39.5