diff --git a/customize.dist/pages.js b/customize.dist/pages.js
index 4cd4f49f4..7e2cf4969 100644
--- a/customize.dist/pages.js
+++ b/customize.dist/pages.js
@@ -56,6 +56,7 @@ define([
footLink('/code/', 'main_code'),
footLink('/slide/', 'main_slide'),
footLink('/poll/', 'main_poll'),
+ footLink('/kanban/', 'main_kanban'),
footLink('/whiteboard/', null, Msg.type.whiteboard)
]),
footerCol('footer_aboutUs', [
@@ -557,6 +558,7 @@ define([
[ 'code', '/code/', Msg.main_codePad, 'fa-file-code-o' ],
[ 'slide', '/slide/', Msg.main_slidePad, 'fa-file-powerpoint-o' ],
[ 'poll', '/poll/', Msg.main_pollPad, 'fa-calendar' ],
+ [ 'kanban', '/kanban/', Msg.main_kanbanPad, 'fa-calendar' ],
[ 'whiteboard', '/whiteboard/', Msg.main_whiteboardPad, 'fa-paint-brush' ],
[ 'recent', '/drive/', Msg.main_localPads, 'fa-hdd-o' ]
].filter(function (x) {
@@ -884,5 +886,12 @@ define([
];
};
+ Pages['/kanban/'] = Pages['/kanban/index.html'] = function () {
+ return [
+ appToolbar(),
+ h('div#cp-app-kanban-content', [])
+ ];
+ };
+
return Pages;
});
diff --git a/customize.dist/src/less2/include/colortheme.less b/customize.dist/src/less2/include/colortheme.less
index 1bdb69291..e2406653d 100644
--- a/customize.dist/src/less2/include/colortheme.less
+++ b/customize.dist/src/less2/include/colortheme.less
@@ -61,6 +61,13 @@
@colortheme_poll-th-fg: #fff;
@colortheme_poll-warn: #ffade3;
+@colortheme_kanban-bg: #006304;
+@colortheme_kanban-color: #fff;
+@colortheme_kanban-help-bg: #bbffbb;
+@colortheme_kanban-th-bg: #005bef;
+@colortheme_kanban-th-fg: #fff;
+@colortheme_kanban-warn: #ffade3;
+
@colortheme_whiteboard-bg: #800080;
@colortheme_whiteboard-color: #fff;
@colortheme_whiteboard-warn: #ffae00;
diff --git a/customize.dist/src/less2/main.less b/customize.dist/src/less2/main.less
index dadbef539..68f1ca9c8 100644
--- a/customize.dist/src/less2/main.less
+++ b/customize.dist/src/less2/main.less
@@ -34,6 +34,7 @@ body.cp-app-file { @import "../../../file/app-file.less"; }
body.cp-app-filepicker { @import "../../../filepicker/app-filepicker.less"; }
body.cp-app-contacts { @import "../../../contacts/app-contacts.less"; }
body.cp-app-poll { @import "../../../poll/app-poll.less"; }
+body.cp-app-kanban { @import "../../../kanban/app-kanban.less"; }
body.cp-app-whiteboard { @import "../../../whiteboard/app-whiteboard.less"; }
body.cp-app-todo { @import "../../../todo/app-todo.less"; }
body.cp-app-profile { @import "../../../profile/app-profile.less"; }
diff --git a/customize.dist/src/less2/pages/page-index.less b/customize.dist/src/less2/pages/page-index.less
index 55671f913..6ddee6349 100644
--- a/customize.dist/src/less2/pages/page-index.less
+++ b/customize.dist/src/less2/pages/page-index.less
@@ -154,6 +154,7 @@ h4 {
.cp-callout-code .fa { background-color: @colortheme_code-bg; }
.cp-callout-slide .fa { background-color: @colortheme_slide-bg; }
.cp-callout-poll .fa { background-color: @colortheme_poll-bg; }
+.cp-callout-kanban .fa { background-color: @colortheme_kanban-bg; }
.cp-callout-whiteboard .fa { background-color: @colortheme_whiteboard-bg; }
.cp-callout-recent .fa { background-color: @colortheme_drive-bg; }
.cp-hidden { display: none !important; }
diff --git a/customize.dist/translations/messages.js b/customize.dist/translations/messages.js
index 868d107cd..d6d186a15 100644
--- a/customize.dist/translations/messages.js
+++ b/customize.dist/translations/messages.js
@@ -8,6 +8,7 @@ define(function () {
out.type.pad = 'Rich text';
out.type.code = 'Code';
out.type.poll = 'Poll';
+ out.type.kanban = 'Kanban';
out.type.slide = 'Presentation';
out.type.drive = 'CryptDrive';
out.type.whiteboard = 'Whiteboard';
@@ -21,6 +22,7 @@ define(function () {
out.button_newpoll = 'New Poll';
out.button_newslide = 'New Presentation';
out.button_newwhiteboard = 'New Whiteboard';
+ out.button_newkanban = 'New Kanban';
// NOTE: Remove updated_0_ if we need an updated_1_
out.updated_0_common_connectionLost = "Server Connection Lost
You're now in read-only mode until the connection is back.";
@@ -245,6 +247,9 @@ define(function () {
out.pad_mediatagWidth = "Width (px)";
out.pad_mediatagHeight = "Height (px)";
+ // Kanban
+ out.kanban_title = "Kanban";
+
// Polls
out.poll_title = "Zero Knowledge Date Picker";
diff --git a/www/kanban/app-kanban.less b/www/kanban/app-kanban.less
new file mode 100644
index 000000000..a52ade01c
--- /dev/null
+++ b/www/kanban/app-kanban.less
@@ -0,0 +1,671 @@
+@import (once) "../../customize/src/less2/include/browser.less";
+@import (once) "../../customize/src/less2/include/toolbar.less";
+@import (once) "../../customize/src/less2/include/markdown.less";
+@import (once) '../../customize/src/less2/include/fileupload.less';
+@import (once) '../../customize/src/less2/include/alertify.less';
+@import (once) '../../customize/src/less2/include/tokenfield.less';
+@import (once) '../../customize/src/less2/include/tools.less';
+@import (once) '../../customize/src/less2/include/avatar.less';
+@import (once) '../../customize/src/less2/include/creation.less';
+
+.toolbar_main(
+ @bg-color: @colortheme_kanban-bg,
+ @warn-color: @colortheme_kanban-warn,
+ @color: @colortheme_kanban-color
+);
+.fileupload_main();
+.alertify_main();
+.tokenfield_main();
+.creation_main();
+
+@kanban-fore: #555;
+
+@kanban-th-bg: @colortheme_kanban-th-bg;
+@kanban-th-fg: @colortheme_kanban-th-fg;
+@kanban-th-user-bg: darken(@kanban-th-bg, 10%);
+@kanban-editing: lighten(@kanban-th-bg, 10%);
+@kanban-winner: darken(@kanban-th-bg, 15%);
+@kanban-td-bg: @kanban-th-bg;
+@kanban-td-fg: @kanban-th-fg;
+
+@kanban-help-bg: @colortheme_kanban-help-bg;
+
+@kanban-uncommitted-cell: #eee;
+@kanban-uncommitted-bg: #ddd; //lighten(@kanban-th-bg, 50%);
+@kanban-uncommitted-text: black;
+
+@kanban-placeholder: #fff;
+@kanban-border-color: #555;
+@kanban-cover-color: #000;
+@kanban-fg: #000;
+@kanban-option-yellow: #ff5;
+@kanban-option-gray: #ccc;
+
+@kanban-add-color: #fff;
+@kanban-add-bg: #777;
+@kanban-add-bg-alt: #444;
+
+.bottom-left(@s: 5px) { border-bottom-left-radius: @s; }
+.top-left(@s: 5px) { border-top-left-radius: @s; }
+
+display: flex;
+flex-flow: column;
+overflow-x: hidden;
+
+#cp-app-kanban-content {
+ display: flex;
+ flex: 1;
+ min-height: 0;
+ #cp-app-kanban-form {
+ flex: 1;
+ overflow-y: auto;
+ &.cp-app-kanban-readonly {
+ #cp-app-kanban-table-scroll {
+ max-width: ~"calc(75% - 30px - 100px)";
+ }
+ table {
+ width: 100%;
+ }
+ table tr td:last-child {
+ margin-left: 0; // uncommitted is hidden
+ }
+ td.cp-app-kanban-table-uncommitted {
+ display: none;
+ }
+ }
+ &.cp-app-kanban-published {
+ #cp-app-kanban-create-option {
+ display: none;
+ }
+ .cp-app-kanban-table-remove[data-rt-id^="y"], .cp-app-kanban-table-edit[data-rt-id^="y"] {
+ display: none;
+ }
+ tr.cp-app-kanban-table-uncommitted {
+ display: none;
+ }
+ }
+ }
+}
+
+input[type="text"], textarea {
+ background-color: white;
+ color: black;
+ border: 0;
+}
+
+input[type="text"][disabled], textarea[disabled] {
+ background-color: transparent;
+ border: 0px;
+}
+
+// The placeholder color only seems to effect Safari when not set
+
+input[type="text"][disabled]::placeholder {
+ color: @kanban-placeholder;
+ opacity: 1;
+}
+
+table#cp-app-kanban-table {
+ margin: 0px;
+ overflow: hidden;
+}
+#cp-app-kanban-table-container {
+ position: relative;
+ margin: 20px;
+}
+#cp-app-kanban-table-container button {
+ border-radius: 0;
+ border: 0;
+}
+#cp-app-kanban-create-user {
+ display: inline-flex;
+ height: 20px;
+ padding: 0 5px;
+ margin: 2px auto;
+ width: auto;
+ overflow: hidden;
+ color: @kanban-add-color;
+ background: @kanban-add-bg;
+ &:hover {
+ background: @kanban-add-bg-alt;
+ }
+}
+#cp-app-kanban-create-option {
+ order: 3;
+ display: inline-flex;
+ width: 46px;
+ height: 20px;
+ margin: 2px;
+ padding: 0;
+ color: @kanban-add-color;
+ background: @kanban-add-bg;
+ &:hover {
+ background: @kanban-add-bg-alt;
+ }
+}
+#cp-app-kanban-table-scroll {
+ overflow-y: hidden;
+ overflow-x: auto;
+ margin-left: 25%;
+ max-width: ~"calc(75% - 100px - 100px)";
+ width: auto;
+ display: inline-block;
+}
+.cp-markdown-toolbar {
+ margin: auto;
+ min-width: 80%;
+ width: 80%;
+}
+#cp-app-kanban-description {
+ &~ .CodeMirror {
+ margin: auto;
+ min-width: 80%;
+ width: 80%;
+ min-height: 200px;
+ height: 200px;
+ border: 1px solid black;
+ .CodeMirror-placeholder {
+ color: #777;
+ }
+ }
+}
+#cp-app-kanban-description-published {
+ display: none;
+ padding: 15px;
+ margin: auto;
+
+ min-width: 80%;
+ width: 80%;
+ min-height: 7em;
+ color: #000;
+ border: 1px solid transparent;
+ background-color: #eeeeee;
+ font: @colortheme_app-font;
+ text-align: left;
+ media-tag > * {
+ max-width: 100%;
+ max-height: 20em;
+ }
+}
+div.cp-app-kanban-published {
+ div.cp-app-kanban-realtime {
+ #cp-app-kanban-description {
+ display: none;
+ &~ .CodeMirror {
+ display: none;
+ }
+ }
+ #cp-app-kanban-description-published {
+ display: block;
+ &:empty {
+ display: none;
+ }
+ }
+ #cp-app-kanban-nocomments {
+ display: none;
+ }
+ #cp-app-kanban-comments {
+ display: block;
+ }
+ }
+}
+
+#cp-app-kanban-help {
+ width: 100%;
+ margin: auto;
+ padding: 20px 10%;
+ background: @kanban-help-bg;
+}
+
+// from cryptpad.less
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+ margin: 20px;
+}
+tbody {
+ * {
+ box-sizing: border-box;
+ }
+ tr {
+ text-align: center;
+ }
+
+ td {
+ .tools_unselectable();
+ border-right: 1px solid @kanban-border-color;
+ padding: 12px;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ &:last-child {
+ border-right: none;
+ }
+ }
+}
+
+div.cp-app-kanban-realtime {
+ display: block;
+ max-height: 100%;
+ max-width: 100%;
+
+ input {
+ &[type="text"] {
+ height: 1em;
+ margin: 0px;
+ }
+ }
+ > textarea {
+ width: 50%;
+ height: 15vh;
+ }
+
+ padding: 0px;
+ margin: 0px;
+
+ .cp-app-kanban-table-scrolled {
+ tr td:last-child {
+ right: 0;
+ }
+ tr td:nth-last-child(2) {
+ right: 100px;
+ }
+ }
+
+ table {
+ border-collapse: collapse;
+ width: ~"calc(100% - 1px)";
+ .cp-app-kanban-table-editing {
+ background-color: @kanban-editing;
+ }
+ .cp-app-kanban-table-uncommitted {
+ .cp-app-kanban-table-cover {
+ background-color: @kanban-uncommitted-cell !important;
+ }
+ div.cp-app-kanban-table-text-cell {
+ background-color: @kanban-uncommitted-bg !important;
+ color: @kanban-uncommitted-text !important;
+ }
+ text-align: center;
+ background-color: @kanban-uncommitted-bg !important;
+ color: @kanban-uncommitted-text !important;
+ }
+ tr {
+ height: 28px;
+ /* Options */
+ td:first-child {
+ position:absolute;
+ left: 0;
+ top: auto;
+ width: 25%;
+ }
+ /* Uncommitted column */
+ td:nth-last-child(2) {
+ position: absolute;
+ top: auto;
+ width: 100px;
+ min-width: unset !important;
+ height: auto !important;
+ }
+ /* Results */
+ td:last-child {
+ color: @kanban-th-fg;
+ position:absolute;
+ top: auto;
+ margin-left: 100px;
+ width: 100px;
+ min-width: unset !important;
+ background-color: @kanban-th-bg;
+ }
+ td {
+ padding: 0px;
+ margin: 0px;
+
+ div.cp-app-kanban-table-text-cell {
+ height: 28px;
+ padding: 0px;
+ margin: 0px;
+ display: flex;
+ align-items: center;
+ .cp-app-kanban-table-remove {
+ order: 1;
+ }
+ .cp-app-kanban-table-edit {
+ order: 3;
+ }
+ input {
+ min-width: 0;
+ order: 2;
+ flex: 1;
+ height: 24px;
+ border: 0px;
+ margin: 2px;
+ &[disabled] {
+ background-color: transparent;
+ color: @kanban-td-fg;
+ //font-weight: bold;
+ }
+ }
+ }
+
+ &.cp-app-kanban-table-checkbox-cell {
+ margin: 0px;
+ padding: 0px;
+ height: 100%;
+ min-width: 100px;
+
+ div.cp-app-kanban-table-checkbox-contain {
+ display: inline-block;
+ height: 100%;
+ width: 100%;
+ position: relative;
+
+ label {
+ background-color: transparent;
+ display: block;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ height: 100%;
+ width: 100%;
+ }
+
+ input {
+ &[type="number"] {
+ &:not(.editable) {
+ display: none;
+
+ ~ .cp-app-kanban-table-cover {
+ line-height: 28px;
+ display: block;
+ font-weight: bold;
+ height: 100%;
+ display: block;
+
+ color: @kanban-cover-color;
+
+ &:after {
+ height: 100%;
+ }
+
+ }
+ }
+ }
+ }
+
+ input[type="number"][value="0"] {
+ ~ .cp-app-kanban-table-cover {
+ background-color: @colortheme_cp-red;
+ &:after { content: "✖"; }
+ }
+ }
+ input[type="number"][value="1"] {
+ ~ .cp-app-kanban-table-cover {
+ background-color: @colortheme_cp-green;
+ &:after { content: "✔"; }
+ }
+ }
+ input[type="number"][value="2"] {
+ ~ .cp-app-kanban-table-cover {
+ background-color: @kanban-option-yellow;
+ &:after { content: "~"; }
+ }
+ }
+ input[type="number"][value="3"] {
+ ~ .cp-app-kanban-table-cover {
+ background-color: @kanban-option-gray;
+ &:after { content: "?"; }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ input {
+ &[type="text"] {
+ height: auto;
+ width: 80%;
+ }
+ }
+ span {
+ .tools_unselectable();
+ }
+ thead {
+ height: 52px;
+ tr {
+ height: 52px;
+ }
+ td {
+ padding: 0px 5px;
+ background: @kanban-th-bg;
+ color: @kanban-th-fg;
+ &:not(:last-child) {
+ border-right: 1px solid rgba(255,255,255,0.2);
+ }
+ &:last-child {
+ height: 52px;
+ line-height: 52px;
+ text-align: center;
+ }
+ &:nth-last-child(2) {
+ border-right: 1px solid @kanban-border-color;
+ }
+ &.cp-app-kanban-table-own {
+ background: @kanban-th-user-bg;
+ .cp-app-kanban-table-lock {
+ cursor: default;
+ }
+ }
+ .cp-app-kanban-table-buttons {
+ display: flex;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ align-items: center;
+ span {
+ cursor: pointer;
+ width: 1em;
+ text-align: center;
+ }
+ .cp-app-kanban-table-bookmark {
+ color: darken(@kanban-th-fg, 30%);
+ &.cp-app-kanban-table-bookmark-full {
+ color: @kanban-th-fg;
+ }
+ }
+ }
+ input {
+ &[type="text"] {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ break-after: always;
+ width: ~"calc(100% - 2px)"; // borders...
+ box-sizing: border-box;
+ padding: 1px 5px;
+ margin: 1px;
+ &[disabled] {
+ color: @kanban-th-fg;
+ }
+ }
+ }
+ }
+ }
+
+ tbody {
+ td:first-child {
+ background: @kanban-td-bg;
+ color: @kanban-td-fg;
+ }
+ td.cp-app-kanban-table-winner {
+ background-color: @kanban-winner;
+ &:last-child { font-weight: bold; }
+ }
+ .cp-app-kanban-table-text-cell {
+ input[type="text"] {
+ width: ~"calc(100% - 50px)";
+ padding: 0 0.5em;
+ }
+ .cp-app-kanban-table-edit {
+ float:right;
+ margin: 2px 10px 0 0;
+ }
+ .cp-app-kanban-table-remove {
+ float: left;
+ margin: 2px 0 0 10px;
+ }
+ }
+ tr:not(:first-child) {
+ td:not(:first-child) {
+ label {
+ border-top: 1px solid @kanban-border-color;
+ }
+ }
+ }
+ }
+ .cp-app-kanban-table-edit {
+ //color: @kanban-cover-color;
+ cursor: pointer;
+ float: left;
+ margin-left: 10px;
+ }
+
+ thead {
+ tr {
+ th {
+ input[type="text"][disabled] {
+ background-color: transparent;
+ color: @kanban-fore;
+ font-weight: bold;
+ }
+ .cp-app-kanban-table-remove {
+ cursor: pointer;
+ font-size: 20px;
+ }
+ }
+ }
+ }
+ tbody {
+ tr {
+ td {
+
+ }
+ }
+ }
+ tfoot {
+ display: none;
+ }
+ }
+ #cp-app-kanban-nocomments {
+ color: #999;
+ text-align: center;
+ margin: 20px;
+ font: @colortheme_app-font;
+ }
+ #cp-app-kanban-comments {
+ width: 50%;
+ margin: 20px auto;
+ min-width: 400px;
+ padding-bottom: 5px;
+ display: none;
+ button {
+ border-radius: 0;
+ }
+ #cp-app-kanban-comments-add {
+ input, textarea {
+ border: 1px solid black;
+ width: 90%;
+ margin: 5px 5%;
+ }
+ input {
+ padding: 5px;
+ height: 26px;
+ &[disabled] {
+ background: #eee;
+ }
+ }
+ textarea {
+ padding: 5px;
+ height: 8em;
+ line-height: 1.5em;
+ }
+ button {
+ padding: 10px;
+ }
+ text-align: center;
+ }
+ #cp-app-kanban-comments-list {
+ .cp-app-kanban-comments-list-el {
+ width: 90%;
+ margin: 5px 5%;
+ }
+ .cp-app-kanban-comments-list-msg {
+ display: flex;
+ background: #eee;
+ padding: 5px 10px;
+ .cp-app-kanban-comments-list-msg-text {
+ flex: 1;
+ white-space: pre-wrap;
+ }
+ .cp-app-kanban-comments-list-msg-actions {
+ button {
+ padding: 0;
+ width: 25px;
+ line-height: 20px;
+ }
+ }
+ }
+ .cp-app-kanban-comments-list-data {
+ background: #ddd;
+ padding: 5px 10px;
+ display: flex;
+ align-items: center;
+ .cp-app-kanban-comments-list-data-name {
+ margin-left: 10px;
+ flex: 1;
+ }
+ .cp-app-kanban-comments-list-data-avatar { .avatar_main(30px); }
+ }
+ }
+ }
+
+ @media screen and (max-width: 500px) {
+ #cp-app-kanban-table-scroll {
+ max-width: 100%;
+ padding: 0;
+ margin: 0;
+ table {
+ tr {
+ td {
+ &:first-child {
+ position: unset;
+ min-width: 100px;
+ &:hover:not(:empty) {
+ position: absolute;
+ min-width: 100px;
+ width: auto;
+ z-index: 100;
+ }
+ }
+ &:nth-last-child(2) {
+ position: unset;
+ }
+ &:last-child {
+ position: unset;
+ }
+ }
+ }
+ }
+ }
+ #cp-app-kanban-comments {
+ min-width: 90%;
+ }
+ }
+}
+
+
+.btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
+
diff --git a/www/kanban/index.html b/www/kanban/index.html
new file mode 100644
index 000000000..e3f7eacc4
--- /dev/null
+++ b/www/kanban/index.html
@@ -0,0 +1,38 @@
+
+
+