mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2025-05-25 11:22:16 +00:00
Merge pull request '[gitea] week 12 cherry-pick' (#2679) from algernon/forgejo:wcp/week-12 into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/2679 Reviewed-by: Otto <otto@codeberg.org> Reviewed-by: oliverpool <oliverpool@noreply.codeberg.org> Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>
This commit is contained in:
commit
2f78daa3af
174 changed files with 3157 additions and 2907 deletions
|
@ -116,33 +116,9 @@ h1.error-code {
|
|||
}
|
||||
|
||||
* {
|
||||
scrollbar-color: var(--color-primary) transparent;
|
||||
caret-color: var(--color-caret);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
box-shadow: inset 0 0 0 6px var(--color-primary);
|
||||
border: 2px solid transparent;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:window-inactive {
|
||||
box-shadow: inset 0 0 0 6px var(--color-primary);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
box-shadow: inset 0 0 0 6px var(--color-primary-dark-2);
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
::file-selector-button {
|
||||
border: 1px solid var(--color-light-border);
|
||||
color: var(--color-text-light);
|
||||
|
@ -184,24 +160,32 @@ a {
|
|||
text-decoration-skip-ink: all;
|
||||
}
|
||||
|
||||
/* muted link = only colored when hovered */
|
||||
/* silenced link = never colored */
|
||||
/* a = always colored, underlined on hover */
|
||||
/* a.muted = colored on hover, underlined on hover */
|
||||
/* a.suppressed = never colored, underlined on hover */
|
||||
/* a.silenced = never colored, never underlined */
|
||||
|
||||
a.muted,
|
||||
a.suppressed,
|
||||
a.silenced,
|
||||
.muted-links a {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a:hover,
|
||||
a.suppressed:hover,
|
||||
a.muted:hover,
|
||||
a.muted:hover [class*="color-text"],
|
||||
.muted-links a:hover {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
a.silenced:hover {
|
||||
a.silenced:hover,
|
||||
a.suppressed:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
a.silenced:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
@ -259,7 +243,7 @@ a.label,
|
|||
}
|
||||
|
||||
.page-content .header-wrapper,
|
||||
.page-content .new-menu {
|
||||
.page-content overflow-menu {
|
||||
margin-top: -15px !important;
|
||||
padding-top: 15px !important;
|
||||
}
|
||||
|
@ -527,73 +511,6 @@ ol.ui.list li,
|
|||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.ui.message {
|
||||
background: var(--color-box-body);
|
||||
color: var(--color-text);
|
||||
box-shadow: none !important;
|
||||
border: 1px solid var(--color-secondary);
|
||||
}
|
||||
|
||||
.ui.info.message .header,
|
||||
.ui.blue.message .header {
|
||||
color: var(--color-blue);
|
||||
}
|
||||
|
||||
.ui.info.message,
|
||||
.ui.attached.info.message,
|
||||
.ui.blue.message,
|
||||
.ui.attached.blue.message {
|
||||
background: var(--color-info-bg);
|
||||
color: var(--color-info-text);
|
||||
border-color: var(--color-info-border);
|
||||
}
|
||||
|
||||
.ui.success.message .header,
|
||||
.ui.positive.message .header,
|
||||
.ui.green.message .header {
|
||||
color: var(--color-green);
|
||||
}
|
||||
|
||||
.ui.success.message,
|
||||
.ui.attached.success.message,
|
||||
.ui.positive.message,
|
||||
.ui.attached.positive.message {
|
||||
background: var(--color-success-bg);
|
||||
color: var(--color-success-text);
|
||||
border-color: var(--color-success-border);
|
||||
}
|
||||
|
||||
.ui.error.message .header,
|
||||
.ui.negative.message .header,
|
||||
.ui.red.message .header {
|
||||
color: var(--color-red);
|
||||
}
|
||||
|
||||
.ui.error.message,
|
||||
.ui.attached.error.message,
|
||||
.ui.red.message,
|
||||
.ui.attached.red.message,
|
||||
.ui.negative.message,
|
||||
.ui.attached.negative.message {
|
||||
background: var(--color-error-bg);
|
||||
color: var(--color-error-text);
|
||||
border-color: var(--color-error-border);
|
||||
}
|
||||
|
||||
.ui.warning.message .header,
|
||||
.ui.yellow.message .header {
|
||||
color: var(--color-yellow);
|
||||
}
|
||||
|
||||
.ui.warning.message,
|
||||
.ui.attached.warning.message,
|
||||
.ui.yellow.message,
|
||||
.ui.attached.yellow.message {
|
||||
background: var(--color-warning-bg);
|
||||
color: var(--color-warning-text);
|
||||
border-color: var(--color-warning-border);
|
||||
}
|
||||
|
||||
.ui.error.header {
|
||||
background: var(--color-error-bg) !important;
|
||||
color: var(--color-error-text) !important;
|
||||
|
@ -1358,75 +1275,21 @@ strong.attention-caution, span.attention-caution {
|
|||
}
|
||||
}
|
||||
|
||||
.ui.menu.new-menu {
|
||||
margin-bottom: 15px;
|
||||
background: var(--color-header-wrapper);
|
||||
overflow-menu {
|
||||
margin-bottom: 15px !important;
|
||||
border-bottom: 1px solid var(--color-secondary) !important;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.ui.menu.new-menu .new-menu-inner {
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
mask-image: linear-gradient(to right, #000 0%, #000 calc(100% - 60px), transparent 100%);
|
||||
-webkit-mask-image: linear-gradient(to right, #000 0%, #000 calc(100% - 60px), transparent 100%);
|
||||
}
|
||||
|
||||
.ui.menu.new-menu .item {
|
||||
overflow-menu .overflow-menu-items {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
overflow-menu .overflow-menu-items .item {
|
||||
margin-bottom: 0 !important; /* reset fomantic's margin, because the active menu has special bottom border */
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.ui.menu.new-menu .item {
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ui.menu.new-menu .item:first-child {
|
||||
margin-left: auto; /* "justify-content: center" doesn't work with "overflow: auto", so use margin: auto */
|
||||
}
|
||||
|
||||
.ui.menu.new-menu .item:last-child {
|
||||
padding-right: 30px !important;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.ui.menu.new-menu::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ui.menu.new-menu::-webkit-scrollbar-track {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
.ui.menu.new-menu::-webkit-scrollbar-thumb {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.ui.menu.new-menu:hover::-webkit-scrollbar {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.repos-search {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.repos-filter {
|
||||
margin-top: 0 !important;
|
||||
border-bottom-width: 0 !important;
|
||||
margin-bottom: 2px !important;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.ui.secondary.pointing.menu.repos-filter .item {
|
||||
padding-left: 4.5px;
|
||||
padding-right: 4.5px;
|
||||
}
|
||||
|
||||
.activity-bar-graph {
|
||||
background-color: var(--color-primary);
|
||||
color: var(--color-primary-contrast);
|
||||
|
@ -1932,7 +1795,6 @@ table th[data-sortt-desc] .svg {
|
|||
background: var(--color-body);
|
||||
border-color: var(--color-secondary);
|
||||
color: var(--color-text);
|
||||
margin-top: 1px; /* offset fomantic's margin-bottom: -1px */
|
||||
}
|
||||
|
||||
.ui.segment .ui.tabular.menu .active.item,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
@import "./modules/divider.css";
|
||||
@import "./modules/svg.css";
|
||||
@import "./modules/flexcontainer.css";
|
||||
@import "./modules/message.css";
|
||||
|
||||
@import "./shared/flex-list.css";
|
||||
@import "./shared/milestone.css";
|
||||
|
|
|
@ -13,6 +13,10 @@
|
|||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.button.is-loading > * {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.is-loading::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
|
@ -20,6 +24,7 @@
|
|||
left: 50%;
|
||||
top: 50%;
|
||||
height: min(4em, 66.6%);
|
||||
width: fit-content; /* compat: safari - https://bugs.webkit.org/show_bug.cgi?id=267625 */
|
||||
aspect-ratio: 1;
|
||||
transform: translate(-50%, -50%);
|
||||
animation: isloadingspin 1000ms infinite linear;
|
||||
|
|
99
web_src/css/modules/message.css
Normal file
99
web_src/css/modules/message.css
Normal file
|
@ -0,0 +1,99 @@
|
|||
.ui.message {
|
||||
background: var(--color-box-body);
|
||||
color: var(--color-text);
|
||||
border: 1px solid var(--color-secondary);
|
||||
position: relative;
|
||||
min-height: 1em;
|
||||
margin: 1em 0;
|
||||
padding: 1em 1.5em;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.ui.message:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ui.message:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ui.attached.message {
|
||||
margin-bottom: -1px;
|
||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
||||
margin-left: -1px;
|
||||
margin-right: -1px;
|
||||
}
|
||||
|
||||
.ui.attached + .ui.attached.message:not(.top):not(.bottom) {
|
||||
margin-top: -1px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.ui.bottom.attached.message {
|
||||
margin-top: -1px;
|
||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||
}
|
||||
|
||||
.ui.bottom.attached.message:not(:last-child) {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.ui.info.message .header,
|
||||
.ui.blue.message .header {
|
||||
color: var(--color-blue);
|
||||
}
|
||||
|
||||
.ui.info.message,
|
||||
.ui.attached.info.message,
|
||||
.ui.blue.message,
|
||||
.ui.attached.blue.message {
|
||||
background: var(--color-info-bg);
|
||||
color: var(--color-info-text);
|
||||
border-color: var(--color-info-border);
|
||||
}
|
||||
|
||||
.ui.success.message .header,
|
||||
.ui.positive.message .header,
|
||||
.ui.green.message .header {
|
||||
color: var(--color-green);
|
||||
}
|
||||
|
||||
.ui.success.message,
|
||||
.ui.attached.success.message,
|
||||
.ui.positive.message,
|
||||
.ui.attached.positive.message {
|
||||
background: var(--color-success-bg);
|
||||
color: var(--color-success-text);
|
||||
border-color: var(--color-success-border);
|
||||
}
|
||||
|
||||
.ui.error.message .header,
|
||||
.ui.negative.message .header,
|
||||
.ui.red.message .header {
|
||||
color: var(--color-red);
|
||||
}
|
||||
|
||||
.ui.error.message,
|
||||
.ui.attached.error.message,
|
||||
.ui.red.message,
|
||||
.ui.attached.red.message,
|
||||
.ui.negative.message,
|
||||
.ui.attached.negative.message {
|
||||
background: var(--color-error-bg);
|
||||
color: var(--color-error-text);
|
||||
border-color: var(--color-error-border);
|
||||
}
|
||||
|
||||
.ui.warning.message .header,
|
||||
.ui.yellow.message .header {
|
||||
color: var(--color-yellow);
|
||||
}
|
||||
|
||||
.ui.warning.message,
|
||||
.ui.attached.warning.message,
|
||||
.ui.yellow.message,
|
||||
.ui.attached.yellow.message {
|
||||
background: var(--color-warning-bg);
|
||||
color: var(--color-warning-text);
|
||||
border-color: var(--color-warning-border);
|
||||
}
|
|
@ -5,6 +5,11 @@
|
|||
display: none !important;
|
||||
}
|
||||
|
||||
/* show target element once it's been moved by tippy.js */
|
||||
.tippy-content .tippy-target {
|
||||
display: unset !important;
|
||||
}
|
||||
|
||||
[data-tippy-root] {
|
||||
max-width: calc(100vw - 32px);
|
||||
}
|
||||
|
@ -46,18 +51,40 @@
|
|||
.tippy-box[data-theme="menu"] {
|
||||
background-color: var(--color-menu);
|
||||
color: var(--color-text);
|
||||
box-shadow: 0 6px 18px var(--color-shadow);
|
||||
}
|
||||
|
||||
.tippy-box[data-theme="menu"] .tippy-content {
|
||||
padding: 0;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.tippy-box[data-theme="menu"] .tippy-svg-arrow-inner {
|
||||
fill: var(--color-menu);
|
||||
}
|
||||
|
||||
.tippy-box[data-theme="menu"] .item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 9px 18px;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.tippy-box[data-theme="menu"] .item:hover {
|
||||
background: var(--color-hover);
|
||||
}
|
||||
|
||||
.tippy-box[data-theme="menu"] .item:focus {
|
||||
background: var(--color-active);
|
||||
}
|
||||
|
||||
/* box-with-header theme to look like .ui.attached.segment. can contain .ui.attached.header */
|
||||
|
||||
.tippy-box[data-theme="box-with-header"] {
|
||||
box-shadow: 0 6px 18px var(--color-shadow);
|
||||
}
|
||||
|
||||
.tippy-box[data-theme="box-with-header"] .tippy-content {
|
||||
background: var(--color-box-body);
|
||||
border-radius: var(--border-radius);
|
||||
|
|
|
@ -1065,11 +1065,7 @@
|
|||
|
||||
.repository.view.issue .comment-list .event .detail {
|
||||
margin-top: 4px;
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
||||
.repository.view.issue .comment-list .event .detail .svg {
|
||||
margin-right: 2px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.repository.view.issue .comment-list .event .segments {
|
||||
|
@ -2038,13 +2034,8 @@
|
|||
}
|
||||
|
||||
#cite-repo-modal #citation-panel {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
#cite-repo-modal #citation-panel {
|
||||
width: 100%;
|
||||
}
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#cite-repo-modal #citation-panel input {
|
||||
|
@ -2064,6 +2055,7 @@
|
|||
padding: 5px 10px;
|
||||
font-size: 1.2em;
|
||||
line-height: 1.4;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
#cite-repo-modal #citation-panel #citation-copy-apa,
|
||||
|
@ -2786,16 +2778,6 @@ tbody.commit-list {
|
|||
border-left: 1px solid var(--color-secondary);
|
||||
}
|
||||
|
||||
.repository .ui.menu.new-menu {
|
||||
background: none !important;
|
||||
}
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.repository .ui.menu.new-menu::after {
|
||||
background: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.migrate-entries {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
|
|
|
@ -74,17 +74,6 @@
|
|||
background-color: var(--color-header-wrapper);
|
||||
}
|
||||
|
||||
.repository .header-wrapper .new-menu {
|
||||
padding-top: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.repository .header-wrapper .new-menu .item {
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.repo-header .flex-item {
|
||||
flex-grow: 1;
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
color: var(--color-text-dark) !important;
|
||||
}
|
||||
|
||||
.code-line-menu {
|
||||
width: auto !important;
|
||||
border: none !important; /* the border is provided by tippy, not using the `.ui.menu` border */
|
||||
}
|
||||
|
||||
.code-line-button {
|
||||
background-color: var(--color-menu);
|
||||
color: var(--color-text-light);
|
||||
|
|
|
@ -5,13 +5,6 @@
|
|||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.repository .ui.secondary.stackable.pointing.menu,
|
||||
.organization .ui.secondary.stackable.pointing.menu {
|
||||
flex-wrap: wrap;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.repository .ui.tabs.container,
|
||||
.organization .ui.tabs.container {
|
||||
margin-top: 14px;
|
||||
|
|
|
@ -30,45 +30,45 @@
|
|||
--color-primary-alpha-90: #4183c4e1;
|
||||
--color-primary-hover: var(--color-primary-light-1);
|
||||
--color-primary-active: var(--color-primary-light-2);
|
||||
--color-secondary: #3f4346;
|
||||
--color-secondary-dark-1: #464a4d;
|
||||
--color-secondary-dark-2: #4f5356;
|
||||
--color-secondary-dark-3: #5f6366;
|
||||
--color-secondary-dark-4: #72767a;
|
||||
--color-secondary-dark-5: #7f8488;
|
||||
--color-secondary-dark-6: #8d9297;
|
||||
--color-secondary-dark-7: #999ea3;
|
||||
--color-secondary-dark-8: #a6abaf;
|
||||
--color-secondary-dark-9: #aeb3b8;
|
||||
--color-secondary-dark-10: #babfc4;
|
||||
--color-secondary-dark-11: #c5cbd0;
|
||||
--color-secondary-dark-12: #ced4da;
|
||||
--color-secondary-dark-13: #d1d7dd;
|
||||
--color-secondary-light-1: #313538;
|
||||
--color-secondary-light-2: #272b2e;
|
||||
--color-secondary-light-3: #1e2225;
|
||||
--color-secondary-light-4: #171b1e;
|
||||
--color-secondary-alpha-10: #3f434619;
|
||||
--color-secondary-alpha-20: #3f434633;
|
||||
--color-secondary-alpha-30: #3f43464b;
|
||||
--color-secondary-alpha-40: #3f434666;
|
||||
--color-secondary-alpha-50: #3f434680;
|
||||
--color-secondary-alpha-60: #3f434699;
|
||||
--color-secondary-alpha-70: #3f4346b3;
|
||||
--color-secondary-alpha-80: #3f4346cc;
|
||||
--color-secondary-alpha-90: #3f4346e1;
|
||||
--color-secondary: #3b444a;
|
||||
--color-secondary-dark-1: #424b51;
|
||||
--color-secondary-dark-2: #4a545b;
|
||||
--color-secondary-dark-3: #59646c;
|
||||
--color-secondary-dark-4: #6b7681;
|
||||
--color-secondary-dark-5: #78858f;
|
||||
--color-secondary-dark-6: #87929d;
|
||||
--color-secondary-dark-7: #939ea9;
|
||||
--color-secondary-dark-8: #a1acb4;
|
||||
--color-secondary-dark-9: #aab3bc;
|
||||
--color-secondary-dark-10: #b6bfc8;
|
||||
--color-secondary-dark-11: #c2cbd3;
|
||||
--color-secondary-dark-12: #ccd4dc;
|
||||
--color-secondary-dark-13: #cfd7df;
|
||||
--color-secondary-light-1: #2e353b;
|
||||
--color-secondary-light-2: #2b353e;
|
||||
--color-secondary-light-3: #1c2227;
|
||||
--color-secondary-light-4: #161b1f;
|
||||
--color-secondary-alpha-10: #3b444a19;
|
||||
--color-secondary-alpha-20: #3b444a33;
|
||||
--color-secondary-alpha-30: #3b444a4b;
|
||||
--color-secondary-alpha-40: #3b444a66;
|
||||
--color-secondary-alpha-50: #3b444a80;
|
||||
--color-secondary-alpha-60: #3b444a99;
|
||||
--color-secondary-alpha-70: #3b444ab3;
|
||||
--color-secondary-alpha-80: #3b444acc;
|
||||
--color-secondary-alpha-90: #3b444ae1;
|
||||
--color-secondary-button: var(--color-secondary-dark-4);
|
||||
--color-secondary-hover: var(--color-secondary-dark-3);
|
||||
--color-secondary-active: var(--color-secondary-dark-2);
|
||||
/* console colors - used for actions console and console files */
|
||||
--color-console-fg: #f8f8f9;
|
||||
--color-console-fg-subtle: #bec4c8;
|
||||
--color-console-bg: #181b1d;
|
||||
--color-console-border: #313538;
|
||||
--color-console-hover-bg: #ffffff16;
|
||||
--color-console-active-bg: #313538;
|
||||
--color-console-menu-bg: #272b2e;
|
||||
--color-console-menu-border: #464a4d;
|
||||
--color-console-bg: #171b1e;
|
||||
--color-console-border: #2e353b;
|
||||
--color-console-hover-bg: #e8e8ff16;
|
||||
--color-console-active-bg: #2e353b;
|
||||
--color-console-menu-bg: #252b30;
|
||||
--color-console-menu-border: #424b51;
|
||||
/* named colors */
|
||||
--color-red: #cc4848;
|
||||
--color-orange: #cc580c;
|
||||
|
@ -81,7 +81,7 @@
|
|||
--color-purple: #b259d0;
|
||||
--color-pink: #d22e8b;
|
||||
--color-brown: #a47252;
|
||||
--color-black: #1f2326;
|
||||
--color-black: #1d2328;
|
||||
/* light variants - produced via Sass scale-color(color, $lightness: +10%) */
|
||||
--color-red-light: #d15a5a;
|
||||
--color-orange-light: #f6a066;
|
||||
|
@ -94,7 +94,7 @@
|
|||
--color-purple-light: #ba6ad5;
|
||||
--color-pink-light: #d74397;
|
||||
--color-brown-light: #b08061;
|
||||
--color-black-light: #46494d;
|
||||
--color-black-light: #424851;
|
||||
/* dark 1 variants - produced via Sass scale-color(color, $lightness: -10%) */
|
||||
--color-red-dark-1: #c23636;
|
||||
--color-orange-dark-1: #f38236;
|
||||
|
@ -107,7 +107,7 @@
|
|||
--color-purple-dark-1: #a742c9;
|
||||
--color-pink-dark-1: #be297d;
|
||||
--color-brown-dark-1: #94674a;
|
||||
--color-black-dark-1: #2c2f35;
|
||||
--color-black-dark-1: #292e38;
|
||||
/* dark 2 variants - produced via Sass scale-color(color, $lightness: -20%) */
|
||||
--color-red-dark-2: #ad3030;
|
||||
--color-orange-dark-2: #f16e17;
|
||||
|
@ -120,9 +120,9 @@
|
|||
--color-purple-dark-2: #9834b9;
|
||||
--color-pink-dark-2: #a9246f;
|
||||
--color-brown-dark-2: #835b42;
|
||||
--color-black-dark-2: #292a2e;
|
||||
--color-black-dark-2: #272930;
|
||||
/* ansi colors used for actions console and console files */
|
||||
--color-ansi-black: #1f2326;
|
||||
--color-ansi-black: #1d2328;
|
||||
--color-ansi-red: #cc4848;
|
||||
--color-ansi-green: #87ab63;
|
||||
--color-ansi-yellow: #cc9903;
|
||||
|
@ -130,7 +130,7 @@
|
|||
--color-ansi-magenta: #d22e8b;
|
||||
--color-ansi-cyan: #00918a;
|
||||
--color-ansi-white: var(--color-console-fg-subtle);
|
||||
--color-ansi-bright-black: #46494d;
|
||||
--color-ansi-bright-black: #424851;
|
||||
--color-ansi-bright-red: #d15a5a;
|
||||
--color-ansi-bright-green: #93b373;
|
||||
--color-ansi-bright-yellow: #eaaf03;
|
||||
|
@ -139,8 +139,8 @@
|
|||
--color-ansi-bright-cyan: #00b6ad;
|
||||
--color-ansi-bright-white: var(--color-console-fg);
|
||||
/* other colors */
|
||||
--color-grey: #3c4043;
|
||||
--color-grey-light: #898e92;
|
||||
--color-grey: #384147;
|
||||
--color-grey-light: #828f99;
|
||||
--color-gold: #b1983b;
|
||||
--color-white: #ffffff;
|
||||
--color-diff-removed-word-bg: #6f3333;
|
||||
|
@ -151,7 +151,7 @@
|
|||
--color-diff-removed-row-border: #634343;
|
||||
--color-diff-moved-row-border: #bcca6f;
|
||||
--color-diff-added-row-border: #314a37;
|
||||
--color-diff-inactive: #24282b;
|
||||
--color-diff-inactive: #22282d;
|
||||
--color-error-border: #a04141;
|
||||
--color-error-bg: #522;
|
||||
--color-error-bg-active: #744;
|
||||
|
@ -180,10 +180,10 @@
|
|||
--color-orange-badge-hover-bg: #f2711c4d;
|
||||
--color-git: #f05133;
|
||||
/* target-based colors */
|
||||
--color-body: #1f2326;
|
||||
--color-box-header: #202427;
|
||||
--color-box-body: #191d20;
|
||||
--color-box-body-highlight: #1d2124;
|
||||
--color-body: #1e2224;
|
||||
--color-box-header: #1a1d1f;
|
||||
--color-box-body: #14171a;
|
||||
--color-box-body-highlight: #121517;
|
||||
--color-text-dark: #f8f8f9;
|
||||
--color-text: #ced2d5;
|
||||
--color-text-light: #bec4c8;
|
||||
|
@ -191,46 +191,46 @@
|
|||
--color-text-light-2: #8d969c;
|
||||
--color-text-light-3: #747f87;
|
||||
--color-footer: var(--color-nav-bg);
|
||||
--color-timeline: #383c3f;
|
||||
--color-timeline: #353c42;
|
||||
--color-input-text: var(--color-text-dark);
|
||||
--color-input-background: #161a1d;
|
||||
--color-input-toggle-background: #313538;
|
||||
--color-input-background: #151a1e;
|
||||
--color-input-toggle-background: #2e353b;
|
||||
--color-input-border: var(--color-secondary);
|
||||
--color-input-border-hover: var(--color-secondary-dark-1);
|
||||
--color-header-wrapper: #191d20;
|
||||
--color-light: #00000028;
|
||||
--color-header-wrapper: #181c20;
|
||||
--color-light: #00001728;
|
||||
--color-light-mimic-enabled: rgba(0, 0, 0, calc(40 / 255 * 222 / 255 / var(--opacity-disabled)));
|
||||
--color-light-border: #ffffff28;
|
||||
--color-hover: #ffffff19;
|
||||
--color-active: #ffffff24;
|
||||
--color-menu: #161a1d;
|
||||
--color-card: #161a1d;
|
||||
--color-markup-table-row: #ffffff06;
|
||||
--color-markup-code-block: #ffffff16;
|
||||
--color-button: #161a1d;
|
||||
--color-light-border: #e8e8ff28;
|
||||
--color-hover: #e8e8ff19;
|
||||
--color-active: #e8e8ff24;
|
||||
--color-menu: #151a1e;
|
||||
--color-card: #151a1e;
|
||||
--color-markup-table-row: #e8e8ff06;
|
||||
--color-markup-code-block: #e8e8ff16;
|
||||
--color-button: #151a1e;
|
||||
--color-code-bg: #191d20;
|
||||
--color-code-sidebar-bg: #1b1f22;
|
||||
--color-shadow: #00000058;
|
||||
--color-shadow: #00001758;
|
||||
--color-secondary-bg: #2f3135;
|
||||
--color-expand-button: #414348;
|
||||
--color-placeholder-text: var(--color-text-light-3);
|
||||
--color-editor-line-highlight: var(--color-primary-light-5);
|
||||
--color-project-board-bg: var(--color-secondary-light-2);
|
||||
--color-project-board-dark-label: #111111;
|
||||
--color-project-board-light-label: #eeeeee;
|
||||
--color-project-board-dark-label: #0e1011;
|
||||
--color-project-board-light-label: #dde0e2;
|
||||
--color-caret: var(--color-text); /* should ideally be --color-text-dark, see #15651 */
|
||||
--color-reaction-bg: #ffffff12;
|
||||
--color-reaction-bg: #e8e8ff12;
|
||||
--color-reaction-hover-bg: var(--color-primary-light-4);
|
||||
--color-reaction-active-bg: var(--color-primary-light-5);
|
||||
--color-tooltip-text: #ffffff;
|
||||
--color-tooltip-bg: #000000f0;
|
||||
--color-nav-bg: #1b1f22;
|
||||
--color-nav-hover-bg: #272b2e;
|
||||
--color-tooltip-text: #fafafb;
|
||||
--color-tooltip-bg: #000017f0;
|
||||
--color-nav-bg: #16191c;
|
||||
--color-nav-hover-bg: var(--color-secondary-light-1);
|
||||
--color-nav-text: var(--color-text);
|
||||
--color-label-text: var(--color-text);
|
||||
--color-label-bg: #7a7f834b;
|
||||
--color-label-hover-bg: #7a7f83a0;
|
||||
--color-label-active-bg: #7a7f83ff;
|
||||
--color-label-bg: #73828e4b;
|
||||
--color-label-hover-bg: #73828ea0;
|
||||
--color-label-active-bg: #73828eff;
|
||||
--color-accent: var(--color-primary-light-1);
|
||||
--color-small-accent: var(--color-primary-light-5);
|
||||
--color-active-line: #534d1b;
|
||||
|
|
|
@ -30,33 +30,33 @@
|
|||
--color-primary-alpha-90: #4183c4e1;
|
||||
--color-primary-hover: var(--color-primary-dark-1);
|
||||
--color-primary-active: var(--color-primary-dark-2);
|
||||
--color-secondary: #dedede;
|
||||
--color-secondary-dark-1: #cecece;
|
||||
--color-secondary-dark-2: #bfbfbf;
|
||||
--color-secondary-dark-3: #a0a0a0;
|
||||
--color-secondary-dark-4: #909090;
|
||||
--color-secondary-dark-5: #818181;
|
||||
--color-secondary-dark-6: #717171;
|
||||
--color-secondary-dark-7: #626262;
|
||||
--color-secondary-dark-8: #525252;
|
||||
--color-secondary-dark-9: #434343;
|
||||
--color-secondary-dark-10: #333333;
|
||||
--color-secondary-dark-11: #242424;
|
||||
--color-secondary-dark-12: #141414;
|
||||
--color-secondary-dark-13: #040404;
|
||||
--color-secondary-light-1: #e5e5e5;
|
||||
--color-secondary-light-2: #ebebeb;
|
||||
--color-secondary-light-3: #f2f2f2;
|
||||
--color-secondary-light-4: #f8f8f8;
|
||||
--color-secondary-alpha-10: #dedede19;
|
||||
--color-secondary-alpha-20: #dedede33;
|
||||
--color-secondary-alpha-30: #dedede4b;
|
||||
--color-secondary-alpha-40: #dedede66;
|
||||
--color-secondary-alpha-50: #dedede80;
|
||||
--color-secondary-alpha-60: #dedede99;
|
||||
--color-secondary-alpha-70: #dededeb3;
|
||||
--color-secondary-alpha-80: #dededecc;
|
||||
--color-secondary-alpha-90: #dededee1;
|
||||
--color-secondary: #d0d7de;
|
||||
--color-secondary-dark-1: #c7ced5;
|
||||
--color-secondary-dark-2: #b9c0c7;
|
||||
--color-secondary-dark-3: #99a0a7;
|
||||
--color-secondary-dark-4: #899097;
|
||||
--color-secondary-dark-5: #7a8188;
|
||||
--color-secondary-dark-6: #6a7178;
|
||||
--color-secondary-dark-7: #5b6269;
|
||||
--color-secondary-dark-8: #4b5259;
|
||||
--color-secondary-dark-9: #3c434a;
|
||||
--color-secondary-dark-10: #2c333a;
|
||||
--color-secondary-dark-11: #1d242b;
|
||||
--color-secondary-dark-12: #0d141b;
|
||||
--color-secondary-dark-13: #00040b;
|
||||
--color-secondary-light-1: #dee5ec;
|
||||
--color-secondary-light-2: #e4ebf2;
|
||||
--color-secondary-light-3: #ebf2f9;
|
||||
--color-secondary-light-4: #f1f8ff;
|
||||
--color-secondary-alpha-10: #d0d7de19;
|
||||
--color-secondary-alpha-20: #d0d7de33;
|
||||
--color-secondary-alpha-30: #d0d7de4b;
|
||||
--color-secondary-alpha-40: #d0d7de66;
|
||||
--color-secondary-alpha-50: #d0d7de80;
|
||||
--color-secondary-alpha-60: #d0d7de99;
|
||||
--color-secondary-alpha-70: #d0d7deb3;
|
||||
--color-secondary-alpha-80: #d0d7decc;
|
||||
--color-secondary-alpha-90: #d0d7dee1;
|
||||
--color-secondary-button: var(--color-secondary-dark-4);
|
||||
--color-secondary-hover: var(--color-secondary-dark-5);
|
||||
--color-secondary-active: var(--color-secondary-dark-6);
|
||||
|
@ -81,7 +81,7 @@
|
|||
--color-purple: #a333c8;
|
||||
--color-pink: #e03997;
|
||||
--color-brown: #a5673f;
|
||||
--color-black: #1b1c1d;
|
||||
--color-black: #191c1d;
|
||||
/* light variants - produced via Sass scale-color(color, $lightness: +25%) */
|
||||
--color-red-light: #e45e5e;
|
||||
--color-orange-light: #f59555;
|
||||
|
@ -107,7 +107,7 @@
|
|||
--color-purple-dark-1: #932eb4;
|
||||
--color-pink-dark-1: #db228a;
|
||||
--color-brown-dark-1: #955d39;
|
||||
--color-black-dark-1: #18191a;
|
||||
--color-black-dark-1: #16191c;
|
||||
/* dark 2 variants - produced via Sass scale-color(color, $lightness: -20%) */
|
||||
--color-red-dark-2: #b11e1e;
|
||||
--color-orange-dark-2: #cc580c;
|
||||
|
@ -120,7 +120,7 @@
|
|||
--color-purple-dark-2: #8229a0;
|
||||
--color-pink-dark-2: #c21e7b;
|
||||
--color-brown-dark-2: #845232;
|
||||
--color-black-dark-2: #161617;
|
||||
--color-black-dark-2: #131619;
|
||||
/* ansi colors used for actions console and console files */
|
||||
--color-ansi-black: #1f2326;
|
||||
--color-ansi-red: #cc4848;
|
||||
|
@ -139,8 +139,8 @@
|
|||
--color-ansi-bright-cyan: #00b6ad;
|
||||
--color-ansi-bright-white: var(--color-console-fg);
|
||||
/* other colors */
|
||||
--color-grey: #707070;
|
||||
--color-grey-light: #838383;
|
||||
--color-grey: #697077;
|
||||
--color-grey-light: #7c838a;
|
||||
--color-gold: #a1882b;
|
||||
--color-white: #ffffff;
|
||||
--color-diff-removed-word-bg: #fdb8c0;
|
||||
|
@ -151,7 +151,7 @@
|
|||
--color-diff-removed-row-border: #f1c0c0;
|
||||
--color-diff-moved-row-border: #d0e27f;
|
||||
--color-diff-added-row-border: #e6ffed;
|
||||
--color-diff-inactive: #f2f2f2;
|
||||
--color-diff-inactive: #f0f2f4;
|
||||
--color-error-border: #e0b4b4;
|
||||
--color-error-bg: #fff6f6;
|
||||
--color-error-bg-active: #fbb;
|
||||
|
@ -181,56 +181,56 @@
|
|||
--color-git: #f05133;
|
||||
/* target-based colors */
|
||||
--color-body: #ffffff;
|
||||
--color-box-header: #f7f7f7;
|
||||
--color-box-header: #f1f3f5;
|
||||
--color-box-body: #ffffff;
|
||||
--color-box-body-highlight: #fafafa;
|
||||
--color-text-dark: #080808;
|
||||
--color-text: #212121;
|
||||
--color-text-light: #555555;
|
||||
--color-text-light-1: #6a6a6a;
|
||||
--color-text-light-2: #808080;
|
||||
--color-text-light-3: #a0a0a0;
|
||||
--color-box-body-highlight: #f4faff;
|
||||
--color-text-dark: #03080d;
|
||||
--color-text: #1c2126;
|
||||
--color-text-light: #3c434a;
|
||||
--color-text-light-1: #4b5259;
|
||||
--color-text-light-2: #6a7178;
|
||||
--color-text-light-3: #899097;
|
||||
--color-footer: var(--color-nav-bg);
|
||||
--color-timeline: #ececec;
|
||||
--color-timeline: #d0d7de;
|
||||
--color-input-text: var(--color-text-dark);
|
||||
--color-input-background: #fafafa;
|
||||
--color-input-toggle-background: #dedede;
|
||||
--color-input-background: #f8f9fb;
|
||||
--color-input-toggle-background: #d0d7de;
|
||||
--color-input-border: var(--color-secondary);
|
||||
--color-input-border-hover: var(--color-secondary-dark-1);
|
||||
--color-header-wrapper: transparent;
|
||||
--color-light: #00000006;
|
||||
--color-header-wrapper: #fafbfc;
|
||||
--color-light: #00001706;
|
||||
--color-light-mimic-enabled: rgba(0, 0, 0, calc(6 / 255 * 222 / 255 / var(--opacity-disabled)));
|
||||
--color-light-border: #0000001d;
|
||||
--color-hover: #00000014;
|
||||
--color-active: #0000001b;
|
||||
--color-menu: #fafafa;
|
||||
--color-card: #fafafa;
|
||||
--color-markup-table-row: #00000008;
|
||||
--color-markup-code-block: #00000010;
|
||||
--color-button: #fafafa;
|
||||
--color-code-bg: #ffffff;
|
||||
--color-code-sidebar-bg: #f5f5f5;
|
||||
--color-shadow: #00000026;
|
||||
--color-secondary-bg: #f4f4f4;
|
||||
--color-light-border: #0000171d;
|
||||
--color-hover: #00001708;
|
||||
--color-active: #00001714;
|
||||
--color-menu: #f8f9fb;
|
||||
--color-card: #f8f9fb;
|
||||
--color-markup-table-row: #00001708;
|
||||
--color-markup-code-block: #00001710;
|
||||
--color-button: #f8f9fb;
|
||||
--color-code-bg: #fafdff;
|
||||
--color-code-sidebar-bg: #f2f5f8;
|
||||
--color-shadow: #00001726;
|
||||
--color-secondary-bg: #f2f5f8;
|
||||
--color-expand-button: #d8efff;
|
||||
--color-placeholder-text: var(--color-text-light-3);
|
||||
--color-editor-line-highlight: var(--color-primary-light-6);
|
||||
--color-project-board-bg: var(--color-secondary-light-4);
|
||||
--color-project-board-dark-label: #111111;
|
||||
--color-project-board-light-label: #eeeeee;
|
||||
--color-project-board-dark-label: #0e1114;
|
||||
--color-project-board-light-label: #eaeef2;
|
||||
--color-caret: var(--color-text-dark);
|
||||
--color-reaction-bg: #0000000a;
|
||||
--color-reaction-bg: #0000170a;
|
||||
--color-reaction-hover-bg: var(--color-primary-light-5);
|
||||
--color-reaction-active-bg: var(--color-primary-light-6);
|
||||
--color-tooltip-text: #ffffff;
|
||||
--color-tooltip-bg: #000000f0;
|
||||
--color-nav-bg: #ffffff;
|
||||
--color-nav-hover-bg: #ebebeb;
|
||||
--color-tooltip-text: #fbfdff;
|
||||
--color-tooltip-bg: #000017f0;
|
||||
--color-nav-bg: #f8f9fb;
|
||||
--color-nav-hover-bg: var(--color-secondary-light-1);
|
||||
--color-nav-text: var(--color-text);
|
||||
--color-label-text: var(--color-text);
|
||||
--color-label-bg: #9d9d9d4b;
|
||||
--color-label-hover-bg: #9d9d9da0;
|
||||
--color-label-active-bg: #9d9d9dff;
|
||||
--color-label-bg: #949da64b;
|
||||
--color-label-hover-bg: #949da6a0;
|
||||
--color-label-active-bg: #949da6ff;
|
||||
--color-accent: var(--color-primary-light-1);
|
||||
--color-small-accent: var(--color-primary-light-6);
|
||||
--color-active-line: #fffbdd;
|
||||
|
|
684
web_src/fomantic/build/semantic.css
generated
684
web_src/fomantic/build/semantic.css
generated
|
@ -14926,690 +14926,6 @@ Floated Menu / Item
|
|||
/*******************************
|
||||
Site Overrides
|
||||
*******************************/
|
||||
/*!
|
||||
* # Fomantic-UI - Message
|
||||
* http://github.com/fomantic/Fomantic-UI/
|
||||
*
|
||||
*
|
||||
* Released under the MIT license
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
*/
|
||||
|
||||
/*******************************
|
||||
Message
|
||||
*******************************/
|
||||
|
||||
.ui.message {
|
||||
position: relative;
|
||||
min-height: 1em;
|
||||
margin: 1em 0;
|
||||
background: #F8F8F9;
|
||||
padding: 1em 1.5em;
|
||||
line-height: 1.4285em;
|
||||
color: rgba(0, 0, 0, 0.87);
|
||||
transition: opacity 0.1s ease, color 0.1s ease, background 0.1s ease, box-shadow 0.1s ease;
|
||||
border-radius: 0.28571429rem;
|
||||
box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.22) inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.message:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ui.message:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Content
|
||||
---------------*/
|
||||
|
||||
/* Header */
|
||||
|
||||
.ui.message .header {
|
||||
display: block;
|
||||
font-family: var(--fonts-regular);
|
||||
font-weight: 500;
|
||||
margin: -0.14285714em 0 0 0;
|
||||
}
|
||||
|
||||
/* Default font size */
|
||||
|
||||
.ui.message .header:not(.ui) {
|
||||
font-size: 1.14285714em;
|
||||
}
|
||||
|
||||
/* Paragraph */
|
||||
|
||||
.ui.message p {
|
||||
opacity: 0.85;
|
||||
margin: 0.75em 0;
|
||||
}
|
||||
|
||||
.ui.message p:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ui.message p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ui.message .header + p {
|
||||
margin-top: 0.25em;
|
||||
}
|
||||
|
||||
/* List */
|
||||
|
||||
.ui.message .list:not(.ui) {
|
||||
text-align: left;
|
||||
padding: 0;
|
||||
opacity: 0.85;
|
||||
list-style-position: inside;
|
||||
margin: 0.5em 0 0;
|
||||
}
|
||||
|
||||
.ui.message .list:not(.ui):first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ui.message .list:not(.ui):last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ui.message .list:not(.ui) li {
|
||||
position: relative;
|
||||
list-style-type: none;
|
||||
margin: 0 0 0.3em 1em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ui.message .list:not(.ui) li:before {
|
||||
position: absolute;
|
||||
content: '•';
|
||||
left: -1em;
|
||||
height: 100%;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
.ui.message .list:not(.ui) li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Icon */
|
||||
|
||||
.ui.message > i.icon {
|
||||
margin-right: 0.6em;
|
||||
}
|
||||
|
||||
/* Close Icon */
|
||||
|
||||
.ui.message > .close.icon {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
top: 0.78575em;
|
||||
right: 0.5em;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.1s ease;
|
||||
}
|
||||
|
||||
.ui.message > .close.icon:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* First / Last Element */
|
||||
|
||||
.ui.message > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ui.message > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
Coupling
|
||||
*******************************/
|
||||
|
||||
.ui.dropdown .menu > .message {
|
||||
margin: 0 -1px;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
States
|
||||
*******************************/
|
||||
|
||||
/*--------------
|
||||
Visible
|
||||
---------------*/
|
||||
|
||||
.ui.visible.visible.visible.visible.message {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ui.icon.visible.visible.visible.visible.message {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Hidden
|
||||
---------------*/
|
||||
|
||||
.ui.hidden.hidden.hidden.hidden.message {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
Variations
|
||||
*******************************/
|
||||
|
||||
/*--------------
|
||||
Compact
|
||||
---------------*/
|
||||
|
||||
.ui.compact.message {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.ui.compact.icon.message {
|
||||
display: inline-flex;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Attached
|
||||
---------------*/
|
||||
|
||||
.ui.attached.message {
|
||||
margin-bottom: -1px;
|
||||
border-radius: 0.28571429rem 0.28571429rem 0 0;
|
||||
box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.15) inset;
|
||||
margin-left: -1px;
|
||||
margin-right: -1px;
|
||||
}
|
||||
|
||||
.ui.attached + .ui.attached.message:not(.top):not(.bottom) {
|
||||
margin-top: -1px;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.ui.bottom.attached.message {
|
||||
margin-top: -1px;
|
||||
border-radius: 0 0 0.28571429rem 0.28571429rem;
|
||||
box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.15) inset, 0 1px 2px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.bottom.attached.message:not(:last-child) {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.ui.attached.icon.message {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Icon
|
||||
---------------*/
|
||||
|
||||
.ui.icon.message {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ui.icon.message > i.icon:not(.close) {
|
||||
display: block;
|
||||
flex: 0 0 auto;
|
||||
width: auto;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
font-size: 3em;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.ui.icon.message > .content {
|
||||
display: block;
|
||||
flex: 1 1 auto;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.ui.icon.message > i.icon:not(.close) + .content {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.ui.icon.message > i.circular.icon {
|
||||
width: 1em;
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Floating
|
||||
---------------*/
|
||||
|
||||
.ui.floating.message {
|
||||
box-shadow: 0 0 0 1px rgba(34, 36, 38, 0.22) inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Colors
|
||||
---------------*/
|
||||
|
||||
/*--------------
|
||||
Types
|
||||
---------------*/
|
||||
|
||||
.ui.positive.message {
|
||||
background-color: #FCFFF5;
|
||||
color: #2C662D;
|
||||
}
|
||||
|
||||
.ui.positive.message,
|
||||
.ui.attached.positive.message {
|
||||
box-shadow: 0 0 0 1px #A3C293 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.positive.message {
|
||||
box-shadow: 0 0 0 1px #A3C293 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.positive.message .header {
|
||||
color: #1A531B;
|
||||
}
|
||||
|
||||
.ui.negative.message {
|
||||
background-color: #FFF6F6;
|
||||
color: #9F3A38;
|
||||
}
|
||||
|
||||
.ui.negative.message,
|
||||
.ui.attached.negative.message {
|
||||
box-shadow: 0 0 0 1px #E0B4B4 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.negative.message {
|
||||
box-shadow: 0 0 0 1px #E0B4B4 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.negative.message .header {
|
||||
color: #912D2B;
|
||||
}
|
||||
|
||||
.ui.info.message {
|
||||
background-color: #F8FFFF;
|
||||
color: #276F86;
|
||||
}
|
||||
|
||||
.ui.info.message,
|
||||
.ui.attached.info.message {
|
||||
box-shadow: 0 0 0 1px #A9D5DE inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.info.message {
|
||||
box-shadow: 0 0 0 1px #A9D5DE inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.info.message .header {
|
||||
color: #0E566C;
|
||||
}
|
||||
|
||||
.ui.warning.message {
|
||||
background-color: #FFFAF3;
|
||||
color: #573A08;
|
||||
}
|
||||
|
||||
.ui.warning.message,
|
||||
.ui.attached.warning.message {
|
||||
box-shadow: 0 0 0 1px #C9BA9B inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.warning.message {
|
||||
box-shadow: 0 0 0 1px #C9BA9B inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.warning.message .header {
|
||||
color: #794B02;
|
||||
}
|
||||
|
||||
.ui.error.message {
|
||||
background-color: #FFF6F6;
|
||||
color: #9F3A38;
|
||||
}
|
||||
|
||||
.ui.error.message,
|
||||
.ui.attached.error.message {
|
||||
box-shadow: 0 0 0 1px #E0B4B4 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.error.message {
|
||||
box-shadow: 0 0 0 1px #E0B4B4 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.error.message .header {
|
||||
color: #912D2B;
|
||||
}
|
||||
|
||||
.ui.success.message {
|
||||
background-color: #FCFFF5;
|
||||
color: #2C662D;
|
||||
}
|
||||
|
||||
.ui.success.message,
|
||||
.ui.attached.success.message {
|
||||
box-shadow: 0 0 0 1px #A3C293 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.success.message {
|
||||
box-shadow: 0 0 0 1px #A3C293 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.success.message .header {
|
||||
color: #1A531B;
|
||||
}
|
||||
|
||||
.ui.primary.message {
|
||||
background-color: #DFF0FF;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.ui.primary.message,
|
||||
.ui.attached.primary.message {
|
||||
box-shadow: 0 0 0 1px #2185D0 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.primary.message {
|
||||
box-shadow: 0 0 0 1px #2185D0 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.primary.message .header {
|
||||
color: rgba(242, 242, 242, 0.9);
|
||||
}
|
||||
|
||||
.ui.secondary.message {
|
||||
background-color: #F4F4F4;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.ui.secondary.message,
|
||||
.ui.attached.secondary.message {
|
||||
box-shadow: 0 0 0 1px #1B1C1D inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.secondary.message {
|
||||
box-shadow: 0 0 0 1px #1B1C1D inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.secondary.message .header {
|
||||
color: rgba(242, 242, 242, 0.9);
|
||||
}
|
||||
|
||||
.ui.red.message {
|
||||
background-color: #FFE8E6;
|
||||
color: #DB2828;
|
||||
}
|
||||
|
||||
.ui.red.message,
|
||||
.ui.attached.red.message {
|
||||
box-shadow: 0 0 0 1px #DB2828 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.red.message {
|
||||
box-shadow: 0 0 0 1px #DB2828 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.red.message .header {
|
||||
color: #c82121;
|
||||
}
|
||||
|
||||
.ui.orange.message {
|
||||
background-color: #FFEDDE;
|
||||
color: #F2711C;
|
||||
}
|
||||
|
||||
.ui.orange.message,
|
||||
.ui.attached.orange.message {
|
||||
box-shadow: 0 0 0 1px #F2711C inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.orange.message {
|
||||
box-shadow: 0 0 0 1px #F2711C inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.orange.message .header {
|
||||
color: #e7640d;
|
||||
}
|
||||
|
||||
.ui.yellow.message {
|
||||
background-color: #FFF8DB;
|
||||
color: #B58105;
|
||||
}
|
||||
|
||||
.ui.yellow.message,
|
||||
.ui.attached.yellow.message {
|
||||
box-shadow: 0 0 0 1px #B58105 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.yellow.message {
|
||||
box-shadow: 0 0 0 1px #B58105 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.yellow.message .header {
|
||||
color: #9c6f04;
|
||||
}
|
||||
|
||||
.ui.olive.message {
|
||||
background-color: #FBFDEF;
|
||||
color: #8ABC1E;
|
||||
}
|
||||
|
||||
.ui.olive.message,
|
||||
.ui.attached.olive.message {
|
||||
box-shadow: 0 0 0 1px #8ABC1E inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.olive.message {
|
||||
box-shadow: 0 0 0 1px #8ABC1E inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.olive.message .header {
|
||||
color: #7aa61a;
|
||||
}
|
||||
|
||||
.ui.green.message {
|
||||
background-color: #E5F9E7;
|
||||
color: #1EBC30;
|
||||
}
|
||||
|
||||
.ui.green.message,
|
||||
.ui.attached.green.message {
|
||||
box-shadow: 0 0 0 1px #1EBC30 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.green.message {
|
||||
box-shadow: 0 0 0 1px #1EBC30 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.green.message .header {
|
||||
color: #1aa62a;
|
||||
}
|
||||
|
||||
.ui.teal.message {
|
||||
background-color: #E1F7F7;
|
||||
color: #10A3A3;
|
||||
}
|
||||
|
||||
.ui.teal.message,
|
||||
.ui.attached.teal.message {
|
||||
box-shadow: 0 0 0 1px #10A3A3 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.teal.message {
|
||||
box-shadow: 0 0 0 1px #10A3A3 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.teal.message .header {
|
||||
color: #0e8c8c;
|
||||
}
|
||||
|
||||
.ui.blue.message {
|
||||
background-color: #DFF0FF;
|
||||
color: #2185D0;
|
||||
}
|
||||
|
||||
.ui.blue.message,
|
||||
.ui.attached.blue.message {
|
||||
box-shadow: 0 0 0 1px #2185D0 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.blue.message {
|
||||
box-shadow: 0 0 0 1px #2185D0 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.blue.message .header {
|
||||
color: #1e77ba;
|
||||
}
|
||||
|
||||
.ui.violet.message {
|
||||
background-color: #EAE7FF;
|
||||
color: #6435C9;
|
||||
}
|
||||
|
||||
.ui.violet.message,
|
||||
.ui.attached.violet.message {
|
||||
box-shadow: 0 0 0 1px #6435C9 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.violet.message {
|
||||
box-shadow: 0 0 0 1px #6435C9 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.violet.message .header {
|
||||
color: #5a30b5;
|
||||
}
|
||||
|
||||
.ui.purple.message {
|
||||
background-color: #F6E7FF;
|
||||
color: #A333C8;
|
||||
}
|
||||
|
||||
.ui.purple.message,
|
||||
.ui.attached.purple.message {
|
||||
box-shadow: 0 0 0 1px #A333C8 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.purple.message {
|
||||
box-shadow: 0 0 0 1px #A333C8 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.purple.message .header {
|
||||
color: #922eb4;
|
||||
}
|
||||
|
||||
.ui.pink.message {
|
||||
background-color: #FFE3FB;
|
||||
color: #E03997;
|
||||
}
|
||||
|
||||
.ui.pink.message,
|
||||
.ui.attached.pink.message {
|
||||
box-shadow: 0 0 0 1px #E03997 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.pink.message {
|
||||
box-shadow: 0 0 0 1px #E03997 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.pink.message .header {
|
||||
color: #dd238b;
|
||||
}
|
||||
|
||||
.ui.brown.message {
|
||||
background-color: #F1E2D3;
|
||||
color: #A5673F;
|
||||
}
|
||||
|
||||
.ui.brown.message,
|
||||
.ui.attached.brown.message {
|
||||
box-shadow: 0 0 0 1px #A5673F inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.brown.message {
|
||||
box-shadow: 0 0 0 1px #A5673F inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.brown.message .header {
|
||||
color: #935b38;
|
||||
}
|
||||
|
||||
.ui.grey.message {
|
||||
background-color: #F4F4F4;
|
||||
color: #767676;
|
||||
}
|
||||
|
||||
.ui.grey.message,
|
||||
.ui.attached.grey.message {
|
||||
box-shadow: 0 0 0 1px #767676 inset, 0 0 0 0 rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.ui.floating.grey.message {
|
||||
box-shadow: 0 0 0 1px #767676 inset, 0 2px 4px 0 rgba(34, 36, 38, 0.12), 0 2px 10px 0 rgba(34, 36, 38, 0.15);
|
||||
}
|
||||
|
||||
.ui.grey.message .header {
|
||||
color: #696969;
|
||||
}
|
||||
|
||||
.ui.black.message {
|
||||
background-color: #1B1C1D;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.ui.black.message .header {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
/*--------------
|
||||
Sizes
|
||||
---------------*/
|
||||
|
||||
.ui.message {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.ui.mini.message {
|
||||
font-size: 0.78571429em;
|
||||
}
|
||||
|
||||
.ui.tiny.message {
|
||||
font-size: 0.85714286em;
|
||||
}
|
||||
|
||||
.ui.small.message {
|
||||
font-size: 0.92857143em;
|
||||
}
|
||||
|
||||
.ui.large.message {
|
||||
font-size: 1.14285714em;
|
||||
}
|
||||
|
||||
.ui.big.message {
|
||||
font-size: 1.28571429em;
|
||||
}
|
||||
|
||||
.ui.huge.message {
|
||||
font-size: 1.42857143em;
|
||||
}
|
||||
|
||||
.ui.massive.message {
|
||||
font-size: 1.71428571em;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
Theme Overrides
|
||||
*******************************/
|
||||
|
||||
/*******************************
|
||||
Site Overrides
|
||||
*******************************/
|
||||
/*!
|
||||
* # Fomantic-UI - Modal
|
||||
* http://github.com/fomantic/Fomantic-UI/
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
"label",
|
||||
"list",
|
||||
"menu",
|
||||
"message",
|
||||
"modal",
|
||||
"search",
|
||||
"segment",
|
||||
|
|
|
@ -384,28 +384,30 @@ export default sfc; // activate the IDE's Vue plugin
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui secondary tiny pointing borderless menu center grid repos-filter">
|
||||
<a class="item" :class="{active: reposFilter === 'all'}" @click="changeReposFilter('all')">
|
||||
{{ textAll }}
|
||||
<div v-show="reposFilter === 'all'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
<a class="item" :class="{active: reposFilter === 'sources'}" @click="changeReposFilter('sources')">
|
||||
{{ textSources }}
|
||||
<div v-show="reposFilter === 'sources'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
<a class="item" :class="{active: reposFilter === 'forks'}" @click="changeReposFilter('forks')">
|
||||
{{ textForks }}
|
||||
<div v-show="reposFilter === 'forks'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
<a class="item" :class="{active: reposFilter === 'mirrors'}" @click="changeReposFilter('mirrors')" v-if="isMirrorsEnabled">
|
||||
{{ textMirrors }}
|
||||
<div v-show="reposFilter === 'mirrors'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
<a class="item" :class="{active: reposFilter === 'collaborative'}" @click="changeReposFilter('collaborative')">
|
||||
{{ textCollaborative }}
|
||||
<div v-show="reposFilter === 'collaborative'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
</div>
|
||||
<overflow-menu class="ui secondary pointing tabular borderless menu repos-filter">
|
||||
<div class="overflow-menu-items tw-justify-center">
|
||||
<a class="item" tabindex="0" :class="{active: reposFilter === 'all'}" @click="changeReposFilter('all')">
|
||||
{{ textAll }}
|
||||
<div v-show="reposFilter === 'all'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
<a class="item" tabindex="0" :class="{active: reposFilter === 'sources'}" @click="changeReposFilter('sources')">
|
||||
{{ textSources }}
|
||||
<div v-show="reposFilter === 'sources'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
<a class="item" tabindex="0" :class="{active: reposFilter === 'forks'}" @click="changeReposFilter('forks')">
|
||||
{{ textForks }}
|
||||
<div v-show="reposFilter === 'forks'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
<a class="item" tabindex="0" :class="{active: reposFilter === 'mirrors'}" @click="changeReposFilter('mirrors')" v-if="isMirrorsEnabled">
|
||||
{{ textMirrors }}
|
||||
<div v-show="reposFilter === 'mirrors'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
<a class="item" tabindex="0" :class="{active: reposFilter === 'collaborative'}" @click="changeReposFilter('collaborative')">
|
||||
{{ textCollaborative }}
|
||||
<div v-show="reposFilter === 'collaborative'" class="ui circular mini grey label">{{ repoTypeCount }}</div>
|
||||
</a>
|
||||
</div>
|
||||
</overflow-menu>
|
||||
</div>
|
||||
<div v-if="repos.length" class="ui attached table segment gt-rounded-bottom">
|
||||
<ul class="repo-owner-name-list">
|
||||
|
@ -501,6 +503,22 @@ ul li:not(:last-child) {
|
|||
border-bottom: 1px solid var(--color-secondary);
|
||||
}
|
||||
|
||||
.repos-search {
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.repos-filter {
|
||||
padding-top: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
border-bottom-width: 0 !important;
|
||||
margin-bottom: 2px !important;
|
||||
}
|
||||
|
||||
.repos-filter .item {
|
||||
padding-left: 6px !important;
|
||||
padding-right: 6px !important;
|
||||
}
|
||||
|
||||
.repo-list-link {
|
||||
min-width: 0; /* for text truncation */
|
||||
display: flex;
|
||||
|
|
|
@ -248,7 +248,7 @@ export default {
|
|||
{{ commit.committer_or_author_name }}
|
||||
<span class="text right">
|
||||
<!-- TODO: make this respect the PreferredTimestampTense setting -->
|
||||
<relative-time class="time-since" prefix="" :datetime="commit.time" data-tooltip-content data-tooltip-interactive="true">{{ commit.time }}</relative-time>
|
||||
<relative-time prefix="" :datetime="commit.time" data-tooltip-content data-tooltip-interactive="true">{{ commit.time }}</relative-time>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@ import {createApp} from 'vue';
|
|||
import {toggleElem} from '../utils/dom.js';
|
||||
import {formatDatetime} from '../utils/time.js';
|
||||
import {renderAnsi} from '../render/ansi.js';
|
||||
import {POST, DELETE} from '../modules/fetch.js';
|
||||
import {GET, POST, DELETE} from '../modules/fetch.js';
|
||||
|
||||
const sfc = {
|
||||
name: 'RepoActionView',
|
||||
|
@ -199,7 +199,7 @@ const sfc = {
|
|||
},
|
||||
|
||||
async fetchArtifacts() {
|
||||
const resp = await POST(`${this.actionsURL}/runs/${this.runIndex}/artifacts`);
|
||||
const resp = await GET(`${this.actionsURL}/runs/${this.runIndex}/artifacts`);
|
||||
return await resp.json();
|
||||
},
|
||||
|
||||
|
@ -466,7 +466,7 @@ export function initRepositoryActionView() {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="job-step-container" ref="steps">
|
||||
<div class="job-step-container" ref="steps" v-if="currentJob.steps.length">
|
||||
<div class="job-step-section" v-for="(jobStep, i) in currentJob.steps" :key="i">
|
||||
<div class="job-step-summary" @click.stop="toggleStepLogs(i)" :class="currentJobStepsStates[i].expanded ? 'selected' : ''">
|
||||
<!-- If the job is done and the job step log is loaded for the first time, show the loading icon
|
||||
|
@ -533,7 +533,7 @@ export function initRepositoryActionView() {
|
|||
width: 30%;
|
||||
max-width: 400px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
top: 12px;
|
||||
max-height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
@ -695,11 +695,15 @@ export function initRepositoryActionView() {
|
|||
background-color: var(--color-console-bg);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
||||
border-radius: var(--border-radius);
|
||||
height: 60px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.job-info-header:has(+ .job-step-container) {
|
||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
||||
}
|
||||
|
||||
.job-info-header .job-info-header-title {
|
||||
color: var(--color-console-fg);
|
||||
font-size: 16px;
|
||||
|
|
|
@ -123,7 +123,7 @@ const sfc = {
|
|||
return -1;
|
||||
},
|
||||
scrollToActive() {
|
||||
let el = this.$refs[`listItem${this.active}`];
|
||||
let el = this.$refs[`listItem${this.active}`]; // eslint-disable-line no-jquery/variable-pattern
|
||||
if (!el || !el.length) return;
|
||||
if (Array.isArray(el)) {
|
||||
el = el[0];
|
||||
|
|
|
@ -49,7 +49,7 @@ export function initAdminCommon() {
|
|||
}
|
||||
|
||||
function onUsePagedSearchChange() {
|
||||
if ($('#use_paged_search').prop('checked')) {
|
||||
if (document.getElementById('use_paged_search').checked) {
|
||||
showElem('.search-page-size');
|
||||
$('.search-page-size').find('input').attr('required', 'required');
|
||||
} else {
|
||||
|
|
|
@ -12,7 +12,7 @@ export function initAdminUserListSearchForm() {
|
|||
if (searchForm.StatusFilterMap) {
|
||||
for (const [k, v] of Object.entries(searchForm.StatusFilterMap)) {
|
||||
if (!v) continue;
|
||||
$form.find(`input[name="status_filter[${k}]"][value=${v}]`).prop('checked', true);
|
||||
$form.find(`input[name="status_filter[${k}]"][value=${v}]`).checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ export function initAdminUserListSearchForm() {
|
|||
$form.find(`input[type=radio]`).each((_, e) => {
|
||||
const $e = $(e);
|
||||
if ($e.attr('name').startsWith('status_filter[')) {
|
||||
$e.prop('checked', false);
|
||||
$e.checked = false;
|
||||
}
|
||||
});
|
||||
$form.trigger('submit');
|
||||
|
|
|
@ -40,28 +40,35 @@ export async function initCitationFileCopyContent() {
|
|||
$citationCopyApa.toggleClass('primary', !isBibtex);
|
||||
};
|
||||
|
||||
try {
|
||||
await initInputCitationValue($citationCopyApa, $citationCopyBibtex);
|
||||
} catch (e) {
|
||||
console.error(`initCitationFileCopyContent error: ${e}`, e);
|
||||
return;
|
||||
}
|
||||
updateUi();
|
||||
$('#cite-repo-button').on('click', async (e) => {
|
||||
const dropdownBtn = e.target.closest('.ui.dropdown.button');
|
||||
dropdownBtn.classList.add('is-loading');
|
||||
|
||||
$citationCopyApa.on('click', () => {
|
||||
localStorage.setItem('citation-copy-format', 'apa');
|
||||
updateUi();
|
||||
});
|
||||
$citationCopyBibtex.on('click', () => {
|
||||
localStorage.setItem('citation-copy-format', 'bibtex');
|
||||
updateUi();
|
||||
});
|
||||
try {
|
||||
try {
|
||||
await initInputCitationValue($citationCopyApa, $citationCopyBibtex);
|
||||
} catch (e) {
|
||||
console.error(`initCitationFileCopyContent error: ${e}`, e);
|
||||
return;
|
||||
}
|
||||
updateUi();
|
||||
|
||||
$inputContent.on('click', () => {
|
||||
$inputContent.trigger('select');
|
||||
});
|
||||
$citationCopyApa.on('click', () => {
|
||||
localStorage.setItem('citation-copy-format', 'apa');
|
||||
updateUi();
|
||||
});
|
||||
$citationCopyBibtex.on('click', () => {
|
||||
localStorage.setItem('citation-copy-format', 'bibtex');
|
||||
updateUi();
|
||||
});
|
||||
|
||||
$inputContent.on('click', () => {
|
||||
$inputContent.trigger('select');
|
||||
});
|
||||
} finally {
|
||||
dropdownBtn.classList.remove('is-loading');
|
||||
}
|
||||
|
||||
$('#cite-repo-button').on('click', () => {
|
||||
$('#cite-repo-modal').modal('show');
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,10 +15,8 @@ export function initGlobalCopyToClipboardListener() {
|
|||
|
||||
e.preventDefault();
|
||||
|
||||
let text;
|
||||
if (target.hasAttribute('data-clipboard-text')) {
|
||||
text = target.getAttribute('data-clipboard-text');
|
||||
} else {
|
||||
let text = target.getAttribute('data-clipboard-text');
|
||||
if (!text) {
|
||||
text = document.querySelector(target.getAttribute('data-clipboard-target'))?.value;
|
||||
}
|
||||
|
||||
|
|
|
@ -231,8 +231,8 @@ export function initDropzone(el) {
|
|||
init() {
|
||||
this.on('success', (file, data) => {
|
||||
file.uuid = data.uuid;
|
||||
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
||||
$dropzone.find('.files').append(input);
|
||||
const $input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
||||
$dropzone.find('.files').append($input);
|
||||
// Create a "Copy Link" element, to conveniently copy the image
|
||||
// or file link as Markdown to the clipboard
|
||||
const copyLinkElement = document.createElement('div');
|
||||
|
@ -305,15 +305,15 @@ export function initGlobalLinkActions() {
|
|||
filter += `#${$this.attr('data-modal-id')}`;
|
||||
}
|
||||
|
||||
const dialog = $(`.delete.modal${filter}`);
|
||||
dialog.find('.name').text($this.data('name'));
|
||||
const $dialog = $(`.delete.modal${filter}`);
|
||||
$dialog.find('.name').text($this.data('name'));
|
||||
for (const [key, value] of Object.entries(dataArray)) {
|
||||
if (key && key.startsWith('data')) {
|
||||
dialog.find(`.${key}`).text(value);
|
||||
$dialog.find(`.${key}`).text(value);
|
||||
}
|
||||
}
|
||||
|
||||
dialog.modal({
|
||||
$dialog.modal({
|
||||
closable: false,
|
||||
onApprove: async () => {
|
||||
if ($this.data('type') === 'form') {
|
||||
|
@ -380,8 +380,8 @@ function initGlobalShowModal() {
|
|||
$attrTarget.text(attrib.value); // FIXME: it should be more strict here, only handle div/span/p
|
||||
}
|
||||
}
|
||||
const colorPickers = $modal.find('.color-picker');
|
||||
if (colorPickers.length > 0) {
|
||||
const $colorPickers = $modal.find('.color-picker');
|
||||
if ($colorPickers.length > 0) {
|
||||
initCompColorPicker(); // FIXME: this might cause duplicate init
|
||||
}
|
||||
$modal.modal('setting', {
|
||||
|
|
|
@ -6,23 +6,23 @@ function isExclusiveScopeName(name) {
|
|||
}
|
||||
|
||||
function updateExclusiveLabelEdit(form) {
|
||||
const nameInput = $(`${form} .label-name-input`);
|
||||
const exclusiveField = $(`${form} .label-exclusive-input-field`);
|
||||
const exclusiveCheckbox = $(`${form} .label-exclusive-input`);
|
||||
const exclusiveWarning = $(`${form} .label-exclusive-warning`);
|
||||
const $nameInput = $(`${form} .label-name-input`);
|
||||
const $exclusiveField = $(`${form} .label-exclusive-input-field`);
|
||||
const $exclusiveCheckbox = $(`${form} .label-exclusive-input`);
|
||||
const $exclusiveWarning = $(`${form} .label-exclusive-warning`);
|
||||
|
||||
if (isExclusiveScopeName(nameInput.val())) {
|
||||
exclusiveField.removeClass('muted');
|
||||
exclusiveField.removeAttr('aria-disabled');
|
||||
if (exclusiveCheckbox.prop('checked') && exclusiveCheckbox.data('exclusive-warn')) {
|
||||
exclusiveWarning.removeClass('gt-hidden');
|
||||
if (isExclusiveScopeName($nameInput.val())) {
|
||||
$exclusiveField.removeClass('muted');
|
||||
$exclusiveField.removeAttr('aria-disabled');
|
||||
if ($exclusiveCheckbox[0].checked && $exclusiveCheckbox.data('exclusive-warn')) {
|
||||
$exclusiveWarning.removeClass('gt-hidden');
|
||||
} else {
|
||||
exclusiveWarning.addClass('gt-hidden');
|
||||
$exclusiveWarning.addClass('gt-hidden');
|
||||
}
|
||||
} else {
|
||||
exclusiveField.addClass('muted');
|
||||
exclusiveField.attr('aria-disabled', 'true');
|
||||
exclusiveWarning.addClass('gt-hidden');
|
||||
$exclusiveField.addClass('muted');
|
||||
$exclusiveField.attr('aria-disabled', 'true');
|
||||
$exclusiveWarning.addClass('gt-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,18 +46,18 @@ export function initCompLabelEdit(selector) {
|
|||
$('.edit-label .color-picker').minicolors('value', $(this).data('color'));
|
||||
$('#label-modal-id').val($(this).data('id'));
|
||||
|
||||
const nameInput = $('.edit-label .label-name-input');
|
||||
nameInput.val($(this).data('title'));
|
||||
const $nameInput = $('.edit-label .label-name-input');
|
||||
$nameInput.val($(this).data('title'));
|
||||
|
||||
const isArchivedCheckbox = $('.edit-label .label-is-archived-input');
|
||||
isArchivedCheckbox.prop('checked', this.hasAttribute('data-is-archived'));
|
||||
const $isArchivedCheckbox = $('.edit-label .label-is-archived-input');
|
||||
$isArchivedCheckbox[0].checked = this.hasAttribute('data-is-archived');
|
||||
|
||||
const exclusiveCheckbox = $('.edit-label .label-exclusive-input');
|
||||
exclusiveCheckbox.prop('checked', this.hasAttribute('data-exclusive'));
|
||||
const $exclusiveCheckbox = $('.edit-label .label-exclusive-input');
|
||||
$exclusiveCheckbox[0].checked = this.hasAttribute('data-exclusive');
|
||||
// Warn when label was previously not exclusive and used in issues
|
||||
exclusiveCheckbox.data('exclusive-warn',
|
||||
$exclusiveCheckbox.data('exclusive-warn',
|
||||
$(this).data('num-issues') > 0 &&
|
||||
(!this.hasAttribute('data-exclusive') || !isExclusiveScopeName(nameInput.val())));
|
||||
(!this.hasAttribute('data-exclusive') || !isExclusiveScopeName($nameInput.val())));
|
||||
updateExclusiveLabelEdit('.edit-label');
|
||||
|
||||
$('.edit-label .label-desc-input').val($(this).data('description'));
|
||||
|
|
|
@ -17,21 +17,21 @@ export function initCompReactionSelector($parent) {
|
|||
|
||||
const data = await res.json();
|
||||
if (data && (data.html || data.empty)) {
|
||||
const content = $(this).closest('.content');
|
||||
let react = content.find('.segment.reactions');
|
||||
if ((!data.empty || data.html === '') && react.length > 0) {
|
||||
react.remove();
|
||||
const $content = $(this).closest('.content');
|
||||
let $react = $content.find('.segment.reactions');
|
||||
if ((!data.empty || data.html === '') && $react.length > 0) {
|
||||
$react.remove();
|
||||
}
|
||||
if (!data.empty) {
|
||||
const attachments = content.find('.segment.bottom:first');
|
||||
react = $(data.html);
|
||||
if (attachments.length > 0) {
|
||||
react.insertBefore(attachments);
|
||||
const $attachments = $content.find('.segment.bottom:first');
|
||||
$react = $(data.html);
|
||||
if ($attachments.length > 0) {
|
||||
$react.insertBefore($attachments);
|
||||
} else {
|
||||
react.appendTo(content);
|
||||
$react.appendTo($content);
|
||||
}
|
||||
react.find('.dropdown').dropdown();
|
||||
initCompReactionSelector(react);
|
||||
$react.find('.dropdown').dropdown();
|
||||
initCompReactionSelector($react);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import $ from 'jquery';
|
||||
import {GET} from '../modules/fetch.js';
|
||||
|
||||
const {appSubUrl, csrfToken, notificationSettings, assetVersionEncoded} = window.config;
|
||||
const {appSubUrl, notificationSettings, assetVersionEncoded} = window.config;
|
||||
let notificationSequenceNumber = 0;
|
||||
|
||||
export function initNotificationsTable() {
|
||||
|
@ -27,25 +28,6 @@ export function initNotificationsTable() {
|
|||
e.target.closest('.notifications-item').setAttribute('data-remove', 'true');
|
||||
});
|
||||
}
|
||||
|
||||
$('#notification_table .button').on('click', function () {
|
||||
(async () => {
|
||||
const data = await updateNotification(
|
||||
$(this).data('url'),
|
||||
$(this).data('status'),
|
||||
$(this).data('page'),
|
||||
$(this).data('q'),
|
||||
$(this).data('notification-id'),
|
||||
);
|
||||
|
||||
if ($(data).data('sequence-number') === notificationSequenceNumber) {
|
||||
$('#notification_div').replaceWith(data);
|
||||
initNotificationsTable();
|
||||
}
|
||||
await updateNotificationCount();
|
||||
})();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
async function receiveUpdateCount(event) {
|
||||
|
@ -63,9 +45,9 @@ async function receiveUpdateCount(event) {
|
|||
}
|
||||
|
||||
export function initNotificationCount() {
|
||||
const notificationCount = $('.notification_count');
|
||||
const $notificationCount = $('.notification_count');
|
||||
|
||||
if (!notificationCount.length) {
|
||||
if (!$notificationCount.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -73,7 +55,7 @@ export function initNotificationCount() {
|
|||
const startPeriodicPoller = (timeout, lastCount) => {
|
||||
if (timeout <= 0 || !Number.isFinite(timeout)) return;
|
||||
usingPeriodicPoller = true;
|
||||
lastCount = lastCount ?? notificationCount.text();
|
||||
lastCount = lastCount ?? $notificationCount.text();
|
||||
setTimeout(async () => {
|
||||
await updateNotificationCountWithCallback(startPeriodicPoller, timeout, lastCount);
|
||||
}, timeout);
|
||||
|
@ -161,60 +143,52 @@ async function updateNotificationCountWithCallback(callback, timeout, lastCount)
|
|||
}
|
||||
|
||||
async function updateNotificationTable() {
|
||||
const notificationDiv = $('#notification_div');
|
||||
if (notificationDiv.length > 0) {
|
||||
const data = await $.ajax({
|
||||
type: 'GET',
|
||||
url: `${appSubUrl}/notifications${window.location.search}`,
|
||||
data: {
|
||||
'div-only': true,
|
||||
'sequence-number': ++notificationSequenceNumber,
|
||||
const notificationDiv = document.getElementById('notification_div');
|
||||
if (notificationDiv) {
|
||||
try {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
params.set('div-only', true);
|
||||
params.set('sequence-number', ++notificationSequenceNumber);
|
||||
const url = `${appSubUrl}/notifications?${params.toString()}`;
|
||||
const response = await GET(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch notification table');
|
||||
}
|
||||
});
|
||||
if ($(data).data('sequence-number') === notificationSequenceNumber) {
|
||||
notificationDiv.replaceWith(data);
|
||||
initNotificationsTable();
|
||||
|
||||
const data = await response.text();
|
||||
if ($(data).data('sequence-number') === notificationSequenceNumber) {
|
||||
notificationDiv.outerHTML = data;
|
||||
initNotificationsTable();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function updateNotificationCount() {
|
||||
const data = await $.ajax({
|
||||
type: 'GET',
|
||||
url: `${appSubUrl}/notifications/new`,
|
||||
headers: {
|
||||
'X-Csrf-Token': csrfToken,
|
||||
},
|
||||
});
|
||||
try {
|
||||
const response = await GET(`${appSubUrl}/notifications/new`);
|
||||
|
||||
const notificationCount = $('.notification_count');
|
||||
if (data.new === 0) {
|
||||
notificationCount.addClass('gt-hidden');
|
||||
} else {
|
||||
notificationCount.removeClass('gt-hidden');
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch notification count');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
const $notificationCount = $('.notification_count');
|
||||
if (data.new === 0) {
|
||||
$notificationCount.addClass('gt-hidden');
|
||||
} else {
|
||||
$notificationCount.removeClass('gt-hidden');
|
||||
}
|
||||
|
||||
$notificationCount.text(`${data.new}`);
|
||||
|
||||
return `${data.new}`;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return '0';
|
||||
}
|
||||
|
||||
notificationCount.text(`${data.new}`);
|
||||
|
||||
return `${data.new}`;
|
||||
}
|
||||
|
||||
async function updateNotification(url, status, page, q, notificationID) {
|
||||
if (status !== 'pinned') {
|
||||
$(`#notification_${notificationID}`).remove();
|
||||
}
|
||||
|
||||
return $.ajax({
|
||||
type: 'POST',
|
||||
url,
|
||||
data: {
|
||||
_csrf: csrfToken,
|
||||
notification_id: notificationID,
|
||||
status,
|
||||
page,
|
||||
q,
|
||||
noredirect: true,
|
||||
'sequence-number': ++notificationSequenceNumber,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -8,8 +8,9 @@ import {initViewedCheckboxListenerFor, countAndUpdateViewedFiles, initExpandAndC
|
|||
import {initImageDiff} from './imagediff.js';
|
||||
import {showErrorToast} from '../modules/toast.js';
|
||||
import {submitEventSubmitter} from '../utils/dom.js';
|
||||
import {POST, GET} from '../modules/fetch.js';
|
||||
|
||||
const {csrfToken, pageData, i18n} = window.config;
|
||||
const {pageData, i18n} = window.config;
|
||||
|
||||
function initRepoDiffReviewButton() {
|
||||
const $reviewBox = $('#review-box');
|
||||
|
@ -65,8 +66,9 @@ function initRepoDiffConversationForm() {
|
|||
if (isSubmittedByButton && submitter.name) {
|
||||
formData.append(submitter.name, submitter.value);
|
||||
}
|
||||
const formDataString = String(new URLSearchParams(formData));
|
||||
const $newConversationHolder = $(await $.post($form.attr('action'), formDataString));
|
||||
|
||||
const response = await POST($form.attr('action'), {data: formData});
|
||||
const $newConversationHolder = $(await response.text());
|
||||
const {path, side, idx} = $newConversationHolder.data();
|
||||
|
||||
$form.closest('.conversation-holder').replaceWith($newConversationHolder);
|
||||
|
@ -92,15 +94,20 @@ function initRepoDiffConversationForm() {
|
|||
const action = $(this).data('action');
|
||||
const url = $(this).data('update-url');
|
||||
|
||||
const data = await $.post(url, {_csrf: csrfToken, origin, action, comment_id});
|
||||
try {
|
||||
const response = await POST(url, {data: new URLSearchParams({origin, action, comment_id})});
|
||||
const data = await response.text();
|
||||
|
||||
if ($(this).closest('.conversation-holder').length) {
|
||||
const conversation = $(data);
|
||||
$(this).closest('.conversation-holder').replaceWith(conversation);
|
||||
conversation.find('.dropdown').dropdown();
|
||||
initCompReactionSelector(conversation);
|
||||
} else {
|
||||
window.location.reload();
|
||||
if ($(this).closest('.conversation-holder').length) {
|
||||
const $conversation = $(data);
|
||||
$(this).closest('.conversation-holder').replaceWith($conversation);
|
||||
$conversation.find('.dropdown').dropdown();
|
||||
initCompReactionSelector($conversation);
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -135,7 +142,7 @@ function onShowMoreFiles() {
|
|||
initImageDiff();
|
||||
}
|
||||
|
||||
export function loadMoreFiles(url) {
|
||||
export async function loadMoreFiles(url) {
|
||||
const $target = $('a#diff-show-more-files');
|
||||
if ($target.hasClass('disabled') || pageData.diffFileInfo.isLoadingNewData) {
|
||||
return;
|
||||
|
@ -143,10 +150,10 @@ export function loadMoreFiles(url) {
|
|||
|
||||
pageData.diffFileInfo.isLoadingNewData = true;
|
||||
$target.addClass('disabled');
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url,
|
||||
}).done((resp) => {
|
||||
|
||||
try {
|
||||
const response = await GET(url);
|
||||
const resp = await response.text();
|
||||
const $resp = $(resp);
|
||||
// the response is a full HTML page, we need to extract the relevant contents:
|
||||
// 1. append the newly loaded file list items to the existing list
|
||||
|
@ -155,10 +162,13 @@ export function loadMoreFiles(url) {
|
|||
$('body').append($resp.find('script#diff-data-script'));
|
||||
|
||||
onShowMoreFiles();
|
||||
}).always(() => {
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
showErrorToast('An error occurred while loading more files.');
|
||||
} finally {
|
||||
$target.removeClass('disabled');
|
||||
pageData.diffFileInfo.isLoadingNewData = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function initRepoDiffShowMore() {
|
||||
|
@ -170,7 +180,7 @@ function initRepoDiffShowMore() {
|
|||
loadMoreFiles(linkLoadMore);
|
||||
});
|
||||
|
||||
$(document).on('click', 'a.diff-load-button', (e) => {
|
||||
$(document).on('click', 'a.diff-load-button', async (e) => {
|
||||
e.preventDefault();
|
||||
const $target = $(e.target);
|
||||
|
||||
|
@ -181,26 +191,28 @@ function initRepoDiffShowMore() {
|
|||
$target.addClass('disabled');
|
||||
|
||||
const url = $target.data('href');
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url,
|
||||
}).done((resp) => {
|
||||
|
||||
try {
|
||||
const response = await GET(url);
|
||||
const resp = await response.text();
|
||||
|
||||
if (!resp) {
|
||||
$target.removeClass('disabled');
|
||||
return;
|
||||
}
|
||||
$target.parent().replaceWith($(resp).find('#diff-file-boxes .diff-file-body .file-body').children());
|
||||
onShowMoreFiles();
|
||||
}).fail(() => {
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
} finally {
|
||||
$target.removeClass('disabled');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function initRepoDiffView() {
|
||||
initRepoDiffConversationForm();
|
||||
const diffFileList = $('#diff-file-list');
|
||||
if (diffFileList.length === 0) return;
|
||||
const $diffFileList = $('#diff-file-list');
|
||||
if ($diffFileList.length === 0) return;
|
||||
initDiffFileTree();
|
||||
initDiffCommitSelect();
|
||||
initRepoDiffShowMore();
|
||||
|
|
|
@ -15,9 +15,9 @@ function initEditPreviewTab($form) {
|
|||
const $this = $(this);
|
||||
let context = `${$this.data('context')}/`;
|
||||
const mode = $this.data('markup-mode') || 'comment';
|
||||
const treePathEl = $form.find('input#tree_path');
|
||||
if (treePathEl.length > 0) {
|
||||
context += treePathEl.val();
|
||||
const $treePathEl = $form.find('input#tree_path');
|
||||
if ($treePathEl.length > 0) {
|
||||
context += $treePathEl.val();
|
||||
}
|
||||
context = context.substring(0, context.lastIndexOf('/'));
|
||||
|
||||
|
@ -25,7 +25,7 @@ function initEditPreviewTab($form) {
|
|||
formData.append('mode', mode);
|
||||
formData.append('context', context);
|
||||
formData.append('text', $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val());
|
||||
formData.append('file_path', treePathEl.val());
|
||||
formData.append('file_path', $treePathEl.val());
|
||||
try {
|
||||
const response = await POST($this.data('url'), {data: formData});
|
||||
const data = await response.text();
|
||||
|
@ -67,10 +67,10 @@ export function initRepoEditor() {
|
|||
$('.js-quick-pull-choice-option').on('change', function () {
|
||||
if ($(this).val() === 'commit-to-new-branch') {
|
||||
showElem($('.quick-pull-branch-name'));
|
||||
$('.quick-pull-branch-name input').prop('required', true);
|
||||
document.querySelector('.quick-pull-branch-name input').required = true;
|
||||
} else {
|
||||
hideElem($('.quick-pull-branch-name'));
|
||||
$('.quick-pull-branch-name input').prop('required', false);
|
||||
document.querySelector('.quick-pull-branch-name input').required = false;
|
||||
}
|
||||
$('#commit-button').text($(this).attr('button_text'));
|
||||
});
|
||||
|
@ -78,11 +78,11 @@ export function initRepoEditor() {
|
|||
const joinTreePath = ($fileNameEl) => {
|
||||
const parts = [];
|
||||
$('.breadcrumb span.section').each(function () {
|
||||
const element = $(this);
|
||||
if (element.find('a').length) {
|
||||
parts.push(element.find('a').text());
|
||||
const $element = $(this);
|
||||
if ($element.find('a').length) {
|
||||
parts.push($element.find('a').text());
|
||||
} else {
|
||||
parts.push(element.text());
|
||||
parts.push($element.text());
|
||||
}
|
||||
});
|
||||
if ($fileNameEl.val()) parts.push($fileNameEl.val());
|
||||
|
@ -135,13 +135,13 @@ export function initRepoEditor() {
|
|||
|
||||
// Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage
|
||||
// to enable or disable the commit button
|
||||
const $commitButton = $('#commit-button');
|
||||
const commitButton = document.getElementById('commit-button');
|
||||
const $editForm = $('.ui.edit.form');
|
||||
const dirtyFileClass = 'dirty-file';
|
||||
|
||||
// Disabling the button at the start
|
||||
if ($('input[name="page_has_posted"]').val() !== 'true') {
|
||||
$commitButton.prop('disabled', true);
|
||||
commitButton.disabled = true;
|
||||
}
|
||||
|
||||
// Registering a custom listener for the file path and the file content
|
||||
|
@ -151,7 +151,7 @@ export function initRepoEditor() {
|
|||
fieldSelector: ':input:not(.commit-form-wrapper :input)',
|
||||
change() {
|
||||
const dirty = $(this).hasClass(dirtyFileClass);
|
||||
$commitButton.prop('disabled', !dirty);
|
||||
commitButton.disabled = !dirty;
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -163,7 +163,7 @@ export function initRepoEditor() {
|
|||
editor.setValue(value);
|
||||
}
|
||||
|
||||
$commitButton.on('click', (event) => {
|
||||
commitButton?.addEventListener('click', (e) => {
|
||||
// A modal which asks if an empty file should be committed
|
||||
if ($editArea.val().length === 0) {
|
||||
$('#edit-empty-content-modal').modal({
|
||||
|
@ -171,7 +171,7 @@ export function initRepoEditor() {
|
|||
$('.edit.form').trigger('submit');
|
||||
},
|
||||
}).modal('show');
|
||||
event.preventDefault();
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
@ -181,6 +181,6 @@ export function renderPreviewPanelContent($panelPreviewer, data) {
|
|||
$panelPreviewer.html(data);
|
||||
initMarkupContent();
|
||||
|
||||
const refIssues = $panelPreviewer.find('p .ref-issue');
|
||||
attachRefIssueContextPopup(refIssues);
|
||||
const $refIssues = $panelPreviewer.find('p .ref-issue');
|
||||
attachRefIssueContextPopup($refIssues);
|
||||
}
|
||||
|
|
|
@ -63,10 +63,10 @@ export function initRepoGraphGit() {
|
|||
(async () => {
|
||||
const response = await GET(String(ajaxUrl));
|
||||
const html = await response.text();
|
||||
const div = $(html);
|
||||
$('#pagination').html(div.find('#pagination').html());
|
||||
$('#rel-container').html(div.find('#rel-container').html());
|
||||
$('#rev-container').html(div.find('#rev-container').html());
|
||||
const $div = $(html);
|
||||
$('#pagination').html($div.find('#pagination').html());
|
||||
$('#rel-container').html($div.find('#rel-container').html());
|
||||
$('#rev-container').html($div.find('#rev-container').html());
|
||||
$('#loading-indicator').addClass('gt-hidden');
|
||||
$('#rel-container').removeClass('gt-hidden');
|
||||
$('#rev-container').removeClass('gt-hidden');
|
||||
|
|
|
@ -6,55 +6,55 @@ import {POST} from '../modules/fetch.js';
|
|||
const {appSubUrl} = window.config;
|
||||
|
||||
export function initRepoTopicBar() {
|
||||
const mgrBtn = $('#manage_topic');
|
||||
if (!mgrBtn.length) return;
|
||||
const editDiv = $('#topic_edit');
|
||||
const viewDiv = $('#repo-topics');
|
||||
const saveBtn = $('#save_topic');
|
||||
const topicDropdown = $('#topic_edit .dropdown');
|
||||
const topicForm = editDiv; // the old logic, editDiv is topicForm
|
||||
const topicDropdownSearch = topicDropdown.find('input.search');
|
||||
const $mgrBtn = $('#manage_topic');
|
||||
if (!$mgrBtn.length) return;
|
||||
const $editDiv = $('#topic_edit');
|
||||
const $viewDiv = $('#repo-topics');
|
||||
const $saveBtn = $('#save_topic');
|
||||
const $topicDropdown = $('#topic_edit .dropdown');
|
||||
const $topicForm = $editDiv; // the old logic, $editDiv is topicForm
|
||||
const $topicDropdownSearch = $topicDropdown.find('input.search');
|
||||
const topicPrompts = {
|
||||
countPrompt: topicDropdown.attr('data-text-count-prompt'),
|
||||
formatPrompt: topicDropdown.attr('data-text-format-prompt'),
|
||||
countPrompt: $topicDropdown.attr('data-text-count-prompt'),
|
||||
formatPrompt: $topicDropdown.attr('data-text-format-prompt'),
|
||||
};
|
||||
|
||||
mgrBtn.on('click', () => {
|
||||
hideElem(viewDiv);
|
||||
showElem(editDiv);
|
||||
topicDropdownSearch.focus();
|
||||
$mgrBtn.on('click', () => {
|
||||
hideElem($viewDiv);
|
||||
showElem($editDiv);
|
||||
$topicDropdownSearch.trigger('focus');
|
||||
});
|
||||
|
||||
$('#cancel_topic_edit').on('click', () => {
|
||||
hideElem(editDiv);
|
||||
showElem(viewDiv);
|
||||
mgrBtn.focus();
|
||||
hideElem($editDiv);
|
||||
showElem($viewDiv);
|
||||
$mgrBtn.trigger('focus');
|
||||
});
|
||||
|
||||
saveBtn.on('click', async () => {
|
||||
$saveBtn.on('click', async () => {
|
||||
const topics = $('input[name=topics]').val();
|
||||
|
||||
const data = new FormData();
|
||||
data.append('topics', topics);
|
||||
|
||||
const response = await POST(saveBtn.attr('data-link'), {data});
|
||||
const response = await POST($saveBtn.attr('data-link'), {data});
|
||||
|
||||
if (response.ok) {
|
||||
const responseData = await response.json();
|
||||
if (responseData.status === 'ok') {
|
||||
viewDiv.children('.topic').remove();
|
||||
$viewDiv.children('.topic').remove();
|
||||
if (topics.length) {
|
||||
const topicArray = topics.split(',');
|
||||
topicArray.sort();
|
||||
for (const topic of topicArray) {
|
||||
const link = $('<a class="ui repo-topic large label topic gt-m-0"></a>');
|
||||
link.attr('href', `${appSubUrl}/explore/repos?q=${encodeURIComponent(topic)}&topic=1`);
|
||||
link.text(topic);
|
||||
link.insertBefore(mgrBtn); // insert all new topics before manage button
|
||||
const $link = $('<a class="ui repo-topic large label topic gt-m-0"></a>');
|
||||
$link.attr('href', `${appSubUrl}/explore/repos?q=${encodeURIComponent(topic)}&topic=1`);
|
||||
$link.text(topic);
|
||||
$link.insertBefore($mgrBtn); // insert all new topics before manage button
|
||||
}
|
||||
}
|
||||
hideElem(editDiv);
|
||||
showElem(viewDiv);
|
||||
hideElem($editDiv);
|
||||
showElem($viewDiv);
|
||||
}
|
||||
} else if (response.status === 422) {
|
||||
const responseData = await response.json();
|
||||
|
@ -62,10 +62,10 @@ export function initRepoTopicBar() {
|
|||
topicPrompts.formatPrompt = responseData.message;
|
||||
|
||||
const {invalidTopics} = responseData;
|
||||
const topicLabels = topicDropdown.children('a.ui.label');
|
||||
const $topicLabels = $topicDropdown.children('a.ui.label');
|
||||
for (const [index, value] of topics.split(',').entries()) {
|
||||
if (invalidTopics.includes(value)) {
|
||||
topicLabels.eq(index).removeClass('green').addClass('red');
|
||||
$topicLabels.eq(index).removeClass('green').addClass('red');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -74,10 +74,10 @@ export function initRepoTopicBar() {
|
|||
}
|
||||
|
||||
// Always validate the form
|
||||
topicForm.form('validate form');
|
||||
$topicForm.form('validate form');
|
||||
});
|
||||
|
||||
topicDropdown.dropdown({
|
||||
$topicDropdown.dropdown({
|
||||
allowAdditions: true,
|
||||
forceSelection: false,
|
||||
fullTextSearch: 'exact',
|
||||
|
@ -100,7 +100,7 @@ export function initRepoTopicBar() {
|
|||
const query = stripTags(this.urlData.query.trim());
|
||||
let found_query = false;
|
||||
const current_topics = [];
|
||||
topicDropdown.find('a.label.visible').each((_, el) => {
|
||||
$topicDropdown.find('a.label.visible').each((_, el) => {
|
||||
current_topics.push(el.getAttribute('data-value'));
|
||||
});
|
||||
|
||||
|
@ -150,15 +150,15 @@ export function initRepoTopicBar() {
|
|||
});
|
||||
|
||||
$.fn.form.settings.rules.validateTopic = function (_values, regExp) {
|
||||
const topics = topicDropdown.children('a.ui.label');
|
||||
const status = topics.length === 0 || topics.last().attr('data-value').match(regExp);
|
||||
const $topics = $topicDropdown.children('a.ui.label');
|
||||
const status = $topics.length === 0 || $topics.last().attr('data-value').match(regExp);
|
||||
if (!status) {
|
||||
topics.last().removeClass('green').addClass('red');
|
||||
$topics.last().removeClass('green').addClass('red');
|
||||
}
|
||||
return status && topicDropdown.children('a.ui.label.red').length === 0;
|
||||
return status && $topicDropdown.children('a.ui.label.red').length === 0;
|
||||
};
|
||||
|
||||
topicForm.form({
|
||||
$topicForm.form({
|
||||
on: 'change',
|
||||
inline: true,
|
||||
fields: {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import $ from 'jquery';
|
||||
import {svg} from '../svg.js';
|
||||
import {showErrorToast} from '../modules/toast.js';
|
||||
import {GET, POST} from '../modules/fetch.js';
|
||||
|
||||
const {appSubUrl, csrfToken} = window.config;
|
||||
const {appSubUrl} = window.config;
|
||||
let i18nTextEdited;
|
||||
let i18nTextOptions;
|
||||
let i18nTextDeleteFromHistory;
|
||||
|
@ -31,19 +32,27 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
|
|||
$dialog.find('.dialog-header-options').dropdown({
|
||||
showOnFocus: false,
|
||||
allowReselection: true,
|
||||
onChange(_value, _text, $item) {
|
||||
async onChange(_value, _text, $item) {
|
||||
const optionItem = $item.data('option-item');
|
||||
if (optionItem === 'delete') {
|
||||
if (window.confirm(i18nTextDeleteFromHistoryConfirm)) {
|
||||
$.post(`${issueBaseUrl}/content-history/soft-delete?comment_id=${commentId}&history_id=${historyId}`, {
|
||||
_csrf: csrfToken,
|
||||
}).done((resp) => {
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('comment_id', commentId);
|
||||
params.append('history_id', historyId);
|
||||
|
||||
const response = await POST(`${issueBaseUrl}/content-history/soft-delete?${params.toString()}`);
|
||||
const resp = await response.json();
|
||||
|
||||
if (resp.ok) {
|
||||
$dialog.modal('hide');
|
||||
} else {
|
||||
showErrorToast(resp.message);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
showErrorToast('An error occurred while deleting the history.');
|
||||
}
|
||||
}
|
||||
} else { // required by eslint
|
||||
showErrorToast(`unknown option item: ${optionItem}`);
|
||||
|
@ -54,19 +63,24 @@ function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleH
|
|||
}
|
||||
});
|
||||
$dialog.modal({
|
||||
onShow() {
|
||||
$.ajax({
|
||||
url: `${issueBaseUrl}/content-history/detail?comment_id=${commentId}&history_id=${historyId}`,
|
||||
data: {
|
||||
_csrf: csrfToken,
|
||||
},
|
||||
}).done((resp) => {
|
||||
async onShow() {
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('comment_id', commentId);
|
||||
params.append('history_id', historyId);
|
||||
|
||||
const url = `${issueBaseUrl}/content-history/detail?${params.toString()}`;
|
||||
const response = await GET(url);
|
||||
const resp = await response.json();
|
||||
|
||||
$dialog.find('.comment-diff-data').removeClass('is-loading').html(resp.diffHtml);
|
||||
// there is only one option "item[data-option-item=delete]", so the dropdown can be entirely shown/hidden.
|
||||
if (resp.canSoftDelete) {
|
||||
$dialog.find('.dialog-header-options').removeClass('gt-hidden');
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
},
|
||||
onHidden() {
|
||||
$dialog.remove();
|
||||
|
@ -103,7 +117,7 @@ function showContentHistoryMenu(issueBaseUrl, $item, commentId) {
|
|||
});
|
||||
}
|
||||
|
||||
export function initRepoIssueContentHistory() {
|
||||
export async function initRepoIssueContentHistory() {
|
||||
const issueIndex = $('#issueIndex').val();
|
||||
if (!issueIndex) return;
|
||||
|
||||
|
@ -114,12 +128,10 @@ export function initRepoIssueContentHistory() {
|
|||
const repoLink = $('#repolink').val();
|
||||
const issueBaseUrl = `${appSubUrl}/${repoLink}/issues/${issueIndex}`;
|
||||
|
||||
$.ajax({
|
||||
url: `${issueBaseUrl}/content-history/overview`,
|
||||
data: {
|
||||
_csrf: csrfToken,
|
||||
},
|
||||
}).done((resp) => {
|
||||
try {
|
||||
const response = await GET(`${issueBaseUrl}/content-history/overview`);
|
||||
const resp = await response.json();
|
||||
|
||||
i18nTextEdited = resp.i18n.textEdited;
|
||||
i18nTextDeleteFromHistory = resp.i18n.textDeleteFromHistory;
|
||||
i18nTextDeleteFromHistoryConfirm = resp.i18n.textDeleteFromHistoryConfirm;
|
||||
|
@ -133,5 +145,7 @@ export function initRepoIssueContentHistory() {
|
|||
const $itemComment = $(`#issuecomment-${commentId}`);
|
||||
showContentHistoryMenu(issueBaseUrl, $itemComment, commentId);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import $ from 'jquery';
|
||||
import {updateIssuesMeta} from './repo-issue.js';
|
||||
import {toggleElem, hideElem} from '../utils/dom.js';
|
||||
import {toggleElem, hideElem, isElemHidden} from '../utils/dom.js';
|
||||
import {htmlEscape} from 'escape-goat';
|
||||
import {confirmModal} from './comp/ConfirmModal.js';
|
||||
import {showErrorToast} from '../modules/toast.js';
|
||||
|
@ -8,32 +8,42 @@ import {createSortable} from '../modules/sortable.js';
|
|||
import {DELETE, POST} from '../modules/fetch.js';
|
||||
|
||||
function initRepoIssueListCheckboxes() {
|
||||
const $issueSelectAll = $('.issue-checkbox-all');
|
||||
const $issueCheckboxes = $('.issue-checkbox');
|
||||
const issueSelectAll = document.querySelector('.issue-checkbox-all');
|
||||
const issueCheckboxes = document.querySelectorAll('.issue-checkbox');
|
||||
|
||||
const syncIssueSelectionState = () => {
|
||||
const $checked = $issueCheckboxes.filter(':checked');
|
||||
const anyChecked = $checked.length !== 0;
|
||||
const allChecked = anyChecked && $checked.length === $issueCheckboxes.length;
|
||||
const checkedCheckboxes = Array.from(issueCheckboxes).filter((el) => el.checked);
|
||||
const anyChecked = Boolean(checkedCheckboxes.length);
|
||||
const allChecked = anyChecked && checkedCheckboxes.length === issueCheckboxes.length;
|
||||
|
||||
if (allChecked) {
|
||||
$issueSelectAll.prop({'checked': true, 'indeterminate': false});
|
||||
issueSelectAll.checked = true;
|
||||
issueSelectAll.indeterminate = false;
|
||||
} else if (anyChecked) {
|
||||
$issueSelectAll.prop({'checked': false, 'indeterminate': true});
|
||||
issueSelectAll.checked = false;
|
||||
issueSelectAll.indeterminate = true;
|
||||
} else {
|
||||
$issueSelectAll.prop({'checked': false, 'indeterminate': false});
|
||||
issueSelectAll.checked = false;
|
||||
issueSelectAll.indeterminate = false;
|
||||
}
|
||||
// if any issue is selected, show the action panel, otherwise show the filter panel
|
||||
toggleElem($('#issue-filters'), !anyChecked);
|
||||
toggleElem($('#issue-actions'), anyChecked);
|
||||
// there are two panels but only one select-all checkbox, so move the checkbox to the visible panel
|
||||
$('#issue-filters, #issue-actions').filter(':visible').find('.issue-list-toolbar-left').prepend($issueSelectAll);
|
||||
const panels = document.querySelectorAll('#issue-filters, #issue-actions');
|
||||
const visiblePanel = Array.from(panels).find((el) => !isElemHidden(el));
|
||||
const toolbarLeft = visiblePanel.querySelector('.issue-list-toolbar-left');
|
||||
toolbarLeft.prepend(issueSelectAll);
|
||||
};
|
||||
|
||||
$issueCheckboxes.on('change', syncIssueSelectionState);
|
||||
for (const el of issueCheckboxes) {
|
||||
el.addEventListener('change', syncIssueSelectionState);
|
||||
}
|
||||
|
||||
$issueSelectAll.on('change', () => {
|
||||
$issueCheckboxes.prop('checked', $issueSelectAll.is(':checked'));
|
||||
issueSelectAll.addEventListener('change', () => {
|
||||
for (const el of issueCheckboxes) {
|
||||
el.checked = issueSelectAll.checked;
|
||||
}
|
||||
syncIssueSelectionState();
|
||||
});
|
||||
|
||||
|
@ -125,7 +135,9 @@ function initRepoIssueListAuthorDropdown() {
|
|||
if (newMenuHtml) {
|
||||
const $newMenuItems = $(newMenuHtml);
|
||||
$newMenuItems.addClass('dynamic-item');
|
||||
$menu.append('<div class="divider dynamic-item"></div>', ...$newMenuItems);
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('divider', 'dynamic-item');
|
||||
$menu[0].append(div, ...$newMenuItems);
|
||||
}
|
||||
$searchDropdown.dropdown('refresh');
|
||||
// defer our selection to the next tick, because dropdown will set the selection item after this `menu` function
|
||||
|
|
|
@ -6,8 +6,9 @@ import {setFileFolding} from './file-fold.js';
|
|||
import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js';
|
||||
import {toAbsoluteUrl} from '../utils.js';
|
||||
import {initDropzone} from './common-global.js';
|
||||
import {POST, GET} from '../modules/fetch.js';
|
||||
|
||||
const {appSubUrl, csrfToken} = window.config;
|
||||
const {appSubUrl} = window.config;
|
||||
|
||||
export function initRepoIssueTimeTracking() {
|
||||
$(document).on('click', '.issue-add-time', () => {
|
||||
|
@ -40,7 +41,7 @@ export function initRepoIssueTimeTracking() {
|
|||
});
|
||||
}
|
||||
|
||||
function updateDeadline(deadlineString) {
|
||||
async function updateDeadline(deadlineString) {
|
||||
hideElem($('#deadline-err-invalid-date'));
|
||||
$('#deadline-loader').addClass('loading');
|
||||
|
||||
|
@ -56,23 +57,21 @@ function updateDeadline(deadlineString) {
|
|||
realDeadline = new Date(newDate);
|
||||
}
|
||||
|
||||
$.ajax(`${$('#update-issue-deadline-form').attr('action')}`, {
|
||||
data: JSON.stringify({
|
||||
due_date: realDeadline,
|
||||
}),
|
||||
headers: {
|
||||
'X-Csrf-Token': csrfToken,
|
||||
},
|
||||
contentType: 'application/json',
|
||||
type: 'POST',
|
||||
success() {
|
||||
try {
|
||||
const response = await POST($('#update-issue-deadline-form').attr('action'), {
|
||||
data: {due_date: realDeadline}
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
window.location.reload();
|
||||
},
|
||||
error() {
|
||||
$('#deadline-loader').removeClass('loading');
|
||||
showElem($('#deadline-err-invalid-date'));
|
||||
},
|
||||
});
|
||||
} else {
|
||||
throw new Error('Invalid response');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
$('#deadline-loader').removeClass('loading');
|
||||
showElem($('#deadline-err-invalid-date'));
|
||||
}
|
||||
}
|
||||
|
||||
export function initRepoIssueDue() {
|
||||
|
@ -145,9 +144,9 @@ export function initRepoIssueSidebarList() {
|
|||
|
||||
$('.menu .ui.dropdown.label-filter').on('keydown', (e) => {
|
||||
if (e.altKey && e.keyCode === 13) {
|
||||
const selectedItems = $('.menu .ui.dropdown.label-filter .menu .item.selected');
|
||||
if (selectedItems.length > 0) {
|
||||
excludeLabel($(selectedItems[0]));
|
||||
const $selectedItems = $('.menu .ui.dropdown.label-filter .menu .item.selected');
|
||||
if ($selectedItems.length > 0) {
|
||||
excludeLabel($($selectedItems[0]));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -156,12 +155,12 @@ export function initRepoIssueSidebarList() {
|
|||
|
||||
export function initRepoIssueCommentDelete() {
|
||||
// Delete comment
|
||||
$(document).on('click', '.delete-comment', function () {
|
||||
$(document).on('click', '.delete-comment', async function () {
|
||||
const $this = $(this);
|
||||
if (window.confirm($this.data('locale'))) {
|
||||
$.post($this.data('url'), {
|
||||
_csrf: csrfToken,
|
||||
}).done(() => {
|
||||
try {
|
||||
const response = await POST($this.data('url'));
|
||||
if (!response.ok) throw new Error('Failed to delete comment');
|
||||
const $conversationHolder = $this.closest('.conversation-holder');
|
||||
|
||||
// Check if this was a pending comment.
|
||||
|
@ -186,7 +185,9 @@ export function initRepoIssueCommentDelete() {
|
|||
}
|
||||
$conversationHolder.remove();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -213,12 +214,12 @@ export function initRepoIssueDependencyDelete() {
|
|||
export function initRepoIssueCodeCommentCancel() {
|
||||
// Cancel inline code comment
|
||||
$(document).on('click', '.cancel-code-comment', (e) => {
|
||||
const form = $(e.currentTarget).closest('form');
|
||||
if (form.length > 0 && form.hasClass('comment-form')) {
|
||||
form.addClass('gt-hidden');
|
||||
showElem(form.closest('.comment-code-cloud').find('button.comment-form-reply'));
|
||||
const $form = $(e.currentTarget).closest('form');
|
||||
if ($form.length > 0 && $form.hasClass('comment-form')) {
|
||||
$form.addClass('gt-hidden');
|
||||
showElem($form.closest('.comment-code-cloud').find('button.comment-form-reply'));
|
||||
} else {
|
||||
form.closest('.comment-code-cloud').remove();
|
||||
$form.closest('.comment-code-cloud').remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -226,22 +227,32 @@ export function initRepoIssueCodeCommentCancel() {
|
|||
export function initRepoPullRequestUpdate() {
|
||||
// Pull Request update button
|
||||
const $pullUpdateButton = $('.update-button > button');
|
||||
$pullUpdateButton.on('click', function (e) {
|
||||
$pullUpdateButton.on('click', async function (e) {
|
||||
e.preventDefault();
|
||||
const $this = $(this);
|
||||
const redirect = $this.data('redirect');
|
||||
$this.addClass('loading');
|
||||
$.post($this.data('do'), {
|
||||
_csrf: csrfToken
|
||||
}).done((data) => {
|
||||
if (data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
} else if (redirect) {
|
||||
window.location.href = redirect;
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
let response;
|
||||
try {
|
||||
response = await POST($this.data('do'));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
$this.removeClass('loading');
|
||||
}
|
||||
let data;
|
||||
try {
|
||||
data = await response?.json(); // the response is probably not a JSON
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
if (data?.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
} else if (redirect) {
|
||||
window.location.href = redirect;
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
|
||||
$('.update-button > .dropdown').dropdown({
|
||||
|
@ -267,20 +278,24 @@ export function initRepoPullRequestAllowMaintainerEdit() {
|
|||
|
||||
const promptError = $checkbox.attr('data-prompt-error');
|
||||
$checkbox.checkbox({
|
||||
'onChange': () => {
|
||||
'onChange': async () => {
|
||||
const checked = $checkbox.checkbox('is checked');
|
||||
let url = $checkbox.attr('data-url');
|
||||
url += '/set_allow_maintainer_edit';
|
||||
$checkbox.checkbox('set disabled');
|
||||
$.ajax({url, type: 'POST',
|
||||
data: {_csrf: csrfToken, allow_maintainer_edit: checked},
|
||||
error: () => {
|
||||
showTemporaryTooltip($checkbox[0], promptError);
|
||||
},
|
||||
complete: () => {
|
||||
$checkbox.checkbox('set enabled');
|
||||
},
|
||||
});
|
||||
try {
|
||||
const response = await POST(url, {
|
||||
data: {allow_maintainer_edit: checked},
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to update maintainer edit permission');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
showTemporaryTooltip($checkbox[0], promptError);
|
||||
} finally {
|
||||
$checkbox.checkbox('set enabled');
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -329,17 +344,15 @@ export function initRepoIssueWipTitle() {
|
|||
});
|
||||
}
|
||||
|
||||
export async function updateIssuesMeta(url, action, issueIds, elementId) {
|
||||
return $.ajax({
|
||||
type: 'POST',
|
||||
url,
|
||||
data: {
|
||||
_csrf: csrfToken,
|
||||
action,
|
||||
issue_ids: issueIds,
|
||||
id: elementId,
|
||||
},
|
||||
});
|
||||
export async function updateIssuesMeta(url, action, issue_ids, id) {
|
||||
try {
|
||||
const response = await POST(url, {data: new URLSearchParams({action, issue_ids, id})});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to update issues meta');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
export function initRepoIssueComments() {
|
||||
|
@ -357,10 +370,10 @@ export function initRepoIssueComments() {
|
|||
});
|
||||
|
||||
$(document).on('click', (event) => {
|
||||
const urlTarget = $(':target');
|
||||
if (urlTarget.length === 0) return;
|
||||
const $urlTarget = $(':target');
|
||||
if ($urlTarget.length === 0) return;
|
||||
|
||||
const urlTargetId = urlTarget.attr('id');
|
||||
const urlTargetId = $urlTarget.attr('id');
|
||||
if (!urlTargetId) return;
|
||||
if (!/^(issue|pull)(comment)?-\d+$/.test(urlTargetId)) return;
|
||||
|
||||
|
@ -377,18 +390,18 @@ export function initRepoIssueComments() {
|
|||
|
||||
export async function handleReply($el) {
|
||||
hideElem($el);
|
||||
const form = $el.closest('.comment-code-cloud').find('.comment-form');
|
||||
form.removeClass('gt-hidden');
|
||||
const $form = $el.closest('.comment-code-cloud').find('.comment-form');
|
||||
$form.removeClass('gt-hidden');
|
||||
|
||||
const $textarea = form.find('textarea');
|
||||
const $textarea = $form.find('textarea');
|
||||
let editor = getComboMarkdownEditor($textarea);
|
||||
if (!editor) {
|
||||
// FIXME: the initialization of the dropzone is not consistent.
|
||||
// When the page is loaded, the dropzone is initialized by initGlobalDropzone, but the editor is not initialized.
|
||||
// When the form is submitted and partially reload, none of them is initialized.
|
||||
const dropzone = form.find('.dropzone')[0];
|
||||
const dropzone = $form.find('.dropzone')[0];
|
||||
if (!dropzone.dropzone) initDropzone(dropzone);
|
||||
editor = await initComboMarkdownEditor(form.find('.combo-markdown-editor'));
|
||||
editor = await initComboMarkdownEditor($form.find('.combo-markdown-editor'));
|
||||
}
|
||||
editor.focus();
|
||||
return editor;
|
||||
|
@ -400,30 +413,30 @@ export function initRepoPullRequestReview() {
|
|||
if (window.history.scrollRestoration !== 'manual') {
|
||||
window.history.scrollRestoration = 'manual';
|
||||
}
|
||||
const commentDiv = $(window.location.hash);
|
||||
if (commentDiv) {
|
||||
const $commentDiv = $(window.location.hash);
|
||||
if ($commentDiv) {
|
||||
// get the name of the parent id
|
||||
const groupID = commentDiv.closest('div[id^="code-comments-"]').attr('id');
|
||||
const groupID = $commentDiv.closest('div[id^="code-comments-"]').attr('id');
|
||||
if (groupID && groupID.startsWith('code-comments-')) {
|
||||
const id = groupID.slice(14);
|
||||
const ancestorDiffBox = commentDiv.closest('.diff-file-box');
|
||||
const $ancestorDiffBox = $commentDiv.closest('.diff-file-box');
|
||||
// on pages like conversation, there is no diff header
|
||||
const diffHeader = ancestorDiffBox.find('.diff-file-header');
|
||||
const $diffHeader = $ancestorDiffBox.find('.diff-file-header');
|
||||
// offset is for scrolling
|
||||
let offset = 30;
|
||||
if (diffHeader[0]) {
|
||||
offset += $('.diff-detail-box').outerHeight() + diffHeader.outerHeight();
|
||||
if ($diffHeader[0]) {
|
||||
offset += $('.diff-detail-box').outerHeight() + $diffHeader.outerHeight();
|
||||
}
|
||||
$(`#show-outdated-${id}`).addClass('gt-hidden');
|
||||
$(`#code-comments-${id}`).removeClass('gt-hidden');
|
||||
$(`#code-preview-${id}`).removeClass('gt-hidden');
|
||||
$(`#hide-outdated-${id}`).removeClass('gt-hidden');
|
||||
// if the comment box is folded, expand it
|
||||
if (ancestorDiffBox.attr('data-folded') && ancestorDiffBox.attr('data-folded') === 'true') {
|
||||
setFileFolding(ancestorDiffBox[0], ancestorDiffBox.find('.fold-file')[0], false);
|
||||
if ($ancestorDiffBox.attr('data-folded') && $ancestorDiffBox.attr('data-folded') === 'true') {
|
||||
setFileFolding($ancestorDiffBox[0], $ancestorDiffBox.find('.fold-file')[0], false);
|
||||
}
|
||||
window.scrollTo({
|
||||
top: commentDiv.offset().top - offset,
|
||||
top: $commentDiv.offset().top - offset,
|
||||
behavior: 'instant'
|
||||
});
|
||||
}
|
||||
|
@ -491,12 +504,12 @@ export function initRepoPullRequestReview() {
|
|||
const side = $(this).data('side');
|
||||
const idx = $(this).data('idx');
|
||||
const path = $(this).closest('[data-path]').data('path');
|
||||
const tr = $(this).closest('tr');
|
||||
const lineType = tr.data('line-type');
|
||||
const $tr = $(this).closest('tr');
|
||||
const lineType = $tr.data('line-type');
|
||||
|
||||
let ntr = tr.next();
|
||||
if (!ntr.hasClass('add-comment')) {
|
||||
ntr = $(`
|
||||
let $ntr = $tr.next();
|
||||
if (!$ntr.hasClass('add-comment')) {
|
||||
$ntr = $(`
|
||||
<tr class="add-comment" data-line-type="${lineType}">
|
||||
${isSplit ? `
|
||||
<td class="add-comment-left" colspan="4"></td>
|
||||
|
@ -505,21 +518,26 @@ export function initRepoPullRequestReview() {
|
|||
<td class="add-comment-left add-comment-right" colspan="5"></td>
|
||||
`}
|
||||
</tr>`);
|
||||
tr.after(ntr);
|
||||
$tr.after($ntr);
|
||||
}
|
||||
|
||||
const td = ntr.find(`.add-comment-${side}`);
|
||||
const commentCloud = td.find('.comment-code-cloud');
|
||||
if (commentCloud.length === 0 && !ntr.find('button[name="pending_review"]').length) {
|
||||
const html = await $.get($(this).closest('[data-new-comment-url]').attr('data-new-comment-url'));
|
||||
td.html(html);
|
||||
td.find("input[name='line']").val(idx);
|
||||
td.find("input[name='side']").val(side === 'left' ? 'previous' : 'proposed');
|
||||
td.find("input[name='path']").val(path);
|
||||
const $td = $ntr.find(`.add-comment-${side}`);
|
||||
const $commentCloud = $td.find('.comment-code-cloud');
|
||||
if ($commentCloud.length === 0 && !$ntr.find('button[name="pending_review"]').length) {
|
||||
try {
|
||||
const response = await GET($(this).closest('[data-new-comment-url]').attr('data-new-comment-url'));
|
||||
const html = await response.text();
|
||||
$td.html(html);
|
||||
$td.find("input[name='line']").val(idx);
|
||||
$td.find("input[name='side']").val(side === 'left' ? 'previous' : 'proposed');
|
||||
$td.find("input[name='path']").val(path);
|
||||
|
||||
initDropzone(td.find('.dropzone')[0]);
|
||||
const editor = await initComboMarkdownEditor(td.find('.combo-markdown-editor'));
|
||||
editor.focus();
|
||||
initDropzone($td.find('.dropzone')[0]);
|
||||
const editor = await initComboMarkdownEditor($td.find('.combo-markdown-editor'));
|
||||
editor.focus();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -547,11 +565,19 @@ export function initRepoIssueWipToggle() {
|
|||
const title = toggleWip.getAttribute('data-title');
|
||||
const wipPrefix = toggleWip.getAttribute('data-wip-prefix');
|
||||
const updateUrl = toggleWip.getAttribute('data-update-url');
|
||||
await $.post(updateUrl, {
|
||||
_csrf: csrfToken,
|
||||
title: title?.startsWith(wipPrefix) ? title.slice(wipPrefix.length).trim() : `${wipPrefix.trim()} ${title}`,
|
||||
});
|
||||
window.location.reload();
|
||||
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('title', title?.startsWith(wipPrefix) ? title.slice(wipPrefix.length).trim() : `${wipPrefix.trim()} ${title}`);
|
||||
|
||||
const response = await POST(updateUrl, {data: params});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to toggle WIP status');
|
||||
}
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -576,39 +602,43 @@ export function initRepoIssueTitleEdit() {
|
|||
|
||||
$('#edit-title').on('click', editTitleToggle);
|
||||
$('#cancel-edit-title').on('click', editTitleToggle);
|
||||
$('#save-edit-title').on('click', editTitleToggle).on('click', function () {
|
||||
const pullrequest_targetbranch_change = function (update_url) {
|
||||
$('#save-edit-title').on('click', editTitleToggle).on('click', async function () {
|
||||
const pullrequest_targetbranch_change = async function (update_url) {
|
||||
const targetBranch = $('#pull-target-branch').data('branch');
|
||||
const $branchTarget = $('#branch_target');
|
||||
if (targetBranch === $branchTarget.text()) {
|
||||
window.location.reload();
|
||||
return false;
|
||||
}
|
||||
$.post(update_url, {
|
||||
_csrf: csrfToken,
|
||||
target_branch: targetBranch
|
||||
}).always(() => {
|
||||
try {
|
||||
await POST(update_url, {data: new URLSearchParams({target_branch: targetBranch})});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const pullrequest_target_update_url = $(this).attr('data-target-update-url');
|
||||
if ($editInput.val().length === 0 || $editInput.val() === $issueTitle.text()) {
|
||||
$editInput.val($issueTitle.text());
|
||||
pullrequest_targetbranch_change(pullrequest_target_update_url);
|
||||
await pullrequest_targetbranch_change(pullrequest_target_update_url);
|
||||
} else {
|
||||
$.post($(this).attr('data-update-url'), {
|
||||
_csrf: csrfToken,
|
||||
title: $editInput.val()
|
||||
}, (data) => {
|
||||
try {
|
||||
const params = new URLSearchParams();
|
||||
params.append('title', $editInput.val());
|
||||
const response = await POST($(this).attr('data-update-url'), {data: params});
|
||||
const data = await response.json();
|
||||
$editInput.val(data.title);
|
||||
$issueTitle.text(data.title);
|
||||
if (pullrequest_target_update_url) {
|
||||
pullrequest_targetbranch_change(pullrequest_target_update_url); // it will reload the window
|
||||
await pullrequest_targetbranch_change(pullrequest_target_update_url); // it will reload the window
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -616,18 +646,18 @@ export function initRepoIssueTitleEdit() {
|
|||
|
||||
export function initRepoIssueBranchSelect() {
|
||||
const changeBranchSelect = function () {
|
||||
const selectionTextField = $('#pull-target-branch');
|
||||
const $selectionTextField = $('#pull-target-branch');
|
||||
|
||||
const baseName = selectionTextField.data('basename');
|
||||
const baseName = $selectionTextField.data('basename');
|
||||
const branchNameNew = $(this).data('branch');
|
||||
const branchNameOld = selectionTextField.data('branch');
|
||||
const branchNameOld = $selectionTextField.data('branch');
|
||||
|
||||
// Replace branch name to keep translation from HTML template
|
||||
selectionTextField.html(selectionTextField.html().replace(
|
||||
$selectionTextField.html($selectionTextField.html().replace(
|
||||
`${baseName}:${branchNameOld}`,
|
||||
`${baseName}:${branchNameNew}`
|
||||
));
|
||||
selectionTextField.data('branch', branchNameNew); // update branch name in setting
|
||||
$selectionTextField.data('branch', branchNameNew); // update branch name in setting
|
||||
};
|
||||
$('#branch-select > .item').on('click', changeBranchSelect);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import {initRepoPullRequestCommitStatus} from './repo-issue-pr-status.js';
|
|||
import {hideElem, showElem} from '../utils/dom.js';
|
||||
import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js';
|
||||
import {attachRefIssueContextPopup} from './contextpopup.js';
|
||||
import {POST, GET} from '../modules/fetch.js';
|
||||
|
||||
const {csrfToken} = window.config;
|
||||
|
||||
|
@ -65,7 +66,7 @@ export function initRepoCommentForm() {
|
|||
const $selectBranch = $('.ui.select-branch');
|
||||
const $branchMenu = $selectBranch.find('.reference-list-menu');
|
||||
const $isNewIssue = $branchMenu.hasClass('new-issue');
|
||||
$branchMenu.find('.item:not(.no-select)').on('click', function () {
|
||||
$branchMenu.find('.item:not(.no-select)').on('click', async function () {
|
||||
const selectedValue = $(this).data('id');
|
||||
const editMode = $('#editing_mode').val();
|
||||
$($(this).data('id-selector')).val(selectedValue);
|
||||
|
@ -75,8 +76,15 @@ export function initRepoCommentForm() {
|
|||
}
|
||||
|
||||
if (editMode === 'true') {
|
||||
const form = $('#update_issueref_form');
|
||||
$.post(form.attr('action'), {_csrf: csrfToken, ref: selectedValue}, () => window.location.reload());
|
||||
const $form = $('#update_issueref_form');
|
||||
const params = new URLSearchParams();
|
||||
params.append('ref', selectedValue);
|
||||
try {
|
||||
await POST($form.attr('action'), {data: params});
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
} else if (editMode === '') {
|
||||
$selectBranch.find('.ui .branch-name').text(selectedValue);
|
||||
}
|
||||
|
@ -131,7 +139,7 @@ export function initRepoCommentForm() {
|
|||
|
||||
hasUpdateAction = $listMenu.data('action') === 'update'; // Update the var
|
||||
|
||||
const clickedItem = $(this);
|
||||
const $clickedItem = $(this);
|
||||
const scope = $(this).attr('data-scope');
|
||||
|
||||
$(this).parent().find('.item').each(function () {
|
||||
|
@ -140,10 +148,10 @@ export function initRepoCommentForm() {
|
|||
if ($(this).attr('data-scope') !== scope) {
|
||||
return true;
|
||||
}
|
||||
if (!$(this).is(clickedItem) && !$(this).hasClass('checked')) {
|
||||
if (!$(this).is($clickedItem) && !$(this).hasClass('checked')) {
|
||||
return true;
|
||||
}
|
||||
} else if (!$(this).is(clickedItem)) {
|
||||
} else if (!$(this).is($clickedItem)) {
|
||||
// Toggle for other labels
|
||||
return true;
|
||||
}
|
||||
|
@ -344,17 +352,18 @@ async function onEditContent(event) {
|
|||
this.on('success', (file, data) => {
|
||||
file.uuid = data.uuid;
|
||||
fileUuidDict[file.uuid] = {submitted: false};
|
||||
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
||||
$dropzone.find('.files').append(input);
|
||||
const $input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
||||
$dropzone.find('.files').append($input);
|
||||
});
|
||||
this.on('removedfile', (file) => {
|
||||
this.on('removedfile', async (file) => {
|
||||
if (disableRemovedfileEvent) return;
|
||||
$(`#${file.uuid}`).remove();
|
||||
if ($dropzone.attr('data-remove-url') && !fileUuidDict[file.uuid].submitted) {
|
||||
$.post($dropzone.attr('data-remove-url'), {
|
||||
file: file.uuid,
|
||||
_csrf: csrfToken,
|
||||
});
|
||||
try {
|
||||
await POST($dropzone.attr('data-remove-url'), {data: new URLSearchParams({file: file.uuid})});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.on('submit', () => {
|
||||
|
@ -362,8 +371,10 @@ async function onEditContent(event) {
|
|||
fileUuidDict[fileUuid].submitted = true;
|
||||
});
|
||||
});
|
||||
this.on('reload', () => {
|
||||
$.getJSON($editContentZone.attr('data-attachment-url'), (data) => {
|
||||
this.on('reload', async () => {
|
||||
try {
|
||||
const response = await GET($editContentZone.attr('data-attachment-url'));
|
||||
const data = await response.json();
|
||||
// do not trigger the "removedfile" event, otherwise the attachments would be deleted from server
|
||||
disableRemovedfileEvent = true;
|
||||
dz.removeAllFiles(true);
|
||||
|
@ -379,10 +390,12 @@ async function onEditContent(event) {
|
|||
dz.files.push(attachment);
|
||||
fileUuidDict[attachment.uuid] = {submitted: true};
|
||||
$dropzone.find(`img[src='${imgSrc}']`).css('max-width', '100%');
|
||||
const input = $(`<input id="${attachment.uuid}" name="files" type="hidden">`).val(attachment.uuid);
|
||||
$dropzone.find('.files').append(input);
|
||||
const $input = $(`<input id="${attachment.uuid}" name="files" type="hidden">`).val(attachment.uuid);
|
||||
$dropzone.find('.files').append($input);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -398,35 +411,37 @@ async function onEditContent(event) {
|
|||
}
|
||||
};
|
||||
|
||||
const saveAndRefresh = (dz) => {
|
||||
const saveAndRefresh = async (dz) => {
|
||||
showElem($renderContent);
|
||||
hideElem($editContentZone);
|
||||
$.post($editContentZone.attr('data-update-url'), {
|
||||
_csrf: csrfToken,
|
||||
content: comboMarkdownEditor.value(),
|
||||
context: $editContentZone.attr('data-context'),
|
||||
files: dz.files.map((file) => file.uuid),
|
||||
}, (data) => {
|
||||
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
content: comboMarkdownEditor.value(),
|
||||
context: $editContentZone.attr('data-context'),
|
||||
});
|
||||
for (const file of dz.files) params.append('files[]', file.uuid);
|
||||
|
||||
const response = await POST($editContentZone.attr('data-update-url'), {data: params});
|
||||
const data = await response.json();
|
||||
if (!data.content) {
|
||||
$renderContent.html($('#no-content').html());
|
||||
$rawContent.text('');
|
||||
} else {
|
||||
$renderContent.html(data.content);
|
||||
$rawContent.text(comboMarkdownEditor.value());
|
||||
|
||||
const refIssues = $renderContent.find('p .ref-issue');
|
||||
attachRefIssueContextPopup(refIssues);
|
||||
const $refIssues = $renderContent.find('p .ref-issue');
|
||||
attachRefIssueContextPopup($refIssues);
|
||||
}
|
||||
const $content = $segment;
|
||||
if (!$content.find('.dropzone-attachments').length) {
|
||||
if (data.attachments !== '') {
|
||||
$content.append(`<div class="dropzone-attachments"></div>`);
|
||||
$content.find('.dropzone-attachments').replaceWith(data.attachments);
|
||||
$content[0].append(data.attachments);
|
||||
}
|
||||
} else if (data.attachments === '') {
|
||||
$content.find('.dropzone-attachments').remove();
|
||||
} else {
|
||||
$content.find('.dropzone-attachments').replaceWith(data.attachments);
|
||||
$content.find('.dropzone-attachments')[0].outerHTML = data.attachments;
|
||||
}
|
||||
if (dz) {
|
||||
dz.emit('submit');
|
||||
|
@ -434,7 +449,9 @@ async function onEditContent(event) {
|
|||
}
|
||||
initMarkupContent();
|
||||
initCommentContent();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
if (!$editContentZone.html()) {
|
||||
|
@ -516,7 +533,7 @@ export function initRepository() {
|
|||
const gitignores = $('input[name="gitignores"]').val();
|
||||
const license = $('input[name="license"]').val();
|
||||
if (gitignores || license) {
|
||||
$('input[name="auto_init"]').prop('checked', true);
|
||||
document.querySelector('input[name="auto_init"]').checked = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,8 +2,7 @@ import $ from 'jquery';
|
|||
import {useLightTextOnBackground} from '../utils/color.js';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import {createSortable} from '../modules/sortable.js';
|
||||
|
||||
const {csrfToken} = window.config;
|
||||
import {POST, DELETE, PUT} from '../modules/fetch.js';
|
||||
|
||||
function updateIssueCount(cards) {
|
||||
const parent = cards.parentElement;
|
||||
|
@ -11,22 +10,23 @@ function updateIssueCount(cards) {
|
|||
parent.getElementsByClassName('project-column-issue-count')[0].textContent = cnt;
|
||||
}
|
||||
|
||||
function createNewColumn(url, columnTitle, projectColorInput) {
|
||||
$.ajax({
|
||||
url,
|
||||
data: JSON.stringify({title: columnTitle.val(), color: projectColorInput.val()}),
|
||||
headers: {
|
||||
'X-Csrf-Token': csrfToken,
|
||||
},
|
||||
contentType: 'application/json',
|
||||
method: 'POST',
|
||||
}).done(() => {
|
||||
async function createNewColumn(url, columnTitle, projectColorInput) {
|
||||
try {
|
||||
await POST(url, {
|
||||
data: {
|
||||
title: columnTitle.val(),
|
||||
color: projectColorInput.val(),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
columnTitle.closest('form').removeClass('dirty');
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function moveIssue({item, from, to, oldIndex}) {
|
||||
async function moveIssue({item, from, to, oldIndex}) {
|
||||
const columnCards = to.getElementsByClassName('issue-card');
|
||||
updateIssueCount(from);
|
||||
updateIssueCount(to);
|
||||
|
@ -38,18 +38,14 @@ function moveIssue({item, from, to, oldIndex}) {
|
|||
})),
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: `${to.getAttribute('data-url')}/move`,
|
||||
data: JSON.stringify(columnSorting),
|
||||
headers: {
|
||||
'X-Csrf-Token': csrfToken,
|
||||
},
|
||||
contentType: 'application/json',
|
||||
type: 'POST',
|
||||
error: () => {
|
||||
from.insertBefore(item, from.children[oldIndex]);
|
||||
},
|
||||
});
|
||||
try {
|
||||
await POST(`${to.getAttribute('data-url')}/move`, {
|
||||
data: columnSorting,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
from.insertBefore(item, from.children[oldIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
async function initRepoProjectSortable() {
|
||||
|
@ -67,20 +63,21 @@ async function initRepoProjectSortable() {
|
|||
ghostClass: 'card-ghost',
|
||||
delayOnTouchOnly: true,
|
||||
delay: 500,
|
||||
onSort: () => {
|
||||
onSort: async () => {
|
||||
boardColumns = mainBoard.getElementsByClassName('project-column');
|
||||
for (let i = 0; i < boardColumns.length; i++) {
|
||||
const column = boardColumns[i];
|
||||
if (parseInt($(column).data('sorting')) !== i) {
|
||||
$.ajax({
|
||||
url: $(column).data('url'),
|
||||
data: JSON.stringify({sorting: i, color: rgbToHex($(column).css('backgroundColor'))}),
|
||||
headers: {
|
||||
'X-Csrf-Token': csrfToken,
|
||||
},
|
||||
contentType: 'application/json',
|
||||
method: 'PUT',
|
||||
});
|
||||
try {
|
||||
await PUT($(column).data('url'), {
|
||||
data: {
|
||||
sorting: i,
|
||||
color: rgbToHex($(column).css('backgroundColor')),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -108,90 +105,85 @@ export function initRepoProject() {
|
|||
const _promise = initRepoProjectSortable();
|
||||
|
||||
$('.edit-project-column-modal').each(function () {
|
||||
const projectHeader = $(this).closest('.project-column-header');
|
||||
const projectTitleLabel = projectHeader.find('.project-column-title');
|
||||
const projectTitleInput = $(this).find('.project-column-title-input');
|
||||
const projectColorInput = $(this).find('#new_project_column_color');
|
||||
const boardColumn = $(this).closest('.project-column');
|
||||
const $projectHeader = $(this).closest('.project-column-header');
|
||||
const $projectTitleLabel = $projectHeader.find('.project-column-title');
|
||||
const $projectTitleInput = $(this).find('.project-column-title-input');
|
||||
const $projectColorInput = $(this).find('#new_project_column_color');
|
||||
const $boardColumn = $(this).closest('.project-column');
|
||||
|
||||
if (boardColumn.css('backgroundColor')) {
|
||||
setLabelColor(projectHeader, rgbToHex(boardColumn.css('backgroundColor')));
|
||||
if ($boardColumn.css('backgroundColor')) {
|
||||
setLabelColor($projectHeader, rgbToHex($boardColumn.css('backgroundColor')));
|
||||
}
|
||||
|
||||
$(this).find('.edit-project-column-button').on('click', function (e) {
|
||||
$(this).find('.edit-project-column-button').on('click', async function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
url: $(this).data('url'),
|
||||
data: JSON.stringify({title: projectTitleInput.val(), color: projectColorInput.val()}),
|
||||
headers: {
|
||||
'X-Csrf-Token': csrfToken,
|
||||
},
|
||||
contentType: 'application/json',
|
||||
method: 'PUT',
|
||||
}).done(() => {
|
||||
projectTitleLabel.text(projectTitleInput.val());
|
||||
projectTitleInput.closest('form').removeClass('dirty');
|
||||
if (projectColorInput.val()) {
|
||||
setLabelColor(projectHeader, projectColorInput.val());
|
||||
try {
|
||||
await PUT($(this).data('url'), {
|
||||
data: {
|
||||
title: $projectTitleInput.val(),
|
||||
color: $projectColorInput.val(),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
$projectTitleLabel.text($projectTitleInput.val());
|
||||
$projectTitleInput.closest('form').removeClass('dirty');
|
||||
if ($projectColorInput.val()) {
|
||||
setLabelColor($projectHeader, $projectColorInput.val());
|
||||
}
|
||||
boardColumn.attr('style', `background: ${projectColorInput.val()}!important`);
|
||||
$boardColumn.attr('style', `background: ${$projectColorInput.val()}!important`);
|
||||
$('.ui.modal').modal('hide');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.default-project-column-modal').each(function () {
|
||||
const boardColumn = $(this).closest('.project-column');
|
||||
const showButton = $(boardColumn).find('.default-project-column-show');
|
||||
const commitButton = $(this).find('.actions > .ok.button');
|
||||
const $boardColumn = $(this).closest('.project-column');
|
||||
const $showButton = $($boardColumn).find('.default-project-column-show');
|
||||
const $commitButton = $(this).find('.actions > .ok.button');
|
||||
|
||||
$(commitButton).on('click', (e) => {
|
||||
$($commitButton).on('click', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
method: 'POST',
|
||||
url: $(showButton).data('url'),
|
||||
headers: {
|
||||
'X-Csrf-Token': csrfToken,
|
||||
},
|
||||
contentType: 'application/json',
|
||||
}).done(() => {
|
||||
try {
|
||||
await POST($($showButton).data('url'));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.show-delete-project-column-modal').each(function () {
|
||||
const deleteColumnModal = $(`${$(this).attr('data-modal')}`);
|
||||
const deleteColumnButton = deleteColumnModal.find('.actions > .ok.button');
|
||||
const $deleteColumnModal = $(`${$(this).attr('data-modal')}`);
|
||||
const $deleteColumnButton = $deleteColumnModal.find('.actions > .ok.button');
|
||||
const deleteUrl = $(this).attr('data-url');
|
||||
|
||||
deleteColumnButton.on('click', (e) => {
|
||||
$deleteColumnButton.on('click', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
url: deleteUrl,
|
||||
headers: {
|
||||
'X-Csrf-Token': csrfToken,
|
||||
},
|
||||
contentType: 'application/json',
|
||||
method: 'DELETE',
|
||||
}).done(() => {
|
||||
try {
|
||||
await DELETE(deleteUrl);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#new_project_column_submit').on('click', (e) => {
|
||||
e.preventDefault();
|
||||
const columnTitle = $('#new_project_column');
|
||||
const projectColorInput = $('#new_project_column_color_picker');
|
||||
if (!columnTitle.val()) {
|
||||
const $columnTitle = $('#new_project_column');
|
||||
const $projectColorInput = $('#new_project_column_color_picker');
|
||||
if (!$columnTitle.val()) {
|
||||
return;
|
||||
}
|
||||
const url = $(this).data('url');
|
||||
createNewColumn(url, columnTitle, projectColorInput);
|
||||
const url = e.target.getAttribute('data-url');
|
||||
createNewColumn(url, $columnTitle, $projectColorInput);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
2
web_src/js/jquery.js
vendored
2
web_src/js/jquery.js
vendored
|
@ -1,3 +1,3 @@
|
|||
import $ from 'jquery';
|
||||
|
||||
window.$ = window.jQuery = $;
|
||||
window.$ = window.jQuery = $; // eslint-disable-line no-jquery/variable-pattern
|
||||
|
|
|
@ -73,7 +73,9 @@ function delegateOne($dropdown) {
|
|||
dropdownTemplates.menu = function(response, fields, preserveHTML, className) {
|
||||
// when the dropdown menu items are loaded from AJAX requests, the items are created dynamically
|
||||
const menuItems = dropdownTemplatesMenuOld(response, fields, preserveHTML, className);
|
||||
const $wrapper = $('<div>').append(menuItems);
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = menuItems;
|
||||
const $wrapper = $(div);
|
||||
const $items = $wrapper.find('> .item');
|
||||
$items.each((_, item) => updateMenuItem($dropdown[0], item));
|
||||
$dropdown[0][ariaPatchKey].deferredRefreshAriaActiveItem();
|
||||
|
|
|
@ -7,7 +7,8 @@ const visibleInstances = new Set();
|
|||
export function createTippy(target, opts = {}) {
|
||||
// the callback functions should be destructured from opts,
|
||||
// because we should use our own wrapper functions to handle them, do not let the user override them
|
||||
const {onHide, onShow, onDestroy, ...other} = opts;
|
||||
const {onHide, onShow, onDestroy, role, theme, ...other} = opts;
|
||||
|
||||
const instance = tippy(target, {
|
||||
appendTo: document.body,
|
||||
animation: false,
|
||||
|
@ -35,17 +36,14 @@ export function createTippy(target, opts = {}) {
|
|||
return onShow?.(instance);
|
||||
},
|
||||
arrow: `<svg width="16" height="7"><path d="m0 7 8-7 8 7Z" class="tippy-svg-arrow-outer"/><path d="m0 8 8-7 8 7Z" class="tippy-svg-arrow-inner"/></svg>`,
|
||||
role: 'menu', // HTML role attribute, only tooltips should use "tooltip"
|
||||
theme: other.role || 'menu', // CSS theme, either "tooltip", "menu" or "box-with-header"
|
||||
role: role || 'menu', // HTML role attribute
|
||||
theme: theme || role || 'menu', // CSS theme, either "tooltip", "menu" or "box-with-header"
|
||||
plugins: [followCursor],
|
||||
...other,
|
||||
});
|
||||
|
||||
// for popups where content refers to a DOM element, we use the 'tippy-target' class
|
||||
// to initially hide the content, now we can remove it as the content has been removed
|
||||
// from the DOM by tippy
|
||||
if (other.content instanceof Element) {
|
||||
other.content.classList.remove('tippy-target');
|
||||
if (role === 'menu') {
|
||||
target.setAttribute('aria-haspopup', 'true');
|
||||
}
|
||||
|
||||
return instance;
|
||||
|
|
|
@ -6,7 +6,6 @@ https://developer.mozilla.org/en-US/docs/Web/Web_Components
|
|||
|
||||
# Guidelines
|
||||
|
||||
* These components are loaded in `<head>` (before DOM body),
|
||||
so they should have their own dependencies and should be very light,
|
||||
then they won't affect the page loading time too much.
|
||||
* If the component is not a public one, it's suggested to have its own `Gitea` or `gitea-` prefix to avoid conflicts.
|
||||
* These components are loaded in `<head>` (before DOM body) in a separate entry point, they need to be lightweight to not affect the page loading time too much.
|
||||
* Do not import `svg.js` into a web component because that file is currently not tree-shakeable, import svg files individually insteat.
|
||||
* All our components must be added to `webpack.config.js` so they work correctly in Vue.
|
||||
|
|
40
web_src/js/webcomponents/absolute-date.js
Normal file
40
web_src/js/webcomponents/absolute-date.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
import {Temporal} from 'temporal-polyfill';
|
||||
|
||||
export function toAbsoluteLocaleDate(dateStr, lang, opts) {
|
||||
return Temporal.PlainDate.from(dateStr).toLocaleString(lang ?? [], opts);
|
||||
}
|
||||
|
||||
window.customElements.define('absolute-date', class extends HTMLElement {
|
||||
static observedAttributes = ['date', 'year', 'month', 'weekday', 'day'];
|
||||
|
||||
update = () => {
|
||||
const year = this.getAttribute('year') ?? '';
|
||||
const month = this.getAttribute('month') ?? '';
|
||||
const weekday = this.getAttribute('weekday') ?? '';
|
||||
const day = this.getAttribute('day') ?? '';
|
||||
const lang = this.closest('[lang]')?.getAttribute('lang') ||
|
||||
this.ownerDocument.documentElement.getAttribute('lang') || '';
|
||||
|
||||
// only use the first 10 characters, e.g. the `yyyy-mm-dd` part
|
||||
const dateStr = this.getAttribute('date').substring(0, 10);
|
||||
|
||||
if (!this.shadowRoot) this.attachShadow({mode: 'open'});
|
||||
this.shadowRoot.textContent = toAbsoluteLocaleDate(dateStr, lang, {
|
||||
...(year && {year}),
|
||||
...(month && {month}),
|
||||
...(weekday && {weekday}),
|
||||
...(day && {day}),
|
||||
});
|
||||
};
|
||||
|
||||
attributeChangedCallback(_name, oldValue, newValue) {
|
||||
if (!this.initialized || oldValue === newValue) return;
|
||||
this.update();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.initialized = false;
|
||||
this.update();
|
||||
this.initialized = true;
|
||||
}
|
||||
});
|
15
web_src/js/webcomponents/absolute-date.test.js
Normal file
15
web_src/js/webcomponents/absolute-date.test.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
import {toAbsoluteLocaleDate} from './absolute-date.js';
|
||||
|
||||
test('toAbsoluteLocaleDate', () => {
|
||||
expect(toAbsoluteLocaleDate('2024-03-15', 'en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})).toEqual('March 15, 2024');
|
||||
|
||||
expect(toAbsoluteLocaleDate('2024-03-15', 'de-DE', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
})).toEqual('15. März 2024');
|
||||
});
|
5
web_src/js/webcomponents/index.js
Normal file
5
web_src/js/webcomponents/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import './polyfills.js';
|
||||
import '@github/relative-time-element';
|
||||
import './origin-url.js';
|
||||
import './overflow-menu.js';
|
||||
import './absolute-date.js';
|
|
@ -15,7 +15,7 @@ export function toOriginUrl(urlStr) {
|
|||
return urlStr;
|
||||
}
|
||||
|
||||
window.customElements.define('gitea-origin-url', class extends HTMLElement {
|
||||
window.customElements.define('origin-url', class extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.textContent = toOriginUrl(this.getAttribute('data-url'));
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import {toOriginUrl} from './GiteaOriginUrl.js';
|
||||
import {toOriginUrl} from './origin-url.js';
|
||||
|
||||
test('toOriginUrl', () => {
|
||||
const oldLocation = window.location;
|
179
web_src/js/webcomponents/overflow-menu.js
Normal file
179
web_src/js/webcomponents/overflow-menu.js
Normal file
|
@ -0,0 +1,179 @@
|
|||
import {throttle} from 'throttle-debounce';
|
||||
import {createTippy} from '../modules/tippy.js';
|
||||
import {isDocumentFragmentOrElementNode} from '../utils/dom.js';
|
||||
import octiconKebabHorizontal from '../../../public/assets/img/svg/octicon-kebab-horizontal.svg';
|
||||
|
||||
window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||
updateItems = throttle(100, () => {
|
||||
if (!this.tippyContent) {
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('tippy-target');
|
||||
div.tabIndex = '-1'; // for initial focus, programmatic focus only
|
||||
div.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Tab') {
|
||||
const items = this.tippyContent.querySelectorAll('[role="menuitem"]');
|
||||
if (e.shiftKey) {
|
||||
if (document.activeElement === items[0]) {
|
||||
e.preventDefault();
|
||||
items[items.length - 1].focus();
|
||||
}
|
||||
} else {
|
||||
if (document.activeElement === items[items.length - 1]) {
|
||||
e.preventDefault();
|
||||
items[0].focus();
|
||||
}
|
||||
}
|
||||
} else if (e.key === 'Escape') {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.button._tippy.hide();
|
||||
this.button.focus();
|
||||
} else if (e.key === ' ' || e.code === 'Enter') {
|
||||
if (document.activeElement?.matches('[role="menuitem"]')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
document.activeElement.click();
|
||||
}
|
||||
} else if (e.key === 'ArrowDown') {
|
||||
if (document.activeElement?.matches('.tippy-target')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
document.activeElement.querySelector('[role="menuitem"]:first-of-type').focus();
|
||||
} else if (document.activeElement?.matches('[role="menuitem"]')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
document.activeElement.nextElementSibling?.focus();
|
||||
}
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
if (document.activeElement?.matches('.tippy-target')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
document.activeElement.querySelector('[role="menuitem"]:last-of-type').focus();
|
||||
} else if (document.activeElement?.matches('[role="menuitem"]')) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
document.activeElement.previousElementSibling?.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.append(div);
|
||||
this.tippyContent = div;
|
||||
}
|
||||
|
||||
// move items in tippy back into the menu items for subsequent measurement
|
||||
for (const item of this.tippyItems || []) {
|
||||
this.menuItemsEl.append(item);
|
||||
}
|
||||
|
||||
// measure which items are partially outside the element and move them into the button menu
|
||||
this.tippyItems = [];
|
||||
const menuRight = this.offsetLeft + this.offsetWidth;
|
||||
const menuItems = this.menuItemsEl.querySelectorAll('.item');
|
||||
for (const item of menuItems) {
|
||||
const itemRight = item.offsetLeft + item.offsetWidth;
|
||||
if (menuRight - itemRight < 38) { // roughly the width of .overflow-menu-button
|
||||
this.tippyItems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no overflown items, remove any previously created button
|
||||
if (!this.tippyItems?.length) {
|
||||
const btn = this.querySelector('.overflow-menu-button');
|
||||
btn?._tippy?.destroy();
|
||||
btn?.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
// remove aria role from items that moved from tippy to menu
|
||||
for (const item of menuItems) {
|
||||
if (!this.tippyItems.includes(item)) {
|
||||
item.removeAttribute('role');
|
||||
}
|
||||
}
|
||||
|
||||
// move all items that overflow into tippy
|
||||
for (const item of this.tippyItems) {
|
||||
item.setAttribute('role', 'menuitem');
|
||||
this.tippyContent.append(item);
|
||||
}
|
||||
|
||||
// update existing tippy
|
||||
if (this.button?._tippy) {
|
||||
this.button._tippy.setContent(this.tippyContent);
|
||||
return;
|
||||
}
|
||||
|
||||
// create button initially
|
||||
const btn = document.createElement('button');
|
||||
btn.classList.add('overflow-menu-button', 'btn', 'tw-px-2', 'hover:tw-text-text-dark');
|
||||
btn.setAttribute('aria-label', window.config.i18n.more_items);
|
||||
btn.innerHTML = octiconKebabHorizontal;
|
||||
this.append(btn);
|
||||
this.button = btn;
|
||||
|
||||
createTippy(btn, {
|
||||
trigger: 'click',
|
||||
hideOnClick: true,
|
||||
interactive: true,
|
||||
placement: 'bottom-end',
|
||||
role: 'menu',
|
||||
content: this.tippyContent,
|
||||
onShow: () => { // FIXME: onShown doesn't work (never be called)
|
||||
setTimeout(() => {
|
||||
this.tippyContent.focus();
|
||||
}, 0);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
init() {
|
||||
// ResizeObserver triggers on initial render, so we don't manually call `updateItems` here which
|
||||
// also avoids a full-page FOUC in Firefox that happens when `updateItems` is called too soon.
|
||||
this.resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
const newWidth = entry.contentBoxSize[0].inlineSize;
|
||||
if (newWidth !== this.lastWidth) {
|
||||
requestAnimationFrame(() => {
|
||||
this.updateItems();
|
||||
});
|
||||
this.lastWidth = newWidth;
|
||||
}
|
||||
}
|
||||
});
|
||||
this.resizeObserver.observe(this);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.setAttribute('role', 'navigation');
|
||||
|
||||
// check whether the mandatory `.overflow-menu-items` element is present initially which happens
|
||||
// with Vue which renders differently than browsers. If it's not there, like in the case of browser
|
||||
// template rendering, wait for its addition.
|
||||
// The eslint rule is not sophisticated enough or aware of this problem, see
|
||||
// https://github.com/43081j/eslint-plugin-wc/pull/130
|
||||
const menuItemsEl = this.querySelector('.overflow-menu-items'); // eslint-disable-line wc/no-child-traversal-in-connectedcallback
|
||||
if (menuItemsEl) {
|
||||
this.menuItemsEl = menuItemsEl;
|
||||
this.init();
|
||||
} else {
|
||||
this.mutationObserver = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
for (const node of mutation.addedNodes) {
|
||||
if (!isDocumentFragmentOrElementNode(node)) continue;
|
||||
if (node.classList.contains('overflow-menu-items')) {
|
||||
this.menuItemsEl = node;
|
||||
this.mutationObserver?.disconnect();
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
this.mutationObserver.observe(this, {childList: true});
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
this.mutationObserver?.disconnect();
|
||||
this.resizeObserver?.disconnect();
|
||||
}
|
||||
});
|
|
@ -1,5 +0,0 @@
|
|||
import '@webcomponents/custom-elements'; // polyfill for some browsers like PaleMoon
|
||||
import './polyfill.js';
|
||||
|
||||
import '@github/relative-time-element';
|
||||
import './GiteaOriginUrl.js';
|
Loading…
Add table
Add a link
Reference in a new issue