Skip to content

Commit c2c04ff

Browse files
Add fullscreen mode as a more efficient operation way to view projects (#34081)
Maybe fix #33482, maybe fix #34015 --------- Co-authored-by: wxiaoguang <[email protected]>
1 parent 04fab18 commit c2c04ff

File tree

9 files changed

+119
-57
lines changed

9 files changed

+119
-57
lines changed

options/locale/locale_en-US.ini

+2
Original file line numberDiff line numberDiff line change
@@ -3844,6 +3844,8 @@ deleted.display_name = Deleted Project
38443844
type-1.display_name = Individual Project
38453845
type-2.display_name = Repository Project
38463846
type-3.display_name = Organization Project
3847+
enter_fullscreen = Fullscreen
3848+
exit_fullscreen = Exit Fullscreen
38473849

38483850
[git.filemode]
38493851
changed_filemode = %[1]s → %[2]s

templates/org/projects/view.tmpl

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
{{template "user/overview/header" .}}
99
</div>
1010
{{end}}
11-
<div class="ui container fluid padded">
12-
{{template "projects/view" .}}
13-
</div>
11+
{{template "projects/view" .}}
1412
</div>
1513
{{template "base/footer" .}}

templates/projects/view.tmpl

+16-9
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{{$canWriteProject := and .CanWriteProjects (or (not .Repository) (not .Repository.IsArchived))}}
22

3-
<div class="ui container tw-max-w-full">
4-
<div class="flex-text-block tw-flex-wrap tw-mb-4">
5-
<h2 class="tw-mb-0">{{.Project.Title}}</h2>
3+
<div class="ui container fluid padded projects-view">
4+
<div class="ui container flex-text-block project-header">
5+
<h2>{{.Project.Title}}</h2>
66
<div class="tw-flex-1"></div>
77
<div class="ui secondary menu tw-m-0">
88
{{$queryLink := QueryBuild "?" "labels" .SelectLabels "assignee" $.AssigneeID "archived_labels" (Iif $.ShowArchivedLabels "true")}}
@@ -19,6 +19,14 @@
1919
</div>
2020
{{if $canWriteProject}}
2121
<div class="ui compact mini menu">
22+
<a class="item screen-full">
23+
{{svg "octicon-screen-full"}}
24+
{{ctx.Locale.Tr "projects.enter_fullscreen"}}
25+
</a>
26+
<a class="item screen-normal tw-hidden">
27+
{{svg "octicon-screen-normal"}}
28+
{{ctx.Locale.Tr "projects.exit_fullscreen"}}
29+
</a>
2230
<a class="item" href="{{.Link}}/edit?redirect=project">
2331
{{svg "octicon-pencil"}}
2432
{{ctx.Locale.Tr "repo.issues.label_edit"}}
@@ -56,13 +64,12 @@
5664
{{end}}
5765
</div>
5866

59-
<div class="content">{{$.Project.RenderedContent}}</div>
60-
61-
<div class="divider"></div>
62-
</div>
67+
<div class="ui container project-description">
68+
{{$.Project.RenderedContent}}
69+
<div class="divider"></div>
70+
</div>
6371

64-
<div id="project-board" data-project-borad-writable="{{$canWriteProject}}">
65-
<div class="board {{if $canWriteProject}}sortable{{end}}" {{if $canWriteProject}}data-url="{{$.Link}}/move"{{end}}>
72+
<div id="project-board" class="board {{if $canWriteProject}}sortable{{end}}" data-project-borad-writable="{{$canWriteProject}}" {{if $canWriteProject}}data-url="{{$.Link}}/move"{{end}}>
6673
{{range .Columns}}
6774
<div class="project-column" {{if .Color}}style="background: {{.Color}} !important; color: {{ContrastColor .Color}} !important"{{end}} data-id="{{.ID}}" data-sorting="{{.Sorting}}" data-url="{{$.Link}}/{{.ID}}">
6875
<div class="project-column-header{{if $canWriteProject}} tw-cursor-grab{{end}}">

templates/repo/projects/view.tmpl

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
<a class="ui small primary button" href="{{.RepoLink}}/issues/new/choose?project={{.Project.ID}}">{{ctx.Locale.Tr "repo.issues.new"}}</a>
99
</div>
1010
</div>
11-
<div class="ui container fluid padded">
12-
{{template "projects/view" .}}
13-
</div>
11+
{{template "projects/view" .}}
1412
</div>
1513

1614
{{template "base/footer" .}}

web_src/css/features/projects.css

+52-24
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
1-
.board {
1+
#project-board {
22
display: flex;
3+
align-items: stretch;
34
flex-direction: row;
45
flex-wrap: nowrap;
5-
overflow-x: auto;
6-
overflow-y: clip;
7-
align-items: stretch;
6+
overflow: auto;
87
margin: 0 0.5em;
8+
max-height: calc(100vh - 120px);
9+
}
10+
11+
.project-header {
12+
padding: 0.5em 0;
13+
overflow-x: auto; /* in fullscreen mode, the position is fixed, so we can't use "flex wrap" which would change the height */
14+
}
15+
16+
.project-header h2 {
17+
white-space: nowrap;
18+
margin: 0;
919
}
1020

1121
.project-column {
12-
background-color: var(--color-project-column-bg) !important;
13-
border: 1px solid var(--color-secondary) !important;
14-
border-radius: var(--border-radius);
15-
margin: 0 0.5rem !important;
16-
padding: 0.5rem !important;
17-
width: 320px;
18-
height: initial;
19-
min-height: max(calc(100vh - 400px), 300px);
2022
flex: 0 0 auto;
21-
overflow: visible;
2223
display: flex;
2324
flex-direction: column;
24-
cursor: default;
25-
}
26-
27-
.project-column .issue-card {
28-
color: var(--color-text);
25+
background-color: var(--color-project-column-bg);
26+
border: 1px solid var(--color-secondary);
27+
border-radius: var(--border-radius);
28+
margin: 0 0.5rem;
29+
padding: 0.5rem;
30+
width: 320px;
31+
overflow: visible;
2932
}
3033

3134
.project-column-header {
@@ -39,16 +42,15 @@
3942
color: inherit;
4043
}
4144

42-
.project-column > .cards {
45+
.project-column > .ui.cards {
4346
flex: 1;
4447
display: flex;
45-
align-content: baseline;
46-
margin: 0 !important;
47-
padding: 0 !important;
48-
flex-wrap: nowrap !important;
48+
flex-wrap: nowrap;
4949
flex-direction: column;
50-
overflow-x: clip;
50+
overflow: clip auto;
5151
gap: .25rem;
52+
margin: 0;
53+
padding: 0;
5254
}
5355

5456
.project-column > .divider {
@@ -98,3 +100,29 @@
98100
.card-ghost * {
99101
opacity: 0;
100102
}
103+
104+
.fullscreen.projects-view .project-header {
105+
position: fixed;
106+
z-index: 1000;
107+
top: 0;
108+
left: 0;
109+
right: 0;
110+
padding: 0.5em;
111+
width: 100%;
112+
max-width: 100%;
113+
background-color: var(--color-body);
114+
border-bottom: 1px solid var(--color-secondary);
115+
}
116+
117+
/* Hide project-description in full-screen due to its variable height. No need to show it for better space use. */
118+
.fullscreen.projects-view .project-description {
119+
display: none;
120+
}
121+
122+
.fullscreen.projects-view #project-board {
123+
position: absolute;
124+
top: 60px;
125+
left: 0;
126+
right: 0;
127+
max-height: calc(100vh - 70px);
128+
}

web_src/css/modules/menu.css

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
.ui.menu {
22
display: flex;
3+
flex-shrink: 0;
34
margin: 1rem 0;
45
font-family: var(--fonts-regular);
56
font-weight: var(--font-weight-normal);
@@ -643,6 +644,7 @@
643644
display: inline-flex;
644645
margin: 0;
645646
vertical-align: middle;
647+
flex-shrink: 0;
646648
}
647649
.ui.compact.vertical.menu {
648650
display: inline-block;

web_src/js/components/RepoActionView.vue

+2-15
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {formatDatetime} from '../utils/time.ts';
77
import {renderAnsi} from '../render/ansi.ts';
88
import {POST, DELETE} from '../modules/fetch.ts';
99
import type {IntervalId} from '../types.ts';
10+
import {toggleFullScreen} from '../utils.ts';
1011
1112
// see "models/actions/status.go", if it needs to be used somewhere else, move it to a shared file like "types/actions.ts"
1213
type RunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked';
@@ -416,21 +417,7 @@ export default defineComponent({
416417
417418
toggleFullScreen() {
418419
this.isFullScreen = !this.isFullScreen;
419-
const fullScreenEl = document.querySelector('.action-view-right');
420-
const outerEl = document.querySelector('.full.height');
421-
const actionBodyEl = document.querySelector('.action-view-body');
422-
const headerEl = document.querySelector('#navbar');
423-
const contentEl = document.querySelector('.page-content');
424-
const footerEl = document.querySelector('.page-footer');
425-
toggleElem(headerEl, !this.isFullScreen);
426-
toggleElem(contentEl, !this.isFullScreen);
427-
toggleElem(footerEl, !this.isFullScreen);
428-
// move .action-view-right to new parent
429-
if (this.isFullScreen) {
430-
outerEl.append(fullScreenEl);
431-
} else {
432-
actionBodyEl.append(fullScreenEl);
433-
}
420+
toggleFullScreen('.action-view-right', this.isFullScreen, '.action-view-body');
434421
},
435422
async hashChangeListener() {
436423
const selectedLogStep = window.location.hash;

web_src/js/features/repo-projects.ts

+21-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import {contrastColor} from '../utils/color.ts';
22
import {createSortable} from '../modules/sortable.ts';
33
import {POST, request} from '../modules/fetch.ts';
44
import {fomanticQuery} from '../modules/fomantic/base.ts';
5-
import {queryElemChildren, queryElems} from '../utils/dom.ts';
5+
import {queryElemChildren, queryElems, toggleElem} from '../utils/dom.ts';
66
import type {SortableEvent} from 'sortablejs';
7+
import {toggleFullScreen} from '../utils.ts';
78

89
function updateIssueCount(card: HTMLElement): void {
910
const parent = card.parentElement;
@@ -34,8 +35,8 @@ async function moveIssue({item, from, to, oldIndex}: SortableEvent): Promise<voi
3435
}
3536

3637
async function initRepoProjectSortable(): Promise<void> {
37-
// the HTML layout is: #project-board > .board > .project-column .cards > .issue-card
38-
const mainBoard = document.querySelector('#project-board > .board.sortable');
38+
// the HTML layout is: #project-board.board > .project-column .cards > .issue-card
39+
const mainBoard = document.querySelector('#project-board');
3940
let boardColumns = mainBoard.querySelectorAll<HTMLElement>('.project-column');
4041
createSortable(mainBoard, {
4142
group: 'project-column',
@@ -139,7 +140,24 @@ function initRepoProjectColumnEdit(writableProjectBoard: Element): void {
139140
});
140141
}
141142

143+
function initRepoProjectToggleFullScreen(): void {
144+
const enterFullscreenBtn = document.querySelector('.screen-full');
145+
const exitFullscreenBtn = document.querySelector('.screen-normal');
146+
if (!enterFullscreenBtn || !exitFullscreenBtn) return;
147+
148+
const toggleFullscreenState = (isFullScreen: boolean) => {
149+
toggleFullScreen('.projects-view', isFullScreen);
150+
toggleElem(enterFullscreenBtn, !isFullScreen);
151+
toggleElem(exitFullscreenBtn, isFullScreen);
152+
};
153+
154+
enterFullscreenBtn.addEventListener('click', () => toggleFullscreenState(true));
155+
exitFullscreenBtn.addEventListener('click', () => toggleFullscreenState(false));
156+
}
157+
142158
export function initRepoProject(): void {
159+
initRepoProjectToggleFullScreen();
160+
143161
const writableProjectBoard = document.querySelector('#project-board[data-project-borad-writable="true"]');
144162
if (!writableProjectBoard) return;
145163

web_src/js/utils.ts

+22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {decode, encode} from 'uint8-to-base64';
22
import type {IssuePageInfo, IssuePathInfo, RepoOwnerPathInfo} from './types.ts';
3+
import {toggleClass, toggleElem} from './utils/dom.ts';
34

45
// transform /path/to/file.ext to /path/to
56
export function dirname(path: string): string {
@@ -179,3 +180,24 @@ export function isImageFile({name, type}: {name?: string, type?: string}): boole
179180
export function isVideoFile({name, type}: {name?: string, type?: string}): boolean {
180181
return /\.(mpe?g|mp4|mkv|webm)$/i.test(name || '') || type?.startsWith('video/');
181182
}
183+
184+
export function toggleFullScreen(fullscreenElementsSelector: string, isFullScreen: boolean, sourceParentSelector?: string): void {
185+
// hide other elements
186+
const headerEl = document.querySelector('#navbar');
187+
const contentEl = document.querySelector('.page-content');
188+
const footerEl = document.querySelector('.page-footer');
189+
toggleElem(headerEl, !isFullScreen);
190+
toggleElem(contentEl, !isFullScreen);
191+
toggleElem(footerEl, !isFullScreen);
192+
193+
const sourceParentEl = sourceParentSelector ? document.querySelector(sourceParentSelector) : contentEl;
194+
195+
const fullScreenEl = document.querySelector(fullscreenElementsSelector);
196+
const outerEl = document.querySelector('.full.height');
197+
toggleClass(fullscreenElementsSelector, 'fullscreen', isFullScreen);
198+
if (isFullScreen) {
199+
outerEl.append(fullScreenEl);
200+
} else {
201+
sourceParentEl.append(fullScreenEl);
202+
}
203+
}

0 commit comments

Comments
 (0)