Add filetree on left of diff view (#21012)
This PR adds a filetree to the left side of the files/diff view. Initially the filetree will not be shown and may be shown via a new "Show file tree" button. Showing and hiding is using the same icon as github. Folders are collapsible. On small devices (max-width 991 PX) the file tree will be hidden. Close #18192 Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		
							parent
							
								
									525751243e
								
							
						
					
					
						commit
						31f934c1d8
					
				| @ -1,7 +1,7 @@ | ||||
| {{template "base/head" .}} | ||||
| <div class="page-content repository diff"> | ||||
| 	{{template "repo/header" .}} | ||||
| 	<div class="ui container {{if .IsSplitStyle}}fluid padded{{end}}"> | ||||
| 	<div class="ui container fluid padded"> | ||||
| 		{{$class := ""}} | ||||
| 		{{if .Commit.Signature}} | ||||
| 			{{$class = (printf "%s%s" $class " isSigned")}} | ||||
|  | ||||
| @ -14,6 +14,11 @@ | ||||
| {{else}} | ||||
| 	<div> | ||||
| 		<div class="diff-detail-box diff-box sticky df sb ac fw"> | ||||
| 			<a class="diff-toggle-file-tree-button"> | ||||
| 				{{/* the icon meaning is reversed here, "octicon-sidebar-collapse" means show the file tree */}} | ||||
| 				{{svg "octicon-sidebar-collapse" 16 "icon hide"}} | ||||
| 				{{svg "octicon-sidebar-expand" 16 "icon"}} | ||||
| 			</a> | ||||
| 			<div class="diff-detail-stats df ac"> | ||||
| 				{{svg "octicon-diff" 16 "mr-2"}}{{.locale.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}} | ||||
| 			</div> | ||||
| @ -31,145 +36,151 @@ | ||||
| 				{{end}} | ||||
| 			</div> | ||||
| 		</div> | ||||
| 		<ol class="diff-detail-box diff-stats m-0 hide" id="diff-files"> | ||||
| 			{{range .Diff.Files}} | ||||
| 				<li> | ||||
| 					<div class="bold df ac pull-right"> | ||||
| 						{{if .IsBin}} | ||||
| 							<span class="ml-1 mr-3"> | ||||
| 								{{$.locale.Tr "repo.diff.bin"}} | ||||
| 							</span> | ||||
| 						{{else}} | ||||
| 							{{template "repo/diff/stats" dict "file" . "root" $}} | ||||
| 						{{end}} | ||||
| 					</div> | ||||
| 					<!-- todo finish all file status, now modify, add, delete and rename --> | ||||
| 					<span class="status {{DiffTypeToStr .GetType}} tooltip" data-content="{{DiffTypeToStr .GetType}}" data-position="right center"> </span> | ||||
| 					<a class="file mono" href="#diff-{{.NameHash}}">{{.Name}}</a> | ||||
| 				</li> | ||||
| 			{{end}} | ||||
| 			{{if .Diff.IsIncomplete}} | ||||
| 				<li id="diff-too-many-files-stats" class="pt-2"> | ||||
| 					<span class="file df ac sb">{{$.locale.Tr "repo.diff.too_many_files"}} | ||||
| 						<a class="ui basic tiny button" id="diff-show-more-files-stats" data-href="{{$.Link}}?skip-to={{.Diff.End}}&file-only=true">{{.locale.Tr "repo.diff.show_more"}}</a> | ||||
| 					</span> | ||||
| 				</li> | ||||
| 			{{end}} | ||||
| 		</ol> | ||||
| 		<div id="diff-file-boxes"> | ||||
| 			{{range $file := .Diff.Files}} | ||||
| 				{{/*notice: the index of Diff.Files should not be used for element ID, because the index will be restarted from 0 when doing load-more for PRs with a lot of files*/}} | ||||
| 				{{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}} | ||||
| 				{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}} | ||||
| 				{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}} | ||||
| 				{{$isCsv := (call $.IsCsvFile $file)}} | ||||
| 				{{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}} | ||||
| 				<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} mt-3" id="diff-{{$file.NameHash}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if $file.ShouldBeHidden}}data-folded="true"{{end}}> | ||||
| 					<h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb"> | ||||
| 						<div class="df ac"> | ||||
| 							<a role="button" class="fold-file muted mr-2"> | ||||
| 								{{if $file.ShouldBeHidden}} | ||||
| 									{{svg "octicon-chevron-right" 18}} | ||||
| 								{{else}} | ||||
| 									{{svg "octicon-chevron-down" 18}} | ||||
| 								{{end}} | ||||
| 							</a> | ||||
| 							<div class="bold df ac"> | ||||
| 								{{if $file.IsBin}} | ||||
| 									<span class="ml-1 mr-3"> | ||||
| 										{{$.locale.Tr "repo.diff.bin"}} | ||||
| 									</span> | ||||
| 								{{else}} | ||||
| 									{{template "repo/diff/stats" dict "file" . "root" $}} | ||||
| 								{{end}} | ||||
| 							</div> | ||||
| 							<span class="file mono"><a class="muted" href="#diff-{{$file.NameHash}}">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}</a>{{if .IsLFSFile}} ({{$.locale.Tr "repo.stored_lfs"}}){{end}}</span> | ||||
| 							{{if $file.IsGenerated}} | ||||
| 								<span class="ui label ml-3">{{$.locale.Tr "repo.diff.generated"}}</span> | ||||
| 							{{end}} | ||||
| 							{{if $file.IsVendored}} | ||||
| 								<span class="ui label ml-3">{{$.locale.Tr "repo.diff.vendored"}}</span> | ||||
| 							{{end}} | ||||
| 						</div> | ||||
| 						<div class="diff-file-header-actions df ac"> | ||||
| 							{{if $showFileViewToggle}} | ||||
| 								<div class="ui compact icon buttons"> | ||||
| 									<span class="ui tiny basic button tooltip file-view-toggle" data-toggle-selector="#diff-source-{{$file.NameHash}}" data-content="{{$.locale.Tr "repo.file_view_source"}}" data-position="bottom center">{{svg "octicon-code"}}</span> | ||||
| 									<span class="ui tiny basic button tooltip file-view-toggle active" data-toggle-selector="#diff-rendered-{{$file.NameHash}}" data-content="{{$.locale.Tr "repo.file_view_rendered"}}" data-position="bottom center">{{svg "octicon-file"}}</span> | ||||
| 								</div> | ||||
| 							{{end}} | ||||
| 							{{if $file.IsProtected}} | ||||
| 								<span class="ui basic label">{{$.locale.Tr "repo.diff.protected"}}</span> | ||||
| 							{{end}} | ||||
| 							{{if not (or $file.IsIncomplete $file.IsBin $file.IsSubmodule)}} | ||||
| 								<a class="ui basic tiny button unescape-button">{{$.locale.Tr "repo.unescape_control_characters"}}</a> | ||||
| 								<a class="ui basic tiny button escape-button" style="display: none;">{{$.locale.Tr "repo.escape_control_characters"}}</a> | ||||
| 							{{end}} | ||||
| 							{{if and (not $file.IsSubmodule) (not $.PageIsWiki)}} | ||||
| 								{{if $file.IsDeleted}} | ||||
| 									<a class="ui basic tiny button" rel="nofollow" href="{{$.BeforeSourcePath}}/{{PathEscapeSegments .Name}}">{{$.locale.Tr "repo.diff.view_file"}}</a> | ||||
| 								{{else}} | ||||
| 									<a class="ui basic tiny button" rel="nofollow" href="{{$.SourcePath}}/{{PathEscapeSegments .Name}}">{{$.locale.Tr "repo.diff.view_file"}}</a> | ||||
| 								{{end}} | ||||
| 							{{end}} | ||||
| 							{{if and $.IsSigned $.PageIsPullFiles (not $.IsArchived)}} | ||||
| 								{{if $file.HasChangedSinceLastReview}} | ||||
| 									<span class="changed-since-last-review unselectable">{{$.locale.Tr "repo.pulls.has_changed_since_last_review"}}</span> | ||||
| 								{{end}} | ||||
| 								<label data-link="{{$.Issue.Link}}/viewed-files" data-headcommit="{{$.PullHeadCommitID}}" class="viewed-file-form unselectable{{if $file.IsViewed}} viewed-file-checked-form{{end}}"> | ||||
| 									<input type="checkbox" name="{{$file.GetDiffFileName}}" autocomplete="off"{{if $file.IsViewed}} checked{{end}}> {{$.locale.Tr "repo.pulls.has_viewed_file"}} | ||||
| 								</label> | ||||
| 							{{end}} | ||||
| 						</div> | ||||
| 					</h4> | ||||
| 					<div class="diff-file-body ui attached unstackable table segment" {{if $file.IsViewed}}data-folded="true"{{end}}> | ||||
| 						<div id="diff-source-{{$file.NameHash}}" class="file-body file-code unicode-escaped code-diff{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $showFileViewToggle}} hide{{end}}"> | ||||
| 							{{if or $file.IsIncomplete $file.IsBin}} | ||||
| 								<div class="diff-file-body binary" style="padding: 5px 10px;"> | ||||
| 									{{if $file.IsIncomplete}} | ||||
| 										{{if $file.IsIncompleteLineTooLong}} | ||||
| 											{{$.locale.Tr "repo.diff.file_suppressed_line_too_long"}} | ||||
| 		<script id="diff-data-script"> | ||||
| 				(() => { | ||||
| 					const diffData = { | ||||
| 						files: [{{range $i, $file := .Diff.Files}}{Name:"{{$file.Name}}",NameHash:"{{$file.NameHash}}",Type:{{$file.Type}},IsBin:{{$file.IsBin}},Addition:{{$file.Addition}},Deletion:{{$file.Deletion}}},{{end}}], | ||||
| 						isIncomplete: {{.Diff.IsIncomplete}}, | ||||
| 						tooManyFilesMessage: "{{$.locale.Tr "repo.diff.too_many_files"}}", | ||||
| 						binaryFileMessage: "{{$.locale.Tr "repo.diff.bin"}}", | ||||
| 						showMoreMessage: "{{.locale.Tr "repo.diff.show_more"}}", | ||||
| 						statisticsMessage: "{{.locale.Tr "repo.diff.stats_desc_file"}}", | ||||
| 						fileTreeIsVisible: false, | ||||
| 						fileListIsVisible: false, | ||||
| 						isLoadingNewData: false, | ||||
| 						diffEnd: {{.Diff.End}}, | ||||
| 						link: "{{$.Link}}" | ||||
| 					}; | ||||
| 					if(window.config.pageData.diffFileInfo) { | ||||
| 						// Page is already loaded - add the data to our existing data | ||||
| 						window.config.pageData.diffFileInfo.files.push(...diffData.files); | ||||
| 						window.config.pageData.diffFileInfo.isIncomplete = diffData.isIncomplete; | ||||
| 						window.config.pageData.diffFileInfo.diffEnd = diffData.diffEnd; | ||||
| 						window.config.pageData.diffFileInfo.link = diffData.link; | ||||
| 					} else { | ||||
| 						// new load of page - populate initial data | ||||
| 						window.config.pageData.diffFileInfo = diffData; | ||||
| 					} | ||||
| 				})(); | ||||
| 				</script> | ||||
| 		<div id="diff-file-list-container"></div> | ||||
| 		<div id="diff-container"> | ||||
| 				<div id="diff-file-tree-container"></div> | ||||
| 				<div id="diff-file-boxes" class="sixteen wide column"> | ||||
| 					{{range $i, $file := .Diff.Files}} | ||||
| 						{{/*notice: the index of Diff.Files should not be used for element ID, because the index will be restarted from 0 when doing load-more for PRs with a lot of files*/}} | ||||
| 						{{$blobBase := call $.GetBlobByPathForCommit $.BaseCommit $file.OldName}} | ||||
| 						{{$blobHead := call $.GetBlobByPathForCommit $.HeadCommit $file.Name}} | ||||
| 						{{$isImage := or (call $.IsBlobAnImage $blobBase) (call $.IsBlobAnImage $blobHead)}} | ||||
| 						{{$isCsv := (call $.IsCsvFile $file)}} | ||||
| 						{{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}} | ||||
| 						<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} mt-3" id="diff-{{$file.NameHash}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if $file.ShouldBeHidden}}data-folded="true"{{end}}> | ||||
| 							<h4 class="diff-file-header sticky-2nd-row ui top attached normal header df ac sb"> | ||||
| 								<div class="df ac"> | ||||
| 									<a role="button" class="fold-file muted mr-2"> | ||||
| 										{{if $file.ShouldBeHidden}} | ||||
| 											{{svg "octicon-chevron-right" 18}} | ||||
| 										{{else}} | ||||
| 											{{$.locale.Tr "repo.diff.file_suppressed"}} | ||||
| 											<a class="ui basic tiny button diff-show-more-button" data-href="{{$.Link}}?file-only=true&files={{$file.Name}}&files={{$file.OldName}}">{{$.locale.Tr "repo.diff.load"}}</a> | ||||
| 											{{svg "octicon-chevron-down" 18}} | ||||
| 										{{end}} | ||||
| 									{{else}} | ||||
| 										{{$.locale.Tr "repo.diff.bin_not_shown"}} | ||||
| 									</a> | ||||
| 									<div class="bold df ac"> | ||||
| 										{{if $file.IsBin}} | ||||
| 											<span class="ml-1 mr-3"> | ||||
| 												{{$.locale.Tr "repo.diff.bin"}} | ||||
| 											</span> | ||||
| 										{{else}} | ||||
| 											{{template "repo/diff/stats" dict "file" . "root" $}} | ||||
| 										{{end}} | ||||
| 									</div> | ||||
| 									<span class="file mono"><a class="muted" href="#diff-{{$file.NameHash}}">{{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}</a>{{if .IsLFSFile}} ({{$.locale.Tr "repo.stored_lfs"}}){{end}}</span> | ||||
| 									{{if $file.IsGenerated}} | ||||
| 										<span class="ui label ml-3">{{$.locale.Tr "repo.diff.generated"}}</span> | ||||
| 									{{end}} | ||||
| 									{{if $file.IsVendored}} | ||||
| 										<span class="ui label ml-3">{{$.locale.Tr "repo.diff.vendored"}}</span> | ||||
| 									{{end}} | ||||
| 								</div> | ||||
| 							{{else}} | ||||
| 								<table class="chroma" data-new-comment-url="{{$.Issue.HTMLURL}}/files/reviews/new_comment" data-path="{{$file.Name}}"> | ||||
| 									{{if $.IsSplitStyle}} | ||||
| 										{{template "repo/diff/section_split" dict "file" . "root" $}} | ||||
| 									{{else}} | ||||
| 										{{template "repo/diff/section_unified" dict "file" . "root" $}} | ||||
| 								<div class="diff-file-header-actions df ac"> | ||||
| 									{{if $showFileViewToggle}} | ||||
| 										<div class="ui compact icon buttons"> | ||||
| 											<span class="ui tiny basic button tooltip file-view-toggle" data-toggle-selector="#diff-source-{{$file.NameHash}}" data-content="{{$.locale.Tr "repo.file_view_source"}}" data-position="bottom center">{{svg "octicon-code"}}</span> | ||||
| 											<span class="ui tiny basic button tooltip file-view-toggle active" data-toggle-selector="#diff-rendered-{{$file.NameHash}}" data-content="{{$.locale.Tr "repo.file_view_rendered"}}" data-position="bottom center">{{svg "octicon-file"}}</span> | ||||
| 										</div> | ||||
| 									{{end}} | ||||
| 								</table> | ||||
| 							{{end}} | ||||
| 						</div> | ||||
| 						{{if $showFileViewToggle}} | ||||
| 							<div id="diff-rendered-{{$file.NameHash}}" class="file-body file-code {{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}"> | ||||
| 								<table class="chroma w-100"> | ||||
| 									{{if $isImage}} | ||||
| 										{{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}} | ||||
| 									{{else}} | ||||
| 										{{template "repo/diff/csv_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}} | ||||
| 									{{if $file.IsProtected}} | ||||
| 										<span class="ui basic label">{{$.locale.Tr "repo.diff.protected"}}</span> | ||||
| 									{{end}} | ||||
| 								</table> | ||||
| 									{{if not (or $file.IsIncomplete $file.IsBin $file.IsSubmodule)}} | ||||
| 										<a class="ui basic tiny button unescape-button">{{$.locale.Tr "repo.unescape_control_characters"}}</a> | ||||
| 										<a class="ui basic tiny button escape-button" style="display: none;">{{$.locale.Tr "repo.escape_control_characters"}}</a> | ||||
| 									{{end}} | ||||
| 									{{if and (not $file.IsSubmodule) (not $.PageIsWiki)}} | ||||
| 										{{if $file.IsDeleted}} | ||||
| 											<a class="ui basic tiny button" rel="nofollow" href="{{$.BeforeSourcePath}}/{{PathEscapeSegments .Name}}">{{$.locale.Tr "repo.diff.view_file"}}</a> | ||||
| 										{{else}} | ||||
| 											<a class="ui basic tiny button" rel="nofollow" href="{{$.SourcePath}}/{{PathEscapeSegments .Name}}">{{$.locale.Tr "repo.diff.view_file"}}</a> | ||||
| 										{{end}} | ||||
| 									{{end}} | ||||
| 									{{if and $.IsSigned $.PageIsPullFiles (not $.IsArchived)}} | ||||
| 										{{if $file.HasChangedSinceLastReview}} | ||||
| 											<span class="changed-since-last-review unselectable">{{$.locale.Tr "repo.pulls.has_changed_since_last_review"}}</span> | ||||
| 										{{end}} | ||||
| 										<label data-link="{{$.Issue.Link}}/viewed-files" data-headcommit="{{$.PullHeadCommitID}}" class="viewed-file-form unselectable{{if $file.IsViewed}} viewed-file-checked-form{{end}}"> | ||||
| 											<input type="checkbox" name="{{$file.GetDiffFileName}}" autocomplete="off"{{if $file.IsViewed}} checked{{end}}> {{$.locale.Tr "repo.pulls.has_viewed_file"}} | ||||
| 										</label> | ||||
| 									{{end}} | ||||
| 								</div> | ||||
| 							</h4> | ||||
| 							<div class="diff-file-body ui attached unstackable table segment" {{if $file.IsViewed}}data-folded="true"{{end}}> | ||||
| 								<div id="diff-source-{{$file.NameHash}}" class="file-body file-code unicode-escaped code-diff{{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}{{if $showFileViewToggle}} hide{{end}}"> | ||||
| 									{{if or $file.IsIncomplete $file.IsBin}} | ||||
| 										<div class="diff-file-body binary" style="padding: 5px 10px;"> | ||||
| 											{{if $file.IsIncomplete}} | ||||
| 												{{if $file.IsIncompleteLineTooLong}} | ||||
| 													{{$.locale.Tr "repo.diff.file_suppressed_line_too_long"}} | ||||
| 												{{else}} | ||||
| 													{{$.locale.Tr "repo.diff.file_suppressed"}} | ||||
| 													<a class="ui basic tiny button diff-show-more-button" data-href="{{$.Link}}?file-only=true&files={{$file.Name}}&files={{$file.OldName}}">{{$.locale.Tr "repo.diff.load"}}</a> | ||||
| 												{{end}} | ||||
| 											{{else}} | ||||
| 												{{$.locale.Tr "repo.diff.bin_not_shown"}} | ||||
| 											{{end}} | ||||
| 										</div> | ||||
| 									{{else}} | ||||
| 										<table class="chroma" data-new-comment-url="{{$.Issue.HTMLURL}}/files/reviews/new_comment" data-path="{{$file.Name}}"> | ||||
| 											{{if $.IsSplitStyle}} | ||||
| 												{{template "repo/diff/section_split" dict "file" . "root" $}} | ||||
| 											{{else}} | ||||
| 												{{template "repo/diff/section_unified" dict "file" . "root" $}} | ||||
| 											{{end}} | ||||
| 										</table> | ||||
| 									{{end}} | ||||
| 								</div> | ||||
| 								{{if $showFileViewToggle}} | ||||
| 									<div id="diff-rendered-{{$file.NameHash}}" class="file-body file-code {{if $.IsSplitStyle}} code-diff-split{{else}} code-diff-unified{{end}}"> | ||||
| 										<table class="chroma w-100"> | ||||
| 											{{if $isImage}} | ||||
| 												{{template "repo/diff/image_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}} | ||||
| 											{{else}} | ||||
| 												{{template "repo/diff/csv_diff" dict "file" . "root" $ "blobBase" $blobBase "blobHead" $blobHead}} | ||||
| 											{{end}} | ||||
| 										</table> | ||||
| 									</div> | ||||
| 								{{end}} | ||||
| 							</div> | ||||
| 						{{end}} | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			{{end}} | ||||
| 						</div> | ||||
| 					{{end}} | ||||
| 
 | ||||
| 			{{if .Diff.IsIncomplete}} | ||||
| 				<div class="diff-file-box diff-box file-content mt-3" id="diff-incomplete"> | ||||
| 					<h4 class="ui top attached normal header df ac sb"> | ||||
| 						{{$.locale.Tr "repo.diff.too_many_files"}} | ||||
| 						<a class="ui basic tiny button" id="diff-show-more-files" data-href="{{$.Link}}?skip-to={{.Diff.End}}&file-only=true">{{.locale.Tr "repo.diff.show_more"}}</a> | ||||
| 					</h4> | ||||
| 					{{if .Diff.IsIncomplete}} | ||||
| 						<div class="diff-file-box diff-box file-content mt-3" id="diff-incomplete"> | ||||
| 							<h4 class="ui top attached normal header df ac sb"> | ||||
| 								{{$.locale.Tr "repo.diff.too_many_files"}} | ||||
| 								<a class="ui basic tiny button" id="diff-show-more-files" data-href="{{$.Link}}?skip-to={{.Diff.End}}&file-only=true">{{.locale.Tr "repo.diff.show_more"}}</a> | ||||
| 							</h4> | ||||
| 						</div> | ||||
| 					{{end}} | ||||
| 				</div> | ||||
| 			{{end}} | ||||
| 		</div> | ||||
| 
 | ||||
| 		{{if not $.Repository.IsArchived}} | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| {{template "base/head" .}} | ||||
| <div class="page-content repository diff {{if .PageIsComparePull}}compare pull{{end}}"> | ||||
| 	{{template "repo/header" .}} | ||||
| 	<div class="ui container {{if .IsSplitStyle}}fluid padded{{end}}"> | ||||
| 	<div class="ui container fluid padded"> | ||||
| 
 | ||||
| 	<h2 class="ui header"> | ||||
| 		{{if and $.PageIsComparePull $.IsSigned (not .Repository.IsArchived)}} | ||||
|  | ||||
| @ -1,7 +1,7 @@ | ||||
| <div class="ui dropdown tiny basic button icon-button tooltip" data-content="{{.locale.Tr "repo.diff.options_button"}}"> | ||||
| 	{{svg "octicon-kebab-horizontal"}} | ||||
| 	<div class="menu"> | ||||
| 		<a class="item tiny basic toggle button" data-target="#diff-files">{{.locale.Tr "repo.diff.show_diff_stats"}}</a> | ||||
| 		<a class="item tiny basic toggle button" id="show-file-list-btn">{{.locale.Tr "repo.diff.show_diff_stats"}}</a> | ||||
| 		{{if .Issue.Index}} | ||||
| 			<a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.patch" download="{{.Issue.Index}}.patch">{{.locale.Tr "repo.diff.download_patch"}}</a> | ||||
| 			<a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.diff" download="{{.Issue.Index}}.diff">{{.locale.Tr "repo.diff.download_diff"}}</a> | ||||
|  | ||||
| @ -5,7 +5,7 @@ | ||||
| 
 | ||||
| <div class="page-content repository view issue pull files diff"> | ||||
| 	{{template "repo/header" .}} | ||||
| 	<div class="ui container {{if .IsSplitStyle}}fluid padded{{end}}"> | ||||
| 	<div class="ui container fluid padded"> | ||||
| 		<div class="navbar"> | ||||
| 			{{template "repo/issue/navbar" .}} | ||||
| 			<div class="ui right"> | ||||
|  | ||||
							
								
								
									
										81
									
								
								web_src/js/components/DiffFileList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								web_src/js/components/DiffFileList.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,81 @@ | ||||
| <template> | ||||
|   <ol class="diff-detail-box diff-stats m-0" id="diff-files" v-if="fileListIsVisible"> | ||||
|     <li v-for="file in files" :key="file.NameHash"> | ||||
|       <div class="bold df ac pull-right"> | ||||
|         <span v-if="file.IsBin" class="ml-1 mr-3">{{ binaryFileMessage }}</span> | ||||
|         {{ file.IsBin ? '' : file.Addition + file.Deletion }} | ||||
|         <span v-if="!file.IsBin" class="diff-stats-bar tooltip mx-3" :data-content="statisticsMessage.replace('%d', (file.Addition + file.Deletion)).replace('%d', file.Addition).replace('%d', file.Deletion)"> | ||||
|           <div class="diff-stats-add-bar" :style="{ 'width': diffStatsWidth(file.Addition, file.Deletion) }" /> | ||||
|         </span> | ||||
|       </div> | ||||
|       <!-- todo finish all file status, now modify, add, delete and rename --> | ||||
|       <span :class="['status', diffTypeToString(file.Type), 'tooltip']" :data-content="diffTypeToString(file.Type)" data-position="right center"> </span> | ||||
|       <a class="file mono" :href="'#diff-' + file.NameHash">{{ file.Name }}</a> | ||||
|     </li> | ||||
|     <li v-if="isIncomplete" id="diff-too-many-files-stats" class="pt-2"> | ||||
|       <span class="file df ac sb">{{ tooManyFilesMessage }} | ||||
|         <a :class="['ui', 'basic', 'tiny', 'button', isLoadingNewData === true ? 'disabled' : '']" id="diff-show-more-files-stats" @click.stop="loadMoreData">{{ showMoreMessage }}</a> | ||||
|       </span> | ||||
|     </li> | ||||
|   </ol> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import {initTooltip} from '../modules/tippy.js'; | ||||
| import {doLoadMoreFiles} from '../features/repo-diff.js'; | ||||
| 
 | ||||
| const {pageData} = window.config; | ||||
| 
 | ||||
| export default { | ||||
|   name: 'DiffFileList', | ||||
| 
 | ||||
|   data: () => { | ||||
|     return pageData.diffFileInfo; | ||||
|   }, | ||||
| 
 | ||||
|   watch: { | ||||
|     fileListIsVisible(newValue) { | ||||
|       if (newValue === true) { | ||||
|         this.$nextTick(() => { | ||||
|           for (const el of this.$el.querySelectorAll('.tooltip')) { | ||||
|             initTooltip(el); | ||||
|           } | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
| 
 | ||||
|   mounted() { | ||||
|     document.getElementById('show-file-list-btn').addEventListener('click', this.toggleFileList); | ||||
|   }, | ||||
| 
 | ||||
|   unmounted() { | ||||
|     document.getElementById('show-file-list-btn').removeEventListener('click', this.toggleFileList); | ||||
|   }, | ||||
| 
 | ||||
|   methods: { | ||||
|     toggleFileList() { | ||||
|       this.fileListIsVisible = !this.fileListIsVisible; | ||||
|     }, | ||||
|     diffTypeToString(pType) { | ||||
|       const diffTypes = { | ||||
|         1: 'add', | ||||
|         2: 'modify', | ||||
|         3: 'del', | ||||
|         4: 'rename', | ||||
|         5: 'copy', | ||||
|       }; | ||||
|       return diffTypes[pType]; | ||||
|     }, | ||||
|     diffStatsWidth(adds, dels) { | ||||
|       return `${adds / (adds + dels) * 100}%`; | ||||
|     }, | ||||
|     loadMoreData() { | ||||
|       this.isLoadingNewData = true; | ||||
|       doLoadMoreFiles(this.link, this.diffEnd, () => { | ||||
|         this.isLoadingNewData = false; | ||||
|       }); | ||||
|     } | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										129
									
								
								web_src/js/components/DiffFileTree.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								web_src/js/components/DiffFileTree.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,129 @@ | ||||
| <template> | ||||
|   <div | ||||
|     v-show="fileTreeIsVisible" | ||||
|     id="diff-file-tree" | ||||
|     class="mr-3 mt-3 diff-detail-box" | ||||
|   > | ||||
|     <!-- only render the tree if we're visible. in many cases this is something that doesn't change very often --> | ||||
|     <div class="ui list" v-if="fileTreeIsVisible"> | ||||
|       <DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item" /> | ||||
|     </div> | ||||
|     <div v-if="isIncomplete" id="diff-too-many-files-stats" class="pt-2"> | ||||
|       <span>{{ tooManyFilesMessage }}</span><a :class="['ui', 'basic', 'tiny', 'button', isLoadingNewData === true ? 'disabled' : '']" id="diff-show-more-files-stats" @click.stop="loadMoreData">{{ showMoreMessage }}</a> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import DiffFileTreeItem from './DiffFileTreeItem.vue'; | ||||
| import {doLoadMoreFiles} from '../features/repo-diff.js'; | ||||
| 
 | ||||
| const {pageData} = window.config; | ||||
| const LOCAL_STORAGE_KEY = 'diff_file_tree_visible'; | ||||
| 
 | ||||
| export default { | ||||
|   name: 'DiffFileTree', | ||||
|   components: {DiffFileTreeItem}, | ||||
| 
 | ||||
|   data: () => { | ||||
|     const fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) === 'true'; | ||||
|     pageData.diffFileInfo.fileTreeIsVisible = fileTreeIsVisible; | ||||
|     return pageData.diffFileInfo; | ||||
|   }, | ||||
| 
 | ||||
|   computed: { | ||||
|     fileTree() { | ||||
|       const result = []; | ||||
|       for (const file of this.files) { | ||||
|         // Split file into directories | ||||
|         const splits = file.Name.split('/'); | ||||
|         let index = 0; | ||||
|         let parent = null; | ||||
|         let isFile = false; | ||||
|         for (const split of splits) { | ||||
|           index += 1; | ||||
|           // reached the end | ||||
|           if (index === splits.length) { | ||||
|             isFile = true; | ||||
|           } | ||||
|           let newParent = { | ||||
|             name: split, | ||||
|             children: [], | ||||
|             isFile | ||||
|           }; | ||||
| 
 | ||||
|           if (isFile === true) { | ||||
|             newParent.file = file; | ||||
|           } | ||||
| 
 | ||||
|           if (parent) { | ||||
|             // check if the folder already exists | ||||
|             const existingFolder = parent.children.find( | ||||
|               (x) => x.name === split | ||||
|             ); | ||||
|             if (existingFolder) { | ||||
|               newParent = existingFolder; | ||||
|             } else { | ||||
|               parent.children.push(newParent); | ||||
|             } | ||||
|           } else { | ||||
|             const existingFolder = result.find((x) => x.name === split); | ||||
|             if (existingFolder) { | ||||
|               newParent = existingFolder; | ||||
|             } else { | ||||
|               result.push(newParent); | ||||
|             } | ||||
|           } | ||||
|           parent = newParent; | ||||
|         } | ||||
|       } | ||||
|       const mergeChildIfOnlyOneDir = (entries) => { | ||||
|         for (const entry of entries) { | ||||
|           if (entry.children) { | ||||
|             mergeChildIfOnlyOneDir(entry.children); | ||||
|           } | ||||
|           if (entry.children.length === 1 && entry.children[0].isFile === false) { | ||||
|             // Merge it to the parent | ||||
|             entry.name = `${entry.name}/${entry.children[0].name}`; | ||||
|             entry.children = entry.children[0].children; | ||||
|           } | ||||
|         } | ||||
|       }; | ||||
|       // Merge folders with just a folder as children in order to | ||||
|       // reduce the depth of our tree. | ||||
|       mergeChildIfOnlyOneDir(result); | ||||
|       return result; | ||||
|     } | ||||
|   }, | ||||
| 
 | ||||
|   mounted() { | ||||
|     // ensure correct buttons when we are mounted to the dom | ||||
|     this.adjustToggleButton(this.fileTreeIsVisible); | ||||
|     document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', this.toggleVisibility); | ||||
|   }, | ||||
|   unmounted() { | ||||
|     document.querySelector('.diff-toggle-file-tree-button').removeEventListener('click', this.toggleVisibility); | ||||
|   }, | ||||
|   methods: { | ||||
|     toggleVisibility() { | ||||
|       this.updateVisibility(!this.fileTreeIsVisible); | ||||
|     }, | ||||
|     updateVisibility(visible) { | ||||
|       this.fileTreeIsVisible = visible; | ||||
|       localStorage.setItem(LOCAL_STORAGE_KEY, this.fileTreeIsVisible); | ||||
|       this.adjustToggleButton(this.fileTreeIsVisible); | ||||
|     }, | ||||
|     adjustToggleButton(visible) { | ||||
|       const [toShow, toHide] = document.querySelectorAll('.diff-toggle-file-tree-button .icon'); | ||||
|       toShow.classList.toggle('hide', visible);  // hide the toShow icon if the tree is visible | ||||
|       toHide.classList.toggle('hide', !visible); // similarly | ||||
|     }, | ||||
|     loadMoreData() { | ||||
|       this.isLoadingNewData = true; | ||||
|       doLoadMoreFiles(this.link, this.diffEnd, () => { | ||||
|         this.isLoadingNewData = false; | ||||
|       }); | ||||
|     } | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										150
									
								
								web_src/js/components/DiffFileTreeItem.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								web_src/js/components/DiffFileTreeItem.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,150 @@ | ||||
| <template> | ||||
|   <div v-show="show"> | ||||
|     <div class="item" :class="item.isFile ? 'filewrapper p-1' : ''"> | ||||
|       <!-- Files --> | ||||
|       <SvgIcon | ||||
|         v-if="item.isFile" | ||||
|         data-position="right center" | ||||
|         name="octicon-file" | ||||
|         class="svg-icon file" | ||||
|       /> | ||||
|       <a | ||||
|         v-if="item.isFile" | ||||
|         class="file ellipsis" | ||||
|         :href="item.isFile ? '#diff-' + item.file.NameHash : ''" | ||||
|       >{{ item.name }}</a> | ||||
|       <SvgIcon | ||||
|         v-if="item.isFile" | ||||
|         data-position="right center" | ||||
|         :name="getIconForDiffType(item.file.Type)" | ||||
|         :class="['svg-icon', getIconForDiffType(item.file.Type), 'status']" | ||||
|       /> | ||||
| 
 | ||||
|       <!-- Directories --> | ||||
|       <div v-if="!item.isFile" class="directory p-1" @click.stop="handleClick(item.isFile)"> | ||||
|         <SvgIcon | ||||
|           class="svg-icon" | ||||
|           :name="collapsed ? 'octicon-chevron-right' : 'octicon-chevron-down'" | ||||
|         /> | ||||
|         <SvgIcon | ||||
|           class="svg-icon directory" | ||||
|           name="octicon-file-directory-fill" | ||||
|         /> | ||||
|         <span class="ellipsis">{{ item.name }}</span> | ||||
|       </div> | ||||
|       <div v-show="!collapsed"> | ||||
|         <DiffFileTreeItem v-for="childItem in item.children" :key="childItem.name" :item="childItem" class="list" /> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import {SvgIcon} from '../svg.js'; | ||||
| 
 | ||||
| export default { | ||||
|   name: 'DiffFileTreeItem', | ||||
|   components: { | ||||
|     SvgIcon, | ||||
|   }, | ||||
| 
 | ||||
|   props: { | ||||
|     item: { | ||||
|       type: Object, | ||||
|       required: true | ||||
|     }, | ||||
|     show: { | ||||
|       type: Boolean, | ||||
|       required: false, | ||||
|       default: true | ||||
|     } | ||||
|   }, | ||||
| 
 | ||||
|   data: () => ({ | ||||
|     collapsed: false, | ||||
|   }), | ||||
|   methods: { | ||||
|     handleClick(itemIsFile) { | ||||
|       if (itemIsFile) { | ||||
|         return; | ||||
|       } | ||||
|       this.$set(this, 'collapsed', !this.collapsed); | ||||
|     }, | ||||
|     getIconForDiffType(pType) { | ||||
|       const diffTypes = { | ||||
|         1: 'octicon-diff-added', | ||||
|         2: 'octicon-diff-modified', | ||||
|         3: 'octicon-diff-removed', | ||||
|         4: 'octicon-diff-renamed', | ||||
|         5: 'octicon-diff-modified', // there is no octicon for copied, so modified should be ok | ||||
|       }; | ||||
|       return diffTypes[pType]; | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
| span.svg-icon.status { | ||||
|   float: right; | ||||
| } | ||||
| span.svg-icon.file { | ||||
|   color: var(--color-secondary-dark-7); | ||||
| } | ||||
| 
 | ||||
| span.svg-icon.directory { | ||||
|   color: var(--color-primary); | ||||
| } | ||||
| 
 | ||||
| span.svg-icon.octicon-diff-modified { | ||||
|   color: var(--color-yellow); | ||||
| } | ||||
| 
 | ||||
| span.svg-icon.octicon-diff-added { | ||||
|   color: var(--color-green); | ||||
| } | ||||
| 
 | ||||
| span.svg-icon.octicon-diff-removed { | ||||
|   color: var(--color-red); | ||||
| } | ||||
| 
 | ||||
| span.svg-icon.octicon-diff-renamed { | ||||
|   color: var(--color-teal); | ||||
| } | ||||
| 
 | ||||
| .item.filewrapper { | ||||
|   display: grid !important; | ||||
|   grid-template-columns: 20px 7fr 1fr; | ||||
|   padding-left: 18px !important; | ||||
| } | ||||
| 
 | ||||
| .item.filewrapper:hover { | ||||
|   color: var(--color-text); | ||||
|   background: var(--color-hover); | ||||
|   border-radius: 4px; | ||||
| } | ||||
| 
 | ||||
| div.directory { | ||||
|   display: grid; | ||||
|   grid-template-columns: 18px 20px auto; | ||||
| } | ||||
| 
 | ||||
| div.directory:hover { | ||||
|   color: var(--color-text); | ||||
|   background: var(--color-hover); | ||||
|   border-radius: 4px; | ||||
| } | ||||
| 
 | ||||
| div.list { | ||||
|   padding-bottom: 0 !important; | ||||
|   padding-top: inherit !important; | ||||
| } | ||||
| 
 | ||||
| a { | ||||
|   text-decoration: none; | ||||
| } | ||||
| 
 | ||||
| a:hover { | ||||
|   text-decoration: none; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										21
									
								
								web_src/js/features/repo-diff-filetree.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								web_src/js/features/repo-diff-filetree.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| import Vue from 'vue'; | ||||
| import DiffFileTree from '../components/DiffFileTree.vue'; | ||||
| import DiffFileList from '../components/DiffFileList.vue'; | ||||
| 
 | ||||
| export default function initDiffFileTree() { | ||||
|   const el = document.getElementById('diff-file-tree-container'); | ||||
|   if (!el) return; | ||||
| 
 | ||||
|   const View = Vue.extend({ | ||||
|     render: (createElement) => createElement(DiffFileTree), | ||||
|   }); | ||||
|   new View().$mount(el); | ||||
| 
 | ||||
|   const fileListElement = document.getElementById('diff-file-list-container'); | ||||
|   if (!fileListElement) return; | ||||
| 
 | ||||
|   const fileListView = Vue.extend({ | ||||
|     render: (createElement) => createElement(DiffFileList), | ||||
|   }); | ||||
|   new fileListView().$mount(fileListElement); | ||||
| } | ||||
| @ -68,7 +68,6 @@ export function initRepoDiffConversationForm() { | ||||
|     initCompReactionSelector($newConversationHolder); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   $(document).on('click', '.resolve-conversation', async function (e) { | ||||
|     e.preventDefault(); | ||||
|     const comment_id = $(this).data('comment-id'); | ||||
| @ -118,32 +117,27 @@ function onShowMoreFiles() { | ||||
|   countAndUpdateViewedFiles(); | ||||
| } | ||||
| 
 | ||||
| export function initRepoDiffShowMore() { | ||||
|   $('#diff-files, #diff-file-boxes').on('click', '#diff-show-more-files, #diff-show-more-files-stats', (e) => { | ||||
|     e.preventDefault(); | ||||
| 
 | ||||
|     if ($(e.target).hasClass('disabled')) { | ||||
| export function doLoadMoreFiles(link, diffEnd, callback) { | ||||
|   const url = `${link}?skip-to=${diffEnd}&file-only=true`; | ||||
|   $.ajax({ | ||||
|     type: 'GET', | ||||
|     url, | ||||
|   }).done((resp) => { | ||||
|     if (!resp) { | ||||
|       callback(resp); | ||||
|       return; | ||||
|     } | ||||
|     $('#diff-show-more-files, #diff-show-more-files-stats').addClass('disabled'); | ||||
| 
 | ||||
|     const url = $('#diff-show-more-files, #diff-show-more-files-stats').data('href'); | ||||
|     $.ajax({ | ||||
|       type: 'GET', | ||||
|       url, | ||||
|     }).done((resp) => { | ||||
|       if (!resp) { | ||||
|         $('#diff-show-more-files, #diff-show-more-files-stats').removeClass('disabled'); | ||||
|         return; | ||||
|       } | ||||
|       $('#diff-too-many-files-stats').remove(); | ||||
|       $('#diff-files').append($(resp).find('#diff-files li')); | ||||
|       $('#diff-incomplete').replaceWith($(resp).find('#diff-file-boxes').children()); | ||||
|       onShowMoreFiles(); | ||||
|     }).fail(() => { | ||||
|       $('#diff-show-more-files, #diff-show-more-files-stats').removeClass('disabled'); | ||||
|     }); | ||||
|     // By simply rerunning the script we add the new data to our existing
 | ||||
|     // pagedata object. this triggers vue and the filetree and filelist will
 | ||||
|     // render the new elements.
 | ||||
|     $('body').append($(resp).find('script#diff-data-script')); | ||||
|     callback(resp); | ||||
|   }).fail(() => { | ||||
|     callback(); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| export function initRepoDiffShowMore() { | ||||
|   $(document).on('click', 'a.diff-show-more-button', (e) => { | ||||
|     e.preventDefault(); | ||||
|     const $target = $(e.target); | ||||
| @ -163,7 +157,6 @@ export function initRepoDiffShowMore() { | ||||
|         $target.removeClass('disabled'); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       $target.parent().replaceWith($(resp).find('#diff-file-boxes .diff-file-body .file-body').children()); | ||||
|       onShowMoreFiles(); | ||||
|     }).fail(() => { | ||||
|  | ||||
| @ -23,6 +23,7 @@ import {initRepoIssueContentHistory} from './features/repo-issue-content.js'; | ||||
| import {initStopwatch} from './features/stopwatch.js'; | ||||
| import {initFindFileInRepo} from './features/repo-findfile.js'; | ||||
| import {initCommentContent, initMarkupContent} from './markup/content.js'; | ||||
| import initDiffFileTree from './features/repo-diff-filetree.js'; | ||||
| 
 | ||||
| import {initUserAuthLinkAccountView, initUserAuthOauth2} from './features/user-auth.js'; | ||||
| import { | ||||
| @ -158,6 +159,7 @@ $(document).ready(() => { | ||||
|   initRepoDiffFileViewToggle(); | ||||
|   initRepoDiffReviewButton(); | ||||
|   initRepoDiffShowMore(); | ||||
|   initDiffFileTree(); | ||||
|   initRepoEditor(); | ||||
|   initRepoGraphGit(); | ||||
|   initRepoIssueContentHistory(); | ||||
|  | ||||
| @ -2,6 +2,11 @@ import octiconChevronDown from '../../public/img/svg/octicon-chevron-down.svg'; | ||||
| import octiconChevronRight from '../../public/img/svg/octicon-chevron-right.svg'; | ||||
| import octiconCopy from '../../public/img/svg/octicon-copy.svg'; | ||||
| import octiconClock from '../../public/img/svg/octicon-clock.svg'; | ||||
| import octiconDiffAdded from '../../public/img/svg/octicon-diff-added.svg'; | ||||
| import octiconDiffModified from '../../public/img/svg/octicon-diff-modified.svg'; | ||||
| import octiconDiffRemoved from '../../public/img/svg/octicon-diff-removed.svg'; | ||||
| import octiconDiffRenamed from '../../public/img/svg/octicon-diff-renamed.svg'; | ||||
| import octiconFileDirectoryFill from '../../public/img/svg/octicon-file-directory-fill.svg'; | ||||
| import octiconGitMerge from '../../public/img/svg/octicon-git-merge.svg'; | ||||
| import octiconGitPullRequest from '../../public/img/svg/octicon-git-pull-request.svg'; | ||||
| import octiconIssueClosed from '../../public/img/svg/octicon-issue-closed.svg'; | ||||
| @ -17,6 +22,9 @@ import octiconRepoForked from '../../public/img/svg/octicon-repo-forked.svg'; | ||||
| import octiconRepoTemplate from '../../public/img/svg/octicon-repo-template.svg'; | ||||
| import octiconTriangleDown from '../../public/img/svg/octicon-triangle-down.svg'; | ||||
| import octiconFile from '../../public/img/svg/octicon-file.svg'; | ||||
| import octiconSidebarExpand from '../../public/img/svg/octicon-sidebar-expand.svg'; | ||||
| import octiconSidebarCollapse from '../../public/img/svg/octicon-sidebar-collapse.svg'; | ||||
| 
 | ||||
| 
 | ||||
| import Vue from 'vue'; | ||||
| 
 | ||||
| @ -40,8 +48,16 @@ export const svgs = { | ||||
|   'octicon-repo-template': octiconRepoTemplate, | ||||
|   'octicon-triangle-down': octiconTriangleDown, | ||||
|   'octicon-file': octiconFile, | ||||
|   'octicon-file-directory-fill': octiconFileDirectoryFill, | ||||
|   'octicon-sidebar-expand': octiconSidebarExpand, | ||||
|   'octicon-sidebar-collapse': octiconSidebarCollapse, | ||||
|   'octicon-diff-added': octiconDiffAdded, | ||||
|   'octicon-diff-modified': octiconDiffModified, | ||||
|   'octicon-diff-removed': octiconDiffRemoved, | ||||
|   'octicon-diff-renamed': octiconDiffRenamed, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| const parser = new DOMParser(); | ||||
| const serializer = new XMLSerializer(); | ||||
| 
 | ||||
|  | ||||
| @ -3068,6 +3068,35 @@ td.blob-excerpt { | ||||
|   padding-left: 8px; | ||||
| } | ||||
| 
 | ||||
| #diff-container { | ||||
|   display: flex; | ||||
| } | ||||
| #diff-file-boxes { | ||||
|   flex: 1; | ||||
| } | ||||
| 
 | ||||
| #diff-file-tree { | ||||
|   width: 20%; | ||||
|   max-width: 380px; | ||||
|   line-height: inherit; | ||||
|   position: sticky; | ||||
|   padding-top: 0; | ||||
|   top: 47px; | ||||
|   max-height: calc(100vh - 50px); | ||||
|   height: 100%; | ||||
|   overflow-y: auto; | ||||
| } | ||||
| 
 | ||||
| @media @mediaMdAndDown { | ||||
|   #diff-file-tree { | ||||
|     display: none; | ||||
|   } | ||||
| 
 | ||||
|   .diff-toggle-file-tree-button { | ||||
|     display: none; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| .ui.message.unicode-escape-prompt { | ||||
|   margin-bottom: 0; | ||||
|   border-radius: 0; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user