| 1 | <% content_for :title, "#{@filename} · #{@repository.full_name}" %> |
| 2 | <%= render "shared/repository_social", repository: @repository %> |
| 3 | |
| 4 | <div class="border-b border-surface-600 bg-surface-800"> |
| 5 | <div class="max-w-6xl mx-auto px-4 sm:px-6 pt-6 pb-0"> |
| 6 | <div class="flex items-center gap-2 text-sm mb-4"> |
| 7 | <%= link_to "@#{@owner.username}", user_profile_path(@owner.username), class: "text-brand-500 hover:underline font-medium" %> |
| 8 | <span class="text-gray-500">/</span> |
| 9 | <%= link_to @repository.name, repository_path(@owner.username, @repository.name), class: "text-brand-500 hover:underline font-semibold" %> |
| 10 | </div> |
| 11 | <nav class="flex items-center gap-1.5 text-sm mb-4 flex-wrap"> |
| 12 | <%= link_to @repository.name, repository_path(@owner.username, @repository.name), class: "breadcrumb-item font-medium" %> |
| 13 | <span class="text-gray-500">/</span> |
| 14 | <% @path_parts[0..-2].each_with_index do |part, i| %> |
| 15 | <% partial_path = @path_parts[0..i].join("/") %> |
| 16 | <%= link_to part, repository_tree_path(@owner.username, @repository.name, @branch, partial_path), class: "breadcrumb-item" %> |
| 17 | <span class="text-gray-500">/</span> |
| 18 | <% end %> |
| 19 | <span class="font-medium text-gray-100"><%= @filename %></span> |
| 20 | </nav> |
| 21 | <div class="flex items-center gap-0 -mb-px"> |
| 22 | <%= link_to repository_path(@owner.username, @repository.name), class: "tab-item active flex items-center gap-1.5" do %> |
| 23 | <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> |
| 24 | <path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8Z"/> |
| 25 | </svg> |
| 26 | Code |
| 27 | <% end %> |
| 28 | <%= link_to repository_commits_path(@owner.username, @repository.name, @branch), |
| 29 | class: "tab-item flex items-center gap-1.5" do %> |
| 30 | <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> |
| 31 | <path d="M11.93 8.5a4.002 4.002 0 0 1-7.86 0H.75a.75.75 0 0 1 0-1.5h3.32a4.002 4.002 0 0 1 7.86 0h3.32a.75.75 0 0 1 0 1.5Zm-1.43-.75a2.5 2.5 0 1 0-5 0 2.5 2.5 0 0 0 5 0Z"/> |
| 32 | </svg> |
| 33 | Commits |
| 34 | <% end %> |
| 35 | <%= link_to repository_pull_requests_path(@owner.username, @repository.name), |
| 36 | class: "tab-item flex items-center gap-1.5" do %> |
| 37 | <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> |
| 38 | <path d="M1.5 3.25a2.25 2.25 0 1 1 3 2.122v5.256a2.251 2.251 0 1 1-1.5 0V5.372A2.25 2.25 0 0 1 1.5 3.25Zm5.677-.177L9.573.677A.25.25 0 0 1 10 .854V2.5h1A2.5 2.5 0 0 1 13.5 5v5.628a2.251 2.251 0 1 1-1.5 0V5a1 1 0 0 0-1-1h-1v1.646a.25.25 0 0 1-.427.177L7.177 3.427a.25.25 0 0 1 0-.354ZM3.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Zm0 9.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5ZM12 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5Z"/> |
| 39 | </svg> |
| 40 | Pulls |
| 41 | <% if @repository.open_pull_requests_count > 0 %> |
| 42 | <span class="badge-gray text-xs"><%= number_with_delimiter(@repository.open_pull_requests_count) %></span> |
| 43 | <% end %> |
| 44 | <% end %> |
| 45 | <%= link_to repository_cicd_path(@owner.username, @repository.name), |
| 46 | class: "tab-item flex items-center gap-1.5" do %> |
| 47 | <svg class="w-4 h-4" viewBox="0 0 16 16" fill="currentColor"> |
| 48 | <path d="M4.75 4.5C2.679 4.5 1 5.958 1 7.75S2.679 11 4.75 11c1.028 0 1.948-.36 2.75-1.242l.652-.716.696.672C10.023 10.849 10.956 11 11.25 11 13.321 11 15 9.542 15 7.75S13.321 4.5 11.25 4.5c-1.028 0-1.948.36-2.75 1.242l-.652.716-.696-.672C5.977 4.651 5.044 4.5 4.75 4.5Zm0 1.5c.483 0 .943.152 1.36.556l.562.541-.562.618C5.693 8.119 5.233 8.5 4.75 8.5c-1.241 0-2.25-.672-2.25-1.5S3.509 6 4.75 6Zm6.5 0c1.241 0 2.25.672 2.25 1.5S12.491 9 11.25 9c-.483 0-.943-.152-1.36-.556l-.562-.541.562-.618c.417-.404.877-.785 1.36-.785Z"/> |
| 49 | </svg> |
| 50 | CI/CD |
| 51 | <% if @commit_count&.> 0 %> |
| 52 | <span class="badge-gray text-xs"><%= number_with_delimiter(@commit_count) %></span> |
| 53 | <% end %> |
| 54 | <% end %> |
| 55 | </div> |
| 56 | </div> |
| 57 | </div> |
| 58 | |
| 59 | <div class="max-w-6xl mx-auto px-4 sm:px-6 py-6"> |
| 60 | <% permalink_path = @commit_sha ? repository_blob_path(@owner.username, @repository.name, @commit_sha, @file_path) : nil %> |
| 61 | <div class="card" data-controller="clipboard line-selection" |
| 62 | <% if permalink_path %>data-line-selection-permalink-base-value="<%= permalink_path %>"<% end %>> |
| 63 | <div class="px-4 py-2.5 border-b border-surface-600 flex items-center justify-between gap-3 bg-surface-600"> |
| 64 | <div class="flex items-center gap-3 text-xs text-gray-400"> |
| 65 | <%= render "shared/branch_switcher", |
| 66 | branches: @branches, |
| 67 | current_branch: @branch, |
| 68 | branch_url: ->(b) { repository_blob_path(@owner.username, @repository.name, b, @file_path) } %> |
| 69 | <span class="font-mono badge-gray"><%= @extension.presence || "text" %></span> |
| 70 | <% if @line_count %> |
| 71 | <span><%= number_with_delimiter(@line_count) %> lines</span> |
| 72 | <% end %> |
| 73 | <span><%= number_to_human_size(@file_size) %></span> |
| 74 | </div> |
| 75 | <div class="flex items-center gap-2"> |
| 76 | <% if @markdown_html %> |
| 77 | <%= link_to "View source", repository_blob_path(@owner.username, @repository.name, @branch, @file_path, plain: 1), |
| 78 | class: "btn-ghost text-xs py-1 px-2.5" %> |
| 79 | <% elsif @plain && BlobsController::MARKDOWN_EXTENSIONS.include?(@extension) %> |
| 80 | <%= link_to "Rendered", repository_blob_path(@owner.username, @repository.name, @branch, @file_path), |
| 81 | class: "btn-ghost text-xs py-1 px-2.5" %> |
| 82 | <% end %> |
| 83 | <% if @highlighted_lines && permalink_path %> |
| 84 | <button type="button" data-action="line-selection#copyPermalink" |
| 85 | class="btn-ghost text-xs py-1 px-2.5">Copy permalink</button> |
| 86 | <button type="button" data-action="clipboard#copy" |
| 87 | class="btn-ghost text-xs py-1 px-2.5">Copy</button> |
| 88 | <% end %> |
| 89 | <%= link_to "Raw", @raw_path, class: "btn-ghost text-xs py-1 px-2.5", target: "_blank", rel: "noopener" %> |
| 90 | </div> |
| 91 | </div> |
| 92 | |
| 93 | <% if @too_large %> |
| 94 | <div class="px-6 py-10 text-center text-sm text-gray-400"> |
| 95 | This file is <%= number_to_human_size(@file_size) %> — too large to display. |
| 96 | <div class="mt-4"> |
| 97 | <%= link_to "View raw", @raw_path, class: "btn-secondary text-xs py-1 px-3", target: "_blank", rel: "noopener" %> |
| 98 | </div> |
| 99 | </div> |
| 100 | <% elsif @image_type %> |
| 101 | <div class="px-6 py-10 flex justify-center bg-surface-800"> |
| 102 | <img src="<%= @image_data_uri %>" alt="<%= @filename %>" |
| 103 | class="max-w-full h-auto rounded border border-surface-600" /> |
| 104 | </div> |
| 105 | <% elsif @is_binary %> |
| 106 | <div class="px-6 py-10 text-center text-sm text-gray-400"> |
| 107 | Binary file — <%= number_to_human_size(@file_size) %> |
| 108 | <div class="mt-4"> |
| 109 | <%= link_to "View raw", @raw_path, class: "btn-secondary text-xs py-1 px-3", target: "_blank", rel: "noopener" %> |
| 110 | </div> |
| 111 | </div> |
| 112 | <% elsif @markdown_html %> |
| 113 | <div class="px-6 py-6 prose-readme" data-controller="code-copy"><%= @markdown_html %></div> |
| 114 | <% else %> |
| 115 | <% if @highlight_skipped %> |
| 116 | <div class="px-4 py-2 text-xs text-amber-300/80 bg-amber-900/10 border-b border-surface-600"> |
| 117 | Large file — syntax highlighting disabled. |
| 118 | </div> |
| 119 | <% end %> |
| 120 | <div class="code-container rounded-none border-0 relative overflow-x-auto"> |
| 121 | <table class="w-full"> |
| 122 | <tbody class="highlight"> |
| 123 | <% @highlighted_lines.each_with_index do |highlighted_line, i| %> |
| 124 | <% n = i + 1 %> |
| 125 | <tr id="L<%= n %>" data-line="<%= n %>" data-line-selection-target="row" class="line-row"> |
| 126 | <td class="line-number text-right text-gray-500 pr-4 pl-4 py-0 select-none w-10 text-xs border-r border-surface-600 align-top font-mono"> |
| 127 | <a href="#L<%= n %>" data-action="line-selection#select" |
| 128 | data-line-selection-line-param="<%= n %>" class="hover:text-brand-500"><%= n %></a> |
| 129 | </td> |
| 130 | <td data-clipboard-target="source" class="pl-4 pr-4 py-0 font-mono text-xs leading-5 whitespace-pre text-gray-200"><%= highlighted_line %></td> |
| 131 | </tr> |
| 132 | <% end %> |
| 133 | </tbody> |
| 134 | </table> |
| 135 | </div> |
| 136 | <% if @truncated %> |
| 137 | <div class="px-4 py-3 text-xs text-gray-400 border-t border-surface-600 text-center"> |
| 138 | Showing first <%= number_with_delimiter(@highlighted_lines.length) %> of <%= number_with_delimiter(@line_count) %> lines. |
| 139 | <%= link_to "View raw", @raw_path, class: "text-brand-500 hover:underline", target: "_blank", rel: "noopener" %> |
| 140 | </div> |
| 141 | <% end %> |
| 142 | <% end %> |
| 143 | </div> |
| 144 | </div> |