gh-board/style/app.less

1050 lines
24 KiB
Plaintext

@import './vendor';
@import (inline) '../node_modules/recordo/recordo.css';
@import './markdown-primer';
.user-select(@type) {
-webkit-user-select: @type;
user-select: @type;
}
.x-stripes(@color; @opacity) {
background-color: @color;
background-image: linear-gradient(to bottom left,
rgba(255,255,255, @opacity) 25%,
transparent 25%,
transparent 50%,
rgba(255,255,255, @opacity) 50%,
rgba(255,255,255, @opacity) 75%,
transparent 75%,
transparent);
background-size: 1pc 1pc;
}
.x-font-and-emoji(@size) {
font-size: @size;
.emoji { height: @size; }
}
.x-clearfix() {
&::before {
display: table;
content: ' ';
}
}
body { background-color: #ddd; }
.app {
/* Allow enough space on top/bottom of screen for fixed header/footer */
padding-top: 5rem;
padding-bottom: 4rem;
// Styles for the whole app (no matter where they occur)
// TODO: Mixin?
.badge {
cursor: pointer;
box-shadow: inset 0 -1px 0 rgba(0,0,0,0.12); // From GH Issues
font-size: 1rem;
&.is-light { color: black; }
&:not(.is-light) { color: white; }
.x-font-and-emoji(1.25rem);
}
.badge { margin-right: .3rem; }
.avatar-image {
display: inline-block;
overflow: hidden;
line-height: 1;
vertical-align: middle;
width: 2.5rem;
height: 2.5rem;
border-radius: 1.25rem;
}
.bottombar-nav { opacity: .9; }
.topbar-nav {
// Add a check next to settings menu items
.settings-item-checkbox[data-checked='true']::before {
// From `.octicon`
font: normal normal normal 16px/1 octicons;
display: inline-block;
text-decoration: none;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
// From `.octicon-check`
content: '\f03a';
position: absolute;
left: 5px;
}
.milestone-dropdown {
.milestone-title {
.x-font-and-emoji(14px); // from the item styling
}
.milestone-item {
> a {
display: table;
width: 100%;
padding: 3px 20px; // from bootstrap .dropdown-menu > li > a
.milestone-title,
.due-at,
.milestone-icon {
display: table-cell;
white-space: nowrap;
}
.milestone-title,
.due-at {
padding-left: 1rem;
}
.milestone-title {
width: 100%; // so the columns all line up
text-align: left;
}
.due-at {
color: #888;
text-align: right;
}
}
}
}
.repo-links {
padding-top: 15px;
padding-bottom: 15px;
display: inline-block;
// handle many repos (just hide the rest)
max-width: 550px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.repo-owner {
padding-right: .5rem;
}
.repo-name {
padding-left: .5rem;
padding-right: .5rem;
}
}
.active-filter {
// &:not(:empty)::before { content: 'Active Filter: '; }
.badge {
margin-right: .3rem; // space between labels
&::after {
content: 'x';
padding-left: 0.5rem;
}
}
}
}
// .bottombar-nav .navbar-right:not(:hover) .nav-squirrel { display: none; }
.kanban-board {
// "ideal" widths for each column
.x-column-widths(@counter) when (@counter > 0) {
.x-column-widths((@counter - 1));
&[data-column-count="@{counter}"] {
@percent: round(100 / @counter) / 100;
.kanban-board-column { width: percentage(@percent); }
}
}
// .x-column-widths(10);
.kanban-board-column {
// .x-column-widths specifies the "ideal" widths but this ensures there is a minimum
// min-width: 35rem; // make it more than 30 to account for secondary repo names.
vertical-align: top;
padding-left: 1rem;
padding-right: 0;
// contains .issue-list
}
} /* End kanban-board */
.dashboard {
.example-repo-input {
width: 100px;
display: inline;
}
.repo-item {
.repo-icon,
.repo-open-link,
.repo-private-label { margin-right: 1rem; }
.repo-updated-at {
color: #888;
&::before { content: '('; }
&::after { content: ')'; }
}
}
}
.bottombar-nav .karma-stats {
padding: 5px;
display: inline-block;
color: #777; // from .navbar-default .navbar-nav > li > a
cursor: default;
&:not(.is-karma-low):not(:hover) .reset-at {
display: none;
}
.karma-progress {
display: inline-block;
margin-bottom: -3px;
width: 20rem;
}
}
}
/* Move the padding to the title so the color fills up the entire header */
.issue-list {
// box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.15);
background-color: #f3f3f3;
border-radius: 0; // override bootstrap
.panel-heading {
padding: 0;
.column-title {
font-weight: normal;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
// display: inline-block;
// give the icon some padding so we can make a colored square
&:not(.has-icon) { padding: 10px 15px; }
&.has-icon {
padding-left: 0;
padding-right: 15px;
padding-top: 0;
padding-bottom: 0;
.label-title,
.milestone-title {
padding-top: 10px;
padding-bottom: 10px;
padding-left: 1rem; // so text is not squished next to the icon
}
}
.x-font-and-emoji(16px); // This is what is set on the <h2>
.column-icon {
display: inline-block;
padding: 10px 15px;
margin: 0; // override colored-icon has a margin
border-radius: 0; //override colored-icon
&:not(.is-light) { color: white; }
}
/* Support filtering on a single kanban column */
.label-title,
.milestone-title {
color: inherit; // It's an <a> but don't make it blue
cursor: pointer;
.octicon { padding-right: 1rem; }
&:hover { text-decoration: none; }
}
}
}
// DnD styling
&:not(.is-over) .dnd-placeholder { display: none; }
.dnd-placeholder {
background-color: #fefefe;
height: 5rem;
margin: 2rem;
border-radius: 3px;
border: 1px dashed #aaa;
text-align: center;
line-height: 2.5rem;
color: #888;
&::before { content: 'Release to drop me in this list'; }
}
// Each Issue
.issue {
cursor: move;
padding-top: 0;
padding-right: 0;
padding-bottom: 0;
padding-left: 0; // don't leave room to show the CI and mergeable status
margin-top: 1rem;
margin-left: 1rem;
margin-right: 1rem;
border-radius: 3px !important;
// Inspired by http://the-echoplex.net/flexyboxes/
&.is-simple-list {
border-radius: 0 !important;
margin: 1px;
// border: 1px solid black;
padding: .5rem;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: flex-start;
align-items: flex-start;
align-content: stretch;
.avatar-filter { flex: 0 0 auto; }
.issue-title {
flex: 1 1 auto;
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: hidden;
padding-left: 1rem;
}
.issue-number {
flex: 0 0 auto;
color: #ccc;
}
}
/* Just make the issue gray so it is clear we are dragging this element from */
&.is-dragging { opacity: .25; }
&[data-state='closed'] { opacity: 0.5; }
// When remotely updated since you last looked, mark the issue as yellow
&.is-updated { background-color: #fcfcd9; }
&.is-pull-request-to-different-branch { background-color: #e9e9fc; }
// The little `[4/5]` section
.task-list-overview {
cursor: pointer;
font-size: 1.2rem;
&.is-done { color: #0c0; }
&:not(.is-done) { color: #ccc; }
}
// Hide the Issue icon if it is an Issue
&:not(:hover) .issue-blurb:not(.is-pull-request) .blurb-icon {
visibility: hidden;
}
.list-group-item-heading {
margin-bottom: 1rem;
padding-left: 1rem;
padding-right: 1rem;
padding-top: 1rem;
// background-color: white;
font-weight: normal; // from h4
.x-font-and-emoji(14px); // This is what is set on the <h4>
> .issue-blurb {
.blurb-number-link { color: #337ab7; } // bootstrap link color
// all blurbs contain the column they are in, so hide it here
.colored-icon { display: none; }
}
// a.issue-status:hover { text-decoration: none; }
.issue-status {
font-size: 1rem;
&[data-status-state='success'] { color: #6cdf44; }
&[data-status-state='pending'] { color: #fb0; }
&[data-status-state='error'],
&[data-status-state='failure'] { color: #d00; font-weight: bold; }
.status-icon { }
}
.merge-conflict-warning { color: #ee0; }
// .related-issues .issue-blurb {
// color: #999;
// font-weight: normal; /* Because it is in a H4 thanks to ListGroupItem */
// font-size: 1.5rem;
// }
// // The list of labels(tags)
// .issue-labels .badge {
// max-width: 10rem;
// overflow-x: hidden;
// text-overflow: ellipsis;
// }
}
&:not(:hover) .list-group-item-heading .etherpad-issue-edit { display: none; }
// Depending on the issue listing type (simple or card) this element could be in the footer, or not
.issue-due-at {
&.is-overdue { color: #d00; font-weight: bold; }
&.is-near { color: #fb0; }
&:not(.is-near):not(.is-overdue) { color: #ccc; }
font-size: 1rem;
padding-left: .5rem;
padding-right: .5rem;
white-space: nowrap; // because of flexbox
}
.issue-title {
display: block;
// it's a link
color: black;
font-weight: normal;
text-decoration: none;
.x-font-and-emoji(1.5rem);
&:hover { text-decoration: none; }
}
.list-group-item-text {
// background-color: white;
padding-left: 1rem;
padding-right: 1rem;
padding-bottom: 1rem;
font-size: 2rem;
// Sometimes the non-primary repo name is long
// if so, add ellipses that expand when hovered
// .issue-blurb {
// .blurb-number-link {
// .blurb-secondary-repo,
// .blurb-number {
// // TODO: get the underline to show up again
// display: inline-block;
// white-space: nowrap;
// vertical-align: middle;
// }
// }
// &:not(:hover) .blurb-number-link .blurb-secondary-repo {
// max-width: 11rem;
// overflow-x: hidden;
// text-overflow: ellipsis;
// }
// // Chrome only underlines links with display:inline
// .blurb-number-link:hover * { text-decoration: underline; }
// }
.task-list-overview { padding: 0 2rem; }
.issue-labels { display: block; }
.badge {
max-width: 15rem;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
line-height: 1.2rem;
padding: 5px;
}
.issue-milestone {
display: inline-block;
border: 1px solid #666;
max-width: 15rem;
// text-overflow: ellipsis;
// overflow: hidden;
// white-space: nowrap;
// line-height: 1.2rem;
padding: 2px;
// it's a link
color: black;
background-color: inherit;
font-weight: normal;
text-decoration: none;
&:hover { text-decoration: none; }
.x-font-and-emoji(1.2rem); // same as font size
.milestone-icon { color: #ccc; }
.milestone-title {
color:inherit; // it's an <a> but don't make it blue
padding-left: .5rem;
}
}
.issue-footer {
// .x-clearfix();
display: block;
min-height: 2rem;
.issue-time-and-user {
display: block;
float: right;
time.updated-at,
.comments-count {
font-size: 1.2rem;
color: #999;
padding-right: 1rem;
display: inline-block;
white-space: nowrap;
vertical-align: middle;
}
.comments-count-number { padding-right: .5rem; }
time.updated-at {
max-width: 9rem;
overflow-x: hidden;
text-overflow: ellipsis;
}
.avatar-image { cursor: pointer; }
}
}
}
// Elements that can occur anywhere in an issue
/* When a Pull Request is not mergeable then make the background a light gray with slashes */
/* Default merge conflict color when no CI status */
&.is-pull-request {
// &:not(.is-mergeable) .list-group-item-heading .issue-blurb .blurb-icon { .x-stripes(#ccc; .8); }
&.is-merge-conflict:not(.is-updated) { .x-stripes(#fcfcfc; .9); }
&.is-merge-conflict.is-updated { .x-stripes(#fcfcd9; .9); }
&.is-merge-conflict.is-pull-request-to-different-branch { .x-stripes(#e9e9fc; .9); }
}
/* Color the blurb icon to be gray if there is an issue */
// &.is-pull-request {
// /* When a Pull Request is not mergeable then make the background a light gray with slashes */
// /* Default merge conflict color when no CI status */
// &:not(.is-mergeable) { .x-stripes(#ccc; .8); }
//
// // Make the blurb icon gray when the PR is not mergeable
// // or when CI does not report success
// &:not(.is-mergeable),
// &[data-status-state='pending'],
// &[data-status-state='error'],
// &[data-status-state='failure'] {
// .issue-footer .blurb-icon { color: #888; }
// }
//
// /* Pull Request status. pending, success, error, or failure */
// &[data-status-state='pending'] {
// // TODO: Move the animation into the mixin
// // Animate the bar while CI is running (uses bootstrap's progress-bar-stripes)
// -webkit-animation: progress-bar-stripes 2s linear infinite;
// animation: progress-bar-stripes 2s linear infinite;
//
// .x-stripes(#fcfc00; .9);
// }
// &[data-status-state='success'] { background-color: #6cdf44; } &[data-status-state='error'] { background-color: #d00; }
// &[data-status-state='failure'] { background-color: #d00; }
//
// }
} /* End Issue */
.related-issues {
background-color: #e6e6e6;
margin-top: 0;
margin-left: 1rem;
margin-right: 1rem;
margin-bottom: 1rem;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
padding-left: 1rem;
box-shadow: inset 0 2px 7px -5px #333;
.related-issue {
overflow: hidden;
white-space: nowrap;
// max-width: 100%;
text-overflow: ellipsis;
.colored-icon { opacity: .5; }
}
}
}
// These are/can-be outside of the app
.popover {
max-width: 500px;
&.popover-issue-body {
min-width: 400px; // some popovers are inside an <a> which is inside an Issue body
.arrow { display: none; }
}
.popover-content {
max-height: 300px;
overflow-y: auto;
}
// When looking at the task-list popover only show the task lists
&.task-list-details .markdown-body {
> :not(.task-list),
// also hide any child list items that do not have a checkbox
.task-list li:not(.task-list-item) { display: none; }
}
}
// Move this into a mixin if we use it outside of popovers
.markdown-body {
&.is-empty {
color: #ccc;
font-style: italic;
&::before { content: 'No Content provided.'; }
}
/* Make sure images are scaled to fit in the modal */
img { max-width: 100%; }
.x-font-and-emoji(1.5rem);
// Style code blocks similar to GitHub (Override bootstrap's default)
code { color: initial; }
// Mostly from GH Issues and PRs
.issue-status-badge {
&[data-state='reopened'],
&[data-state='open'] { background-color: #6cc644; }
&[data-state='closed'] { background-color: #bd2c00; }
&[data-state='merged'] { background-color: #6e5494; }
background-color: #666; // default (no state)
color: white;
display: inline-block;
white-space: nowrap;
margin-left: .5rem;
padding: 1px 5px;
font-size: 12px;
border-radius: 3px;
text-align: center;
font-weight: bold;
}
// only apply padding to the top-most task list
> .task-list {
padding-left: 0;
.task-list-item {
list-style-type: none;
.task-list-item-checkbox {
cursor: default;
vertical-align: middle;
margin-right: .5rem;
}
}
}
}
// All blurbs, not just the footer, get a pointer and link color inherits
// A blurb can be inside an issue or in the move modal
.issue-blurb {
.blurb-context,
.blurb-icon {
cursor: pointer;
margin-left: .5rem;
&[data-state='merged'] { color: #6e5494; }
&[data-state='closed'] { color: #bd2c00; }
&[data-state='open'] { color: #6cc644; }
}
.blurb-context { margin-right: .5rem; }
.blurb-number-link {
// color: #66f;
&:hover { text-decoration: none; }
}
.blurb-secondary-repo {
display: inline-block;
margin-left: .5rem;
color: #ccc;
}
&.is-pull-request .blurb-icon { color: #6cc644; }
// color is from https://github.com/notifications
&.is-pull-request.is-merged .blurb-icon { color: #6e5494; }
.blurb-context { color: #666; }
}
.modal .anonymous-instructions [disabled] {
opacity: 1;
}
// move the checkbox to cover the list bullet just like a <BS.FormControl> without a label=""
.modal.move-issue {
.related-issues .related-issue {
list-style: none;
.select-related-issue { margin-left: -20px; }
.issue-blurb .colored-icon { display: none; }
}
}
.app.is-table-layout {
.kanban-board {
display: table;
&::before,
&::after { display: none; }
> .row {
display: table-row;
&::before,
&::after { display: none; }
.kanban-board-column {
min-width: 30rem;
display: table-cell;
float: none;
.issue-list {
width: 30rem;
}
}
}
}
}
// Override bootstrap breakpoints for the nav bar on smaller screens
.topbar-nav {
.container {
.navbar-header {
float: left;
margin-right: 0;
margin-left: 0;
}
.navbar-nav {
float: left;
margin: 0;
> li {
float: left;
> a {
padding-top: 15px;
padding-bottom: 15px;
display: inline-block;
}
}
}
.navbar-right {
// .pull-right();
float: right !important;
margin-right: -15px;
}
}
}
// More bootstrap overrides
.dropdown-header {
.user-select(none);
cursor: default;
}
// buttons made to look like links have extra padding
.btn.btn-link { padding: 0; }
@-webkit-keyframes icon-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
@keyframes icon-spin {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(359deg);
transform: rotate(359deg);
}
}
i.icon-spin {
-webkit-animation: icon-spin 2s infinite linear;
animation: icon-spin 2s infinite linear;
}
@media (min-width: 992px) {
.kanban-board[data-column-count="1"] .kanban-board-column {
width: 70%;
max-width: 1024px;
}
}
.sign-in a {
padding: 5px !important;
line-height: 15px !important;
// .btn
font-size: 14px;
font-weight: normal;
text-align: center;
white-space: nowrap;
vertical-align: middle;
.user-select(none);
border-radius: 4px;
// .btn-success
color: white !important;
background-color: #5cb85c;
border-color: #4cae4c;
&:hover,
&:focus {
background-color: lighten(#5cb85c, 10%) !important; // btn-success
}
}
.game-modal {
.modal-content {
width: 720px;
.game-wrapper {
width: 690px;
height: 534px;
}
}
}
// react-dnd now requires DragSource and DropTarget elements to be simple Components
// so I had to insert a wrapper div around ListGroupItem
// .list-group > .-drag-source + .-drag-source { border-top: 1px solid #eee; }
.badge { border-radius: 3px; font-weight: normal; }
.navbar { min-height: 20px; } // bootstrap
// from bootstrap
.topbar-nav .container {
padding-top: 10px;
padding-bottom: 10px;
.navbar-brand,
.navbar-nav > li,
.navbar-nav > li > a {
padding-top: 0;
padding-bottom: 0;
}
}
.navbar-brand { height: 20px; }
.etherpad-wrapper {
// display: table;
// width: 100%;
// .etherpad-inner {
// display: table-row;
// .etherpad-edit {
// // display: table-cell;
// // vertical-align: top;
// iframe {
// min-width: 600px;
// height: 600px;
// }
// }
iframe { height: 600px; }
.etherpad-preview {
// display: table-cell;
// vertical-align: top;
.markdown-body {
height: 600px;
overflow-y: auto;
background-color: #fff;
padding: 1em;
}
}
// }
// display: flex;
// flex-direction: row;
}
.filter-menu {
> .dropdown-menu {
width: 32rem; // this matches the ellipses for milestones
.filter-panel {
margin-bottom: 0; // override bootstrap
> .panel-body {
// padding: 0; //override bootstrap
}
.filter-category {
.panel-body {
padding: 0; //override bootstrap
}
.form-group,
.list-group {
margin-bottom: 0; // override bootstrap
}
//...
.list-group {
// allow vertical scrolling
max-height: 380px; // TODO: have this be calculated by the page height
overflow-y: auto;
.list-group-item {
padding: 5px 10px; // make it narrower than bootstrap's default
&:hover { background-color: #eee; }
// padd just enough for the missing octicon-check
&:not(.is-selected) { padding-left: 3.1rem; }
// Hide the exclude button unless hovering over the item
&:not(.is-excluded):not(:hover) .item-toggle-exclude { display: none; }
// Make selected (or excluded) items bold
&.is-selected,
&.is-excluded {
.item-text { font-weight: bold; }
}
.item-checkmark { margin-right: 1rem; }
.item-text {
display: inline-block;
margin-left: 1rem;
color: inherit; // override the blue link color
// milestones are long; truncate them
max-width: 21rem;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
}
.item-toggle-exclude { float: right; }
.item-icon {
width: 1em;
height: 1em;
display: inline-block;
border-radius: 3px;
}
}
}
}
}
}
}
.colored-icon {
display: inline-block;
// padding: 3px 8px;
padding: 1px 6px;
margin: 2px;
border-radius: 3px;
&:not(.is-light) { color: white; }
}
.octicon.private {
color: #e9dba5;
}
// burnup chart needs a background color
.burnup {
margin-left: 2rem;
margin-right: 2rem;
.burnup-chart {
background-color: white;
}
}
.featured-image {
max-width: 100%;
max-height: 100px;
display: block;
margin-left: auto;
margin-right: auto;
}
.batch-label .label-actions {
text-align: right;
.action-delete { color: #bd2c00; }
}
// These are the badges for Issues that are in GFM.
.issue-status-badges .issue-title {
color: #666;
background-color: #eee;
display: inline-block;
cursor: default;
&:not(:hover) {
max-width: 30rem;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
}
&::before { content: '('; }
&::after { content: ')'; }
}