mirror of
https://github.com/wekan/wekan.git
synced 2026-11-05 21:44:59 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd0cd64849 | ||
|
|
aab671398c | ||
|
|
d64aeb25d5 | ||
|
|
aa4fa83127 | ||
|
|
81c3dc1d95 | ||
|
|
746eecf3d8 | ||
|
|
cd948fb576 | ||
|
|
4ec4e19e63 | ||
|
|
d88d197de9 | ||
|
|
2a24918a9c | ||
|
|
d2a85b41e4 | ||
|
|
9bcd991a61 | ||
|
|
1a7bd65e59 | ||
|
|
f8ee929cf7 | ||
|
|
734165f3c7 | ||
|
|
8f9ef1bde8 | ||
|
|
2119c6ab0c | ||
|
|
a85479f73c | ||
|
|
21ba0a9606 | ||
|
|
82ba0f9593 | ||
|
|
7769124401 | ||
|
|
d9c978e7fc | ||
|
|
90899f0928 | ||
|
|
f0421da517 | ||
|
|
573d4bf2cb | ||
|
|
f1e1fd3593 | ||
|
|
c387c5bc34 | ||
|
|
0549bc0b0c | ||
|
|
c2a3e11324 | ||
|
|
107e2ac900 | ||
|
|
3b60bdea14 | ||
|
|
f6591d7820 | ||
|
|
6bbd622066 | ||
|
|
ee79cab7b2 | ||
|
|
a0b94065c5 | ||
|
|
e1fa607f87 | ||
|
|
2e91a359f5 | ||
|
|
9720e703fd | ||
|
|
f88898d5b8 | ||
|
|
30c1597b65 | ||
|
|
5bc5171220 | ||
|
|
d0f118e7af | ||
|
|
c481443667 | ||
|
|
b87cff1289 | ||
|
|
0c080830bc | ||
|
|
cdd7d69c66 | ||
|
|
c1cbcdcc72 | ||
|
|
1c84b19f24 | ||
|
|
2c73dae019 | ||
|
|
d285850a04 | ||
|
|
719ef87efc | ||
|
|
039b9abf5e | ||
|
|
39daf56811 | ||
|
|
a8de2f224f | ||
|
|
dda013844c | ||
|
|
3e9481c5bd | ||
|
|
85ac03a892 | ||
|
|
752699d1c2 | ||
|
|
339ca581ab | ||
|
|
20e9cf1144 | ||
|
|
9737884c4b | ||
|
|
2f5670e830 | ||
|
|
108b18cebf | ||
|
|
814ac22a0d | ||
|
|
3814a218c2 | ||
|
|
3fda90612d | ||
|
|
05762aa50c | ||
|
|
9a31371de0 | ||
|
|
b9b7143185 | ||
|
|
972721bdb5 | ||
|
|
3a48982916 | ||
|
|
6b3a6f9f7d | ||
|
|
48fddecb62 | ||
|
|
7f0d1cc5b3 | ||
|
|
70e82be0b4 | ||
|
|
5fc0809844 | ||
|
|
c79990bcd9 | ||
|
|
cd9e7412ea | ||
|
|
3e472606b5 | ||
|
|
2966bc3204 | ||
|
|
5dc6093eec | ||
|
|
86fc60f5ba | ||
|
|
8189a3f9ab | ||
|
|
76a65e2533 | ||
|
|
ad2914934e | ||
|
|
2769ba2874 | ||
|
|
294f1e178e | ||
|
|
c994d34bb8 | ||
|
|
42b5dd0751 | ||
|
|
f884d6d471 | ||
|
|
abe915a8d6 | ||
|
|
a2e8de2fd8 | ||
|
|
e34ca6a8a5 | ||
|
|
596c9de603 | ||
|
|
4170361a1c | ||
|
|
978a36ea77 | ||
|
|
8745ef7de8 | ||
|
|
2ce929b7b3 | ||
|
|
2dcdfa2862 | ||
|
|
b18daac9c9 | ||
|
|
606041a00d | ||
|
|
4ed5952a81 | ||
|
|
37bfce2eb7 | ||
|
|
59541699ce | ||
|
|
af73c16e37 | ||
|
|
673b09b84b | ||
|
|
09f8edfead | ||
|
|
e1ebdeca4f | ||
|
|
31769aa4af | ||
|
|
b32ad86ce7 |
No files matched your search
Vendored
+12
-11
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"editor.tabSize": 2,
|
||||
"editor.rulers": [80],
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.insertFinalNewline": true,
|
||||
"files.exclude": {
|
||||
"**/.git": true,
|
||||
"**/.DS_Store": true,
|
||||
"node_modules": true,
|
||||
".meteor/local": true
|
||||
}
|
||||
}
|
||||
"terminal.integrated.env.linux": {
|
||||
"TERM": "xterm-256color"
|
||||
},
|
||||
"terminal.integrated.env.osx": {
|
||||
"TERM": "xterm-256color"
|
||||
},
|
||||
"terminal.integrated.env.windows": {
|
||||
"TERM": "xterm-256color"
|
||||
},
|
||||
"terminal.integrated.shell.linux": "/bin/bash",
|
||||
"terminal.integrated.shellArgs.linux": ["-l"]
|
||||
}
|
||||
@@ -19,6 +19,97 @@ Fixing other platforms In Progress.
|
||||
|
||||
[Upgrade WeKan](https://wekan.fi/upgrade/)
|
||||
|
||||
# v7.99 2025-10-11 WeKan ® release
|
||||
|
||||
This release fixed the following bugs:
|
||||
|
||||
- [Improve automatic Snap upgrades](https://github.com/wekan/wekan/commit/aab671398c7ee3d7ea4934c6c9c977ad630fa74f).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v7.98 2025-10-11 WeKan ® release
|
||||
|
||||
This release adds the following CRITICAL SECURITY FIXES:
|
||||
|
||||
- [Security Fix: IDOR CWE-639 that affected WeKan 7.80-7.93](https://github.com/wekan/wekan/commit/b87cff1289d2c98ef84d69e171f112ecedb4d843).
|
||||
Thanks to Romain Korpas at apitech.fr and xet7.
|
||||
- [Security Fix: Computational Resource Abuse in Export endpoints](https://github.com/wekan/wekan/commit/d0f118e7af0b2ede517d6d051226c38fa8e557b6).
|
||||
Thanks to Anynymous Security Researcher and xet7.
|
||||
- [Security Fix FG-VD-22-078: Prevent SVG Billion Laughs Attack](https://github.com/wekan/wekan/commit/30c1597b658b0ef50fd2efc56786e8b0f08ac72c).
|
||||
Thanks to Nguyen Thanh Nguyen of Fortinet's FortiGuard Labs and xet7.
|
||||
- [Security Fix usd-2022-0041: CWE-284 Improper Access Control](https://github.com/wekan/wekan/commit/f6591d7820e01075cba93612a5fdbf692fbe49dc).
|
||||
Thanks to Christian Pöschl of usd AG and xet7.
|
||||
- [Security Fix JVN#14269684: Broken access control](https://github.com/wekan/wekan/commit/9720e703fd9432bf0e1bfea2358f8c7ea078f1b1).
|
||||
Thanks to Ryoya Koyama of Mitsui Bussan Secure Directions, Inc and xet7.
|
||||
- [Security Fix JVN#74210258: Stored XSS](https://github.com/wekan/wekan/commit/e1fa607f87d821accb846f2deef1f388003848d1).
|
||||
Thanks to Ryoya Koyama of Mitsui Bussan Secure Directions, Inc and xet7.
|
||||
- [Security Fix JVN#86586539: Stored XSS](https://github.com/wekan/wekan/commit/ee79cab7b27f73fab62a00ec49add73fd6f7bcaa).
|
||||
Thanks to Ryoya Koyama of Mitsui Bussan Secure Directions, Inc and xet7.
|
||||
- [Security Fix JVN#15385465: CWE-79 XSS, that affected WeKan 7.94](https://github.com/wekan/wekan/commit/81c3dc1d956cd7040655940f6569653d7b98fa9a).
|
||||
Thanks to Sho Sugiyama and xet7.
|
||||
- Security Fix JVN#80785288: CWE-79 XSS, that affected WeKan 3.94 and v3.95. This was already previously fixed.
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following new features:
|
||||
|
||||
- [Mobile one board per row. Board zoom size percent. Board toggle mobile/desktop mode. In Progress](https://github.com/wekan/wekan/commit/752699d1c2fb8ea9ff0f3ec9ae0b2b776443d826).
|
||||
Thanks to xet7.
|
||||
- [Drag any files from file manager to minicard or opened card.
|
||||
[Part 1](https://github.com/wekan/wekan/commit/3e9481c5bd2c02ba501bd0a6ef1d1e6ce82bb1d9),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/cdd7d69c660d0b6ac06b7b75d4f59985b8a9322a).
|
||||
Thanks to xet7.
|
||||
- [Use attachments from old CollectionFS database structure, when not yet migrated to Meteor-Files/ostrio-files, without needing to migrate database structure](https://github.com/wekan/wekan/commit/a8de2f224f61d0e5c7061fefb1cdd4f45f3bb020).
|
||||
Thanks to xet7.
|
||||
- [Show console.log 'Legacy attachments route loaded' only when environment variable DEBUG=true](https://github.com/wekan/wekan/commit/1c84b19f246ebe6d3cad4f56726013147756d9c3).
|
||||
Thanks to xet7.
|
||||
- [Make possible for lists to have different names at different swimlanes. Make possible to drag list from one swimlane to another swimlane](https://github.com/wekan/wekan/commit/719ef87efceacfe91461a8eeca7cf74d11f4cc0a).
|
||||
Thanks to xet7.
|
||||
- [Add support for Docker/Compose Secrets for passwords to Docker/Snap/Bundle platforms](https://github.com/wekan/wekan/commit/107e2ac90043138ea8aa09aadd92f4af355289c0).
|
||||
Thanks to Roemer and xet7.
|
||||
- Add Snap automatic upgrades.
|
||||
[Part 1](https://github.com/wekan/wekan/commit/0549bc0b0c7dd4a5db53d645662dd4362ef4d1f3),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/f1e1fd359364dbe6366501ac4f6a150d73509f17).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- Fix DOMPurify paths.
|
||||
[Part 1](https://github.com/wekan/wekan/commit/90899f0928274cbc30ed3d6df0227664efcd2584),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/77691244018f3a1e44c28973b40a363bf77f99b2),
|
||||
[Part 3](https://github.com/wekan/wekan/commit/21ba0a96066a495e885fcf186f026cf1c7ddf45d),
|
||||
[Part 4](https://github.com/wekan/wekan/commit/2119c6ab0c2d76c8a9b22fa712b35b38345fc040).
|
||||
Thanks to xet7.
|
||||
- [Fix sizes of drag handles at desktop mode](https://github.com/wekan/wekan/commit/734165f3c78e9ba9643826da62f78844273f18f6).
|
||||
Thanks to xet7.
|
||||
- [Fixed showing translations always, regardsless of is ROOT_URL set correctly or not](https://github.com/wekan/wekan/commit/1a7bd65e596a4a1030e2686a787186b6d1c61abe).
|
||||
Thanks to xet7.
|
||||
- [Snap: Removed double mongo3 that's already at migratemongo](https://github.com/wekan/wekan/commit/2a24918a9c31e541f4d6424b77cfd76a8d9f2b06).
|
||||
Thanks to xet7.
|
||||
- [Updated release scripts of snapcraft pack command syntax](https://github.com/wekan/wekan/commit/d88d197de964fd71e61ea6c932521f1e5abe7630).
|
||||
Thanks to xet7.
|
||||
- [Try to fix Snap automatic upgrade](https://github.com/wekan/wekan/commit/4ec4e19e637b86b05b11afd076fae09d3698b8de).
|
||||
Thanks to xet7.
|
||||
- [Added missing metadata fields to snapcraft.yaml](https://github.com/wekan/wekan/commit/cd948fb5765efdf5a7d792180a25ffa26bab2730).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v7.97 2025-10-08 WeKan ® release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fixed Collapse button not there when using clearlight board theme](https://github.com/wekan/wekan/pull/5900).
|
||||
Thanks to seve12.
|
||||
- [Fixed translation of "Change Language" at login page](https://github.com/wekan/wekan/commit/9a31371de0e155d3144769f45a1fa216872935eb).
|
||||
Thanks to xet7.
|
||||
- [Some mobile and tablet fixes. Show drag handles at touch screens only. No toggle of drag handles anymore](https://github.com/wekan/wekan/commit/3fda90612d88fc5a8f1e17ae5c399745de06aada).
|
||||
Thanks to xet7.
|
||||
- [Removed white box that appeared when clicking something](https://github.com/wekan/wekan/commit/3814a218c2dab3ed9e8908c3a2de996ffebf6d9d).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v7.96 2025-10-07 WeKan ® release
|
||||
|
||||
This release adds the following updates:
|
||||
|
||||
+9
-4
@@ -66,6 +66,7 @@ ENV \
|
||||
OAUTH2_LOGIN_STYLE=redirect \
|
||||
OAUTH2_CLIENT_ID="" \
|
||||
OAUTH2_SECRET="" \
|
||||
OAUTH2_SECRET_FILE="" \
|
||||
OAUTH2_SERVER_URL="" \
|
||||
OAUTH2_AUTH_ENDPOINT="" \
|
||||
OAUTH2_USERINFO_ENDPOINT="" \
|
||||
@@ -91,6 +92,7 @@ ENV \
|
||||
LDAP_AUTHENTIFICATION=false \
|
||||
LDAP_AUTHENTIFICATION_USERDN="" \
|
||||
LDAP_AUTHENTIFICATION_PASSWORD="" \
|
||||
LDAP_AUTHENTIFICATION_PASSWORD_FILE="" \
|
||||
LDAP_LOG_ENABLED=false \
|
||||
LDAP_BACKGROUND_SYNC=false \
|
||||
LDAP_BACKGROUND_SYNC_INTERVAL="" \
|
||||
@@ -156,7 +158,10 @@ ENV \
|
||||
ORACLE_OIM_ENABLED=false \
|
||||
WAIT_SPINNER="" \
|
||||
WRITABLE_PATH=/data \
|
||||
S3=""
|
||||
S3="" \
|
||||
MAIL_SERVICE_PASSWORD_FILE="" \
|
||||
MONGO_PASSWORD_FILE="" \
|
||||
S3_SECRET_FILE=""
|
||||
|
||||
# NODE_OPTIONS="--max_old_space_size=4096"
|
||||
|
||||
@@ -244,9 +249,9 @@ cd /home/wekan/app
|
||||
# Remove legacy webbroser bundle, so that Wekan works also at Android Firefox, iOS Safari, etc.
|
||||
#rm -rf /home/wekan/app_build/bundle/programs/web.browser.legacy
|
||||
#mv /home/wekan/app_build/bundle /build
|
||||
wget "https://github.com/wekan/wekan/releases/download/v7.96/wekan-7.96-amd64.zip"
|
||||
unzip wekan-7.96-amd64.zip
|
||||
rm wekan-7.96-amd64.zip
|
||||
wget "https://github.com/wekan/wekan/releases/download/v7.99/wekan-7.99-amd64.zip"
|
||||
unzip wekan-7.99-amd64.zip
|
||||
rm wekan-7.99-amd64.zip
|
||||
mv /home/wekan/app/bundle /build
|
||||
|
||||
# Put back the original tar
|
||||
|
||||
+6
-1
@@ -53,7 +53,12 @@ ENV QEMU_ARCHITECTURE=aarch64 \
|
||||
WITH_API=true \
|
||||
PORT=8080 \
|
||||
ROOT_URL=http://localhost \
|
||||
MONGO_URL=mongodb://127.0.0.1:27017/wekan
|
||||
MONGO_URL=mongodb://127.0.0.1:27017/wekan \
|
||||
LDAP_AUTHENTIFICATION_PASSWORD_FILE="" \
|
||||
OAUTH2_SECRET_FILE="" \
|
||||
MAIL_SERVICE_PASSWORD_FILE="" \
|
||||
MONGO_PASSWORD_FILE="" \
|
||||
S3_SECRET_FILE=""
|
||||
|
||||
# Copy qemu-static to image
|
||||
COPY --from=builder qemu-${QEMU_ARCHITECTURE}-static /usr/bin
|
||||
|
||||
+6
-1
@@ -56,7 +56,12 @@ ENV QEMU_ARCHITECTURE=s390x \
|
||||
WITH_API=true \
|
||||
PORT=8080 \
|
||||
ROOT_URL=http://localhost \
|
||||
MONGO_URL=mongodb://127.0.0.1:27017/wekan
|
||||
MONGO_URL=mongodb://127.0.0.1:27017/wekan \
|
||||
LDAP_AUTHENTIFICATION_PASSWORD_FILE="" \
|
||||
OAUTH2_SECRET_FILE="" \
|
||||
MAIL_SERVICE_PASSWORD_FILE="" \
|
||||
MONGO_PASSWORD_FILE="" \
|
||||
S3_SECRET_FILE=""
|
||||
|
||||
# Copy qemu-static to image
|
||||
COPY --from=builder qemu-${QEMU_ARCHITECTURE}-static /usr/bin
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
||||
appVersion: "v7.96.0"
|
||||
appVersion: "v7.99.0"
|
||||
files:
|
||||
userUploads:
|
||||
- README.md
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.activity-title {
|
||||
margin: 0 0.5em 0.8em;
|
||||
margin: 0 0.7vw 1vh;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.reactions-popup .add-comment-reaction {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
font-size: 22px;
|
||||
border-radius: 0.7vw;
|
||||
font-size: clamp(18px, 4vw, 22px);
|
||||
text-align: center;
|
||||
line-height: 30px;
|
||||
width: 40px;
|
||||
line-height: 1.3;
|
||||
width: 5vw;
|
||||
}
|
||||
.reactions-popup .add-comment-reaction:hover {
|
||||
background-color: #b0c4de;
|
||||
@@ -19,13 +19,13 @@
|
||||
clear: both;
|
||||
}
|
||||
.activities .activity {
|
||||
margin: 0.5px 0;
|
||||
padding: 6px 0;
|
||||
margin: 0.1vh 0;
|
||||
padding: 0.8vh 0;
|
||||
display: flex;
|
||||
}
|
||||
.activities .activity .member {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 4vw;
|
||||
height: 4vw;
|
||||
}
|
||||
.activities .activity .activity-member {
|
||||
font-weight: 700;
|
||||
@@ -36,18 +36,18 @@
|
||||
flex: 1;
|
||||
align-self: center;
|
||||
margin: 0;
|
||||
margin-left: 3px;
|
||||
margin-left: 0.4vw;
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
.activities .activity .activity-desc .activity-comment {
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
border-radius: 0.4vw;
|
||||
background: #fff;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
box-shadow: 0 0.2vh 0.3vh rgba(0,0,0,0.2);
|
||||
margin-top: 0.7vh;
|
||||
padding: 0.7vh 0.7vw;
|
||||
}
|
||||
.activities .activity .activity-desc .activity-checklist {
|
||||
display: block;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { sanitizeHTML, sanitizeText } from '/imports/lib/secureDOMPurify';
|
||||
import { TAPi18n } from '/imports/i18n';
|
||||
|
||||
const activitiesPerPage = 500;
|
||||
@@ -216,15 +217,11 @@ BlazeComponent.extendComponent({
|
||||
{
|
||||
href: source.url,
|
||||
},
|
||||
DOMPurify.sanitize(source.system, {
|
||||
ALLOW_UNKNOWN_PROTOCOLS: true,
|
||||
}),
|
||||
sanitizeHTML(source.system),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return DOMPurify.sanitize(source.system, {
|
||||
ALLOW_UNKNOWN_PROTOCOLS: true,
|
||||
});
|
||||
return sanitizeHTML(source.system);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -248,10 +245,10 @@ BlazeComponent.extendComponent({
|
||||
href: `${attachment.link()}?download=true`,
|
||||
target: '_blank',
|
||||
},
|
||||
DOMPurify.sanitize(attachment.name),
|
||||
sanitizeText(attachment.name),
|
||||
),
|
||||
)) ||
|
||||
DOMPurify.sanitize(this.currentData().activity.attachmentName)
|
||||
sanitizeText(this.currentData().activity.attachmentName)
|
||||
);
|
||||
},
|
||||
|
||||
@@ -265,7 +262,7 @@ BlazeComponent.extendComponent({
|
||||
|
||||
Template.activity.helpers({
|
||||
sanitize(value) {
|
||||
return DOMPurify.sanitize(value, { ALLOW_UNKNOWN_PROTOCOLS: true });
|
||||
return sanitizeHTML(value);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -336,7 +333,7 @@ function createCardLink(card, board) {
|
||||
href: card.originRelativeUrl(),
|
||||
class: 'action-card',
|
||||
},
|
||||
DOMPurify.sanitize(text, { ALLOW_UNKNOWN_PROTOCOLS: true }),
|
||||
sanitizeHTML(text),
|
||||
),
|
||||
)
|
||||
);
|
||||
@@ -353,7 +350,7 @@ function createBoardLink(board, list) {
|
||||
href: board.originRelativeUrl(),
|
||||
class: 'action-board',
|
||||
},
|
||||
DOMPurify.sanitize(text, { ALLOW_UNKNOWN_PROTOCOLS: true }),
|
||||
sanitizeHTML(text),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
@@ -6,6 +6,27 @@
|
||||
bottom: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
/* When zoom is 50% or lower, ensure full width like content */
|
||||
.board-wrapper[style*="transform: scale(0.5)"] {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.board-wrapper[style*="transform: scale(0.4)"] {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.board-wrapper[style*="transform: scale(0.3)"] {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
.board-wrapper .board-canvas {
|
||||
position: absolute;
|
||||
@@ -15,6 +36,219 @@
|
||||
bottom: 0;
|
||||
transition: margin 0.1s;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
/* Ensure horizontal scrollbar is visible for high zoom levels */
|
||||
.board-wrapper .board-canvas[style*="overflow-x: auto"] {
|
||||
overflow-x: auto !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
/* Style the scrollbar for better visibility */
|
||||
.board-wrapper .board-canvas::-webkit-scrollbar {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.board-wrapper .board-canvas::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.board-wrapper .board-canvas::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.board-wrapper .board-canvas::-webkit-scrollbar-thumb:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
/* Ensure content area can scroll horizontally for high zoom levels */
|
||||
#content[style*="overflow-x: auto"] {
|
||||
overflow-x: auto !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
/* Style content area scrollbar */
|
||||
#content::-webkit-scrollbar {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
#content::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
#content::-webkit-scrollbar-thumb {
|
||||
background: #888;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
#content::-webkit-scrollbar-thumb:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
/* Ensure scrollbars are always visible for high zoom levels */
|
||||
#content[style*="overflow-x: auto"] {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#content[style*="overflow-x: auto"]::-webkit-scrollbar {
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
/* Force vertical scrollbar to always be visible */
|
||||
#content[style*="overflow-y: auto"] {
|
||||
overflow-y: scroll !important;
|
||||
}
|
||||
|
||||
/* Mobile - make all text 2x bigger inside #content by default (icons stay same size) */
|
||||
@media screen and (max-width: 800px),
|
||||
screen and (max-device-width: 800px),
|
||||
screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 800px),
|
||||
screen and (max-width: 800px) and (orientation: portrait),
|
||||
screen and (max-width: 800px) and (orientation: landscape) {
|
||||
#content {
|
||||
font-size: 2em !important; /* 2x bigger base font size for content area */
|
||||
}
|
||||
|
||||
/* Make all text elements 2x bigger */
|
||||
#content h1, #content h2, #content h3, #content h4, #content h5, #content h6,
|
||||
#content p, #content span, #content div, #content a, #content button,
|
||||
#content .minicard, #content .list-header-name, #content .board-header-btn,
|
||||
#content .card-title, #content .card-details, #content .card-description,
|
||||
#content .swimlane-header, #content .list-title, #content .card-text,
|
||||
#content .member, #content .member-name, #content .member-initials,
|
||||
#content .checklist-item, #content .checklist-title, #content .comment,
|
||||
#content .activity, #content .activity-text, #content .activity-time,
|
||||
#content .board-title, #content .board-description, #content .list-name,
|
||||
#content .card-text, #content .card-title, #content .card-description,
|
||||
#content .swimlane-title, #content .swimlane-description,
|
||||
#content .board-header-title, #content .board-header-description,
|
||||
#content .card-detail-title, #content .card-detail-description,
|
||||
#content .list-header-title, #content .list-header-description,
|
||||
#content .swimlane-header-title, #content .swimlane-header-description,
|
||||
#content .minicard-title, #content .minicard-description,
|
||||
#content .card-comment, #content .card-comment-text,
|
||||
#content .checklist-item-text, #content .checklist-item-title,
|
||||
#content .activity-item, #content .activity-item-text,
|
||||
#content .board-member, #content .board-member-name,
|
||||
#content .team-member, #content .team-member-name,
|
||||
#content .org-member, #content .org-member-name,
|
||||
#content .template-member, #content .template-member-name,
|
||||
#content .user-name, #content .user-email, #content .user-role,
|
||||
#content .setting-title, #content .setting-description,
|
||||
#content .popup-title, #content .popup-description,
|
||||
#content .modal-title, #content .modal-description,
|
||||
#content .notification-title, #content .notification-text,
|
||||
#content .announcement-title, #content .announcement-text,
|
||||
#content .offline-warning-title, #content .offline-warning-text,
|
||||
#content .error-title, #content .error-text,
|
||||
#content .success-title, #content .success-text,
|
||||
#content .info-title, #content .info-text,
|
||||
#content .warning-title, #content .warning-text {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
/* Keep icons the same size (don't scale them) */
|
||||
#content .fa, #content .icon, #content i {
|
||||
font-size: 1em !important; /* Keep original icon size */
|
||||
}
|
||||
|
||||
/* Reset specific icon sizes to prevent double scaling */
|
||||
#content .fa-home, #content .fa-bars, #content .fa-search,
|
||||
#content .fa-bell, #content .fa-user, #content .fa-cog,
|
||||
#content .fa-plus, #content .fa-minus, #content .fa-edit,
|
||||
#content .fa-trash, #content .fa-save, #content .fa-cancel,
|
||||
#content .fa-arrow-left, #content .fa-arrow-right,
|
||||
#content .fa-arrow-up, #content .fa-arrow-down,
|
||||
#content .fa-check, #content .fa-times, #content .fa-close,
|
||||
#content .fa-star, #content .fa-heart, #content .fa-thumbs-up,
|
||||
#content .fa-thumbs-down, #content .fa-comment, #content .fa-reply,
|
||||
#content .fa-share, #content .fa-download, #content .fa-upload,
|
||||
#content .fa-copy, #content .fa-paste, #content .fa-cut,
|
||||
#content .fa-undo, #content .fa-redo, #content .fa-refresh,
|
||||
#content .fa-sync, #content .fa-spinner, #content .fa-loading,
|
||||
#content .fa-info, #content .fa-question, #content .fa-exclamation,
|
||||
#content .fa-warning, #content .fa-error, #content .fa-success,
|
||||
#content .fa-check-circle, #content .fa-times-circle,
|
||||
#content .fa-exclamation-circle, #content .fa-question-circle,
|
||||
#content .fa-info-circle, #content .fa-warning-circle,
|
||||
#content .fa-error-circle, #content .fa-success-circle {
|
||||
font-size: 1em !important; /* Keep original icon size */
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback for iPhone devices using JavaScript detection */
|
||||
.iphone-device #content {
|
||||
font-size: 2em !important; /* 2x bigger base font size for content area */
|
||||
}
|
||||
|
||||
.iphone-device #content h1, .iphone-device #content h2, .iphone-device #content h3, .iphone-device #content h4, .iphone-device #content h5, .iphone-device #content h6,
|
||||
.iphone-device #content p, .iphone-device #content span, .iphone-device #content div, .iphone-device #content a, .iphone-device #content button,
|
||||
.iphone-device #content .minicard, .iphone-device #content .list-header-name, .iphone-device #content .board-header-btn,
|
||||
.iphone-device #content .card-title, .iphone-device #content .card-details, .iphone-device #content .card-description,
|
||||
.iphone-device #content .swimlane-header, .iphone-device #content .list-title, .iphone-device #content .card-text,
|
||||
.iphone-device #content .member, .iphone-device #content .member-name, .iphone-device #content .member-initials,
|
||||
.iphone-device #content .checklist-item, .iphone-device #content .checklist-title, .iphone-device #content .comment,
|
||||
.iphone-device #content .activity, .iphone-device #content .activity-text, .iphone-device #content .activity-time,
|
||||
.iphone-device #content .board-title, .iphone-device #content .board-description, .iphone-device #content .list-name,
|
||||
.iphone-device #content .card-text, .iphone-device #content .card-title, .iphone-device #content .card-description,
|
||||
.iphone-device #content .swimlane-title, .iphone-device #content .swimlane-description,
|
||||
.iphone-device #content .board-header-title, .iphone-device #content .board-header-description,
|
||||
.iphone-device #content .card-detail-title, .iphone-device #content .card-detail-description,
|
||||
.iphone-device #content .list-header-title, .iphone-device #content .list-header-description,
|
||||
.iphone-device #content .swimlane-header-title, .iphone-device #content .swimlane-header-description,
|
||||
.iphone-device #content .minicard-title, .iphone-device #content .minicard-description,
|
||||
.iphone-device #content .card-comment, .iphone-device #content .card-comment-text,
|
||||
.iphone-device #content .checklist-item-text, .iphone-device #content .checklist-item-title,
|
||||
.iphone-device #content .activity-item, .iphone-device #content .activity-item-text,
|
||||
.iphone-device #content .board-member, .iphone-device #content .board-member-name,
|
||||
.iphone-device #content .team-member, .iphone-device #content .team-member-name,
|
||||
.iphone-device #content .org-member, .iphone-device #content .org-member-name,
|
||||
.iphone-device #content .template-member, .iphone-device #content .template-member-name,
|
||||
.iphone-device #content .user-name, .iphone-device #content .user-email, .iphone-device #content .user-role,
|
||||
.iphone-device #content .setting-title, .iphone-device #content .setting-description,
|
||||
.iphone-device #content .popup-title, .iphone-device #content .popup-description,
|
||||
.iphone-device #content .modal-title, .iphone-device #content .modal-description,
|
||||
.iphone-device #content .notification-title, .iphone-device #content .notification-text,
|
||||
.iphone-device #content .announcement-title, .iphone-device #content .announcement-text,
|
||||
.iphone-device #content .offline-warning-title, .iphone-device #content .offline-warning-text,
|
||||
.iphone-device #content .error-title, .iphone-device #content .error-text,
|
||||
.iphone-device #content .success-title, .iphone-device #content .success-text,
|
||||
.iphone-device #content .info-title, .iphone-device #content .info-text,
|
||||
.iphone-device #content .warning-title, .iphone-device #content .warning-text {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
/* Keep icons the same size for iPhone devices */
|
||||
.iphone-device #content .fa, .iphone-device #content .icon, .iphone-device #content i {
|
||||
font-size: 1em !important; /* Keep original icon size */
|
||||
}
|
||||
|
||||
/* Ensure scrollbars are positioned correctly */
|
||||
#content[style*="overflow-x: auto"]::-webkit-scrollbar:vertical {
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
#content[style*="overflow-x: auto"]::-webkit-scrollbar:horizontal {
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
/* Force both scrollbars to always be visible for high zoom levels */
|
||||
#content[style*="overflow-x: auto"][style*="overflow-y: auto"] {
|
||||
overflow-x: scroll !important;
|
||||
overflow-y: scroll !important;
|
||||
}
|
||||
|
||||
/* Ensure the right scrollbar is always visible on the inner right edge */
|
||||
#content[style*="overflow-y: auto"] {
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
.board-wrapper .board-canvas .board-overlay {
|
||||
position: fixed;
|
||||
@@ -33,15 +267,58 @@
|
||||
.board-wrapper .board-canvas.is-dragging-active .minicard-wrapper.is-checked {
|
||||
display: none;
|
||||
}
|
||||
/* Mobile view styles - applied when isMiniScreen is true (iPhone, etc.) */
|
||||
.board-wrapper.mobile-view {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
}
|
||||
|
||||
.board-wrapper.mobile-view .board-canvas {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
}
|
||||
|
||||
.board-wrapper.mobile-view .board-canvas.mobile-view .swimlane {
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.board-wrapper {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
}
|
||||
|
||||
.board-wrapper .board-canvas {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
}
|
||||
|
||||
.board-wrapper .board-canvas .swimlane {
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
padding: 0 0px 0px 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
.calendar-event-green {
|
||||
|
||||
@@ -16,13 +16,14 @@ template(name="boardBody")
|
||||
if notDisplayThisBoard
|
||||
| {{_ 'tableVisibilityMode-allowPrivateOnly'}}
|
||||
else
|
||||
.board-wrapper(class=currentBoard.colorClass)
|
||||
.board-wrapper(class=currentBoard.colorClass class="{{#if isMiniScreen}}mobile-view{{/if}}")
|
||||
.board-canvas.js-swimlanes(
|
||||
class="{{#if hasSwimlanes}}dragscroll{{/if}}"
|
||||
class="{{#if Sidebar.isOpen}}is-sibling-sidebar-open{{/if}}"
|
||||
class="{{#if MultiSelection.isActive}}is-multiselection-active{{/if}}"
|
||||
class="{{#if draggingActive.get}}is-dragging-active{{/if}}"
|
||||
class="{{#unless isVerticalScrollbars}}no-scrollbars{{/unless}}")
|
||||
class="{{#unless isVerticalScrollbars}}no-scrollbars{{/unless}}"
|
||||
class="{{#if isMiniScreen}}mobile-view{{/if}}")
|
||||
if showOverlay.get
|
||||
.board-overlay
|
||||
if currentBoard.isTemplatesBoard
|
||||
|
||||
@@ -76,6 +76,15 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
},
|
||||
onRendered() {
|
||||
// Initialize user settings (zoom and mobile mode)
|
||||
Utils.initializeUserSettings();
|
||||
|
||||
// Detect iPhone devices and add class for better CSS targeting
|
||||
const isIPhone = /iPhone|iPod/.test(navigator.userAgent);
|
||||
if (isIPhone) {
|
||||
document.body.classList.add('iphone-device');
|
||||
}
|
||||
|
||||
// Accessibility: Focus management for popups and menus
|
||||
function focusFirstInteractive(container) {
|
||||
if (!container) return;
|
||||
@@ -192,7 +201,6 @@ BlazeComponent.extendComponent({
|
||||
button:focus, [role="button"]:focus, a:focus, input:focus, select:focus, textarea:focus, .dropdown-menu:focus, .js-board-view-swimlanes:focus, .js-add-card:focus {
|
||||
outline: 3px solid #005fcc !important;
|
||||
outline-offset: 2px !important;
|
||||
background-color: #e6f0ff !important;
|
||||
}
|
||||
/* Input borders */
|
||||
input, textarea, select {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - NEPHRITIS
|
||||
=================*/
|
||||
|
||||
@@ -99,7 +99,7 @@ THEME - NEPHRITIS
|
||||
|
||||
/* === END NEPHRITIS THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Pomegranate
|
||||
=================*/
|
||||
|
||||
@@ -200,7 +200,7 @@ THEME - Pomegranate
|
||||
|
||||
/* === END Pomegranate THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Belize
|
||||
=================*/
|
||||
|
||||
@@ -301,7 +301,7 @@ THEME - Belize
|
||||
|
||||
/* === END Belize THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Wisteria
|
||||
=================*/
|
||||
|
||||
@@ -402,7 +402,7 @@ THEME - Wisteria
|
||||
|
||||
/* === END Wisteria THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Midnight
|
||||
=================*/
|
||||
|
||||
@@ -503,7 +503,7 @@ THEME - Midnight
|
||||
|
||||
/* === END Midnight THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Pumpkin
|
||||
=================*/
|
||||
|
||||
@@ -604,7 +604,7 @@ THEME - Pumpkin
|
||||
|
||||
/* === END Pumpkin THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Moderate Pink
|
||||
=================*/
|
||||
|
||||
@@ -705,7 +705,7 @@ THEME - Moderate Pink
|
||||
|
||||
/* === END Moderatepink THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Strong Cyan
|
||||
=================*/
|
||||
|
||||
@@ -806,7 +806,7 @@ THEME - Strong Cyan
|
||||
|
||||
/* === END Strongcyan THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Lime Green
|
||||
=================*/
|
||||
|
||||
@@ -907,7 +907,7 @@ THEME - Lime Green
|
||||
|
||||
/* === END Limegreen THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Dark
|
||||
=================*/
|
||||
|
||||
@@ -1111,7 +1111,7 @@ THEME - Dark
|
||||
|
||||
/* === END Dark THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Relax
|
||||
=================*/
|
||||
|
||||
@@ -1241,7 +1241,7 @@ THEME - Relax
|
||||
|
||||
/* === END Relax THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Corteza
|
||||
=================*/
|
||||
|
||||
@@ -1342,7 +1342,7 @@ THEME - Corteza
|
||||
|
||||
/* === END Corteza THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Clear Blue
|
||||
=================*/
|
||||
|
||||
@@ -1609,7 +1609,7 @@ THEME - Clear Blue
|
||||
|
||||
/* === END Clearblue THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Natural
|
||||
=================*/
|
||||
|
||||
@@ -1719,7 +1719,7 @@ THEME - Natural
|
||||
|
||||
/* === END Natural THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Modern
|
||||
=================*/
|
||||
|
||||
@@ -2006,7 +2006,7 @@ THEME - Modern
|
||||
|
||||
/* === END Modern THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Modern Dark
|
||||
=================*/
|
||||
|
||||
@@ -2496,7 +2496,7 @@ THEME - Modern Dark
|
||||
/* === END ModernDark THEME === */
|
||||
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Exodark
|
||||
=================*/
|
||||
|
||||
@@ -2744,7 +2744,7 @@ THEME - Exodark
|
||||
|
||||
/* === END Exodark THEME === */
|
||||
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Clean Dark
|
||||
=================*/
|
||||
|
||||
@@ -3183,7 +3183,7 @@ THEME - Clean Dark
|
||||
.board-color-cleandark.background-box {
|
||||
background-color:#23232B;
|
||||
} /*Fixes contrast issues with background box in theme selection list*/
|
||||
/* ===============
|
||||
/* ===============
|
||||
THEME - Clean Light
|
||||
=================*/
|
||||
/* Please note Clean Light theme elements also contain references to some cleandark theme elements so if unable to find code you're looking for under CleanDark it might be here. This should probably be cleaned up*/
|
||||
@@ -3322,7 +3322,13 @@ THEME - Clean Light
|
||||
|
||||
.board-color-cleanlight .list .list-header .list-header-menu .js-collapse,
|
||||
.board-color-cleandark .list .list-header .list-header-menu .js-collapse {
|
||||
display: none;
|
||||
/* Make collapse button visible in Clean Light / Clean Dark themes.
|
||||
Previously this was hidden which caused the missing Collapse button
|
||||
when using these themes. Use inline-block so it lines up with other
|
||||
header controls. */
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.board-color-cleanlight .list-header-add,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.integration-form {
|
||||
padding: 5px;
|
||||
padding: 0.7vh 0.7vw;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.flex,
|
||||
@@ -12,12 +12,928 @@
|
||||
display: flex;
|
||||
}
|
||||
.option {
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
-webkit-border-radius: 0.4vw;
|
||||
border-radius: 0.4vw;
|
||||
background: #fff;
|
||||
text-decoration: none;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
-webkit-box-shadow: 0 0.2vh 0.3vh rgba(0,0,0,0.2);
|
||||
box-shadow: 0 0.2vh 0.3vh rgba(0,0,0,0.2);
|
||||
margin-top: 0.7vh;
|
||||
padding: 0.7vh 0.7vw;
|
||||
}
|
||||
|
||||
/* Zoom and Mobile Mode Controls */
|
||||
.board-header-btns.center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.zoom-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5vw;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 0.5vh 1vw;
|
||||
border-radius: 0.5vw;
|
||||
box-shadow: 0 0.2vh 0.5vh rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn {
|
||||
padding: 0.5vh 0.8vw !important;
|
||||
border-radius: 0.3vw !important;
|
||||
background: #fff !important;
|
||||
border: 1px solid #000 !important;
|
||||
transition: all 0.2s ease !important;
|
||||
color: #000 !important;
|
||||
height: auto !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
float: none !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn i {
|
||||
color: #000 !important;
|
||||
float: none !important;
|
||||
display: inline !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn:hover {
|
||||
background: #000 !important;
|
||||
border-color: #000 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn:hover i {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn.is-active {
|
||||
background: #0079bf;
|
||||
color: white;
|
||||
border-color: #005a8a;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn.is-active i {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.zoom-level {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
min-width: 3vw;
|
||||
text-align: center;
|
||||
font-size: clamp(12px, 2vw, 14px);
|
||||
cursor: pointer;
|
||||
padding: 0.3vh 0.5vw;
|
||||
border-radius: 0.3vw;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.zoom-level:hover {
|
||||
background: #f0f0f0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/* Mobile Mode Styles */
|
||||
.mobile-mode .board-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mobile-mode .board-canvas {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.mobile-mode .minicard {
|
||||
font-size: clamp(16px, 4vw, 20px);
|
||||
padding: 1.2vh 1.5vw 0.5vh;
|
||||
min-height: 3vh;
|
||||
}
|
||||
|
||||
.mobile-mode .list-header-name {
|
||||
font-size: clamp(18px, 4.5vw, 24px);
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btn {
|
||||
padding: 1vh 1.5vw;
|
||||
font-size: clamp(14px, 3.5vw, 18px);
|
||||
}
|
||||
|
||||
.mobile-mode .zoom-controls {
|
||||
padding: 1vh 1.5vw;
|
||||
gap: 1vw;
|
||||
}
|
||||
|
||||
.mobile-mode .zoom-controls .board-header-btn {
|
||||
padding: 1vh 1.5vw !important;
|
||||
font-size: clamp(14px, 3.5vw, 18px) !important;
|
||||
background: #fff !important;
|
||||
border: 1px solid #000 !important;
|
||||
color: #000 !important;
|
||||
height: auto !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
float: none !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.mobile-mode .zoom-controls .board-header-btn i {
|
||||
color: #000 !important;
|
||||
float: none !important;
|
||||
display: inline !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .zoom-controls .board-header-btn:hover {
|
||||
background: #000 !important;
|
||||
border-color: #000 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.mobile-mode .zoom-controls .board-header-btn:hover i {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.mobile-mode .zoom-level {
|
||||
font-size: clamp(14px, 3.5vw, 18px);
|
||||
min-width: 4vw;
|
||||
}
|
||||
|
||||
/* Comprehensive Mobile Mode Styles - Works on all screen sizes */
|
||||
.mobile-mode .board-wrapper {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
transform: none !important;
|
||||
transform-origin: initial !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-canvas {
|
||||
height: 100% !important;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
margin-bottom: 2rem !important;
|
||||
display: block !important;
|
||||
float: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane-header {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
font-size: clamp(18px, 2.5vw, 32px) !important;
|
||||
padding: 1rem !important;
|
||||
margin-bottom: 1rem !important;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
display: block !important;
|
||||
float: none !important;
|
||||
margin-bottom: 2rem !important;
|
||||
border-left: none !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
clear: both !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list-header {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding: 1rem !important;
|
||||
font-size: clamp(18px, 2.5vw, 32px) !important;
|
||||
display: grid !important;
|
||||
grid-template-columns: 30px 1fr auto auto !important;
|
||||
gap: 10px !important;
|
||||
align-items: center !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list-header .list-header-name {
|
||||
font-size: clamp(18px, 2.5vw, 32px) !important;
|
||||
font-weight: bold !important;
|
||||
grid-row: 1 !important;
|
||||
grid-column: 2 !important;
|
||||
align-self: end !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list-header .cardCount {
|
||||
font-size: clamp(14px, 2vw, 24px) !important;
|
||||
grid-row: 2 !important;
|
||||
grid-column: 2 !important;
|
||||
align-self: start !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list-header .list-header-menu-icon {
|
||||
position: static !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
transform: none !important;
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 3 !important;
|
||||
padding: 14px !important;
|
||||
font-size: clamp(24px, 3vw, 48px) !important;
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list-header .list-header-handle {
|
||||
position: static !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
transform: none !important;
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 4 !important;
|
||||
padding: 14px !important;
|
||||
font-size: clamp(28px, 3.5vw, 56px) !important;
|
||||
text-align: center !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list-body {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding: 1rem !important;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.mobile-mode .minicard {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
font-size: clamp(16px, 2vw, 24px) !important;
|
||||
padding: 1.2vh 1.5vw 0.5vh !important;
|
||||
min-height: 3vh !important;
|
||||
margin-bottom: 0.5rem !important;
|
||||
display: block !important;
|
||||
float: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .minicard .minicard-title {
|
||||
font-size: clamp(16px, 2vw, 24px) !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
.mobile-mode .minicard .minicard-members {
|
||||
font-size: clamp(12px, 1.5vw, 18px) !important;
|
||||
}
|
||||
|
||||
.mobile-mode .minicard .minicard-lists {
|
||||
font-size: clamp(12px, 1.5vw, 18px) !important;
|
||||
}
|
||||
|
||||
/* Desktop Mode Styles */
|
||||
.desktop-mode .board-wrapper {
|
||||
width: auto !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.desktop-mode .swimlane {
|
||||
width: auto !important;
|
||||
min-width: auto !important;
|
||||
}
|
||||
|
||||
.desktop-mode .list {
|
||||
width: auto !important;
|
||||
min-width: auto !important;
|
||||
display: flex !important;
|
||||
float: left !important;
|
||||
margin-bottom: 0 !important;
|
||||
border-left: 1px solid #ccc !important;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.desktop-mode .list-header {
|
||||
width: auto !important;
|
||||
min-width: auto !important;
|
||||
padding: 2.5vh 1.5vw 0.5vh !important;
|
||||
font-size: clamp(14px, 3vw, 18px) !important;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.desktop-mode .list-header .list-header-name {
|
||||
font-size: clamp(14px, 3vw, 18px) !important;
|
||||
display: inline !important;
|
||||
grid-row: auto !important;
|
||||
grid-column: auto !important;
|
||||
align-self: auto !important;
|
||||
}
|
||||
|
||||
.desktop-mode .list-header .cardCount {
|
||||
font-size: 12px !important;
|
||||
grid-row: auto !important;
|
||||
grid-column: auto !important;
|
||||
align-self: auto !important;
|
||||
}
|
||||
|
||||
.desktop-mode .list-header .list-header-menu-icon {
|
||||
position: absolute !important;
|
||||
right: 60px !important;
|
||||
top: 50% !important;
|
||||
transform: translateY(-50%) !important;
|
||||
grid-row: auto !important;
|
||||
grid-column: auto !important;
|
||||
padding: 14px !important;
|
||||
font-size: 40px !important;
|
||||
}
|
||||
|
||||
.desktop-mode .list-header .list-header-handle {
|
||||
position: absolute !important;
|
||||
right: 10px !important;
|
||||
top: 50% !important;
|
||||
transform: translateY(-50%) !important;
|
||||
grid-row: auto !important;
|
||||
grid-column: auto !important;
|
||||
padding: 7px !important;
|
||||
font-size: clamp(16px, 3vw, 20px) !important;
|
||||
}
|
||||
|
||||
.desktop-mode .list-body {
|
||||
width: auto !important;
|
||||
min-width: auto !important;
|
||||
padding: 5px 11px !important;
|
||||
}
|
||||
|
||||
.desktop-mode .minicard {
|
||||
width: auto !important;
|
||||
min-width: auto !important;
|
||||
font-size: clamp(12px, 2.5vw, 16px) !important;
|
||||
padding: 0.5vh 0.8vw !important;
|
||||
min-height: auto !important;
|
||||
margin-bottom: 9px !important;
|
||||
}
|
||||
|
||||
.desktop-mode .minicard .minicard-title {
|
||||
font-size: clamp(12px, 2.5vw, 16px) !important;
|
||||
}
|
||||
|
||||
.desktop-mode .minicard .minicard-members {
|
||||
font-size: 10px !important;
|
||||
}
|
||||
|
||||
.desktop-mode .minicard .minicard-lists {
|
||||
font-size: 10px !important;
|
||||
}
|
||||
|
||||
/* Additional Mobile Mode Styles for Other Elements - Works on all screen sizes */
|
||||
.mobile-mode .swimlane-header .swimlane-title {
|
||||
font-size: clamp(18px, 2.5vw, 32px) !important;
|
||||
font-weight: bold !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane-header .swimlane-description {
|
||||
font-size: clamp(14px, 2vw, 24px) !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header {
|
||||
font-size: clamp(18px, 2.5vw, 32px) !important;
|
||||
padding: 1rem !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-title {
|
||||
font-size: clamp(18px, 2.5vw, 32px) !important;
|
||||
font-weight: bold !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-description {
|
||||
font-size: clamp(14px, 2vw, 24px) !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn {
|
||||
font-size: clamp(14px, 2vw, 24px) !important;
|
||||
padding: 1vh 1.5vw !important;
|
||||
display: inline-block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn i {
|
||||
font-size: clamp(14px, 2vw, 24px) !important;
|
||||
display: inline !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
/* Force mobile mode visibility on all screen sizes */
|
||||
.mobile-mode .list-header .fa-angle-right,
|
||||
.mobile-mode .list-header .fa-arrows {
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
opacity: 1 !important;
|
||||
position: static !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list-header .fa-angle-right {
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 3 !important;
|
||||
padding: 14px !important;
|
||||
font-size: clamp(24px, 3vw, 48px) !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list-header .fa-arrows {
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 4 !important;
|
||||
padding: 14px !important;
|
||||
font-size: clamp(28px, 3.5vw, 56px) !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
/* Override any media queries that might hide elements in mobile mode */
|
||||
.mobile-mode * {
|
||||
max-width: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list,
|
||||
.mobile-mode .swimlane,
|
||||
.mobile-mode .board-wrapper,
|
||||
.mobile-mode .board-canvas {
|
||||
max-width: 100% !important;
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
}
|
||||
|
||||
/* Force mobile mode list styling on all screen sizes - override desktop CSS */
|
||||
.mobile-mode .board-canvas {
|
||||
display: block !important;
|
||||
flex-direction: column !important;
|
||||
flex-wrap: nowrap !important;
|
||||
align-items: stretch !important;
|
||||
justify-content: flex-start !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane .swimlane-header {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 0 1rem 0 !important;
|
||||
padding: 1rem !important;
|
||||
font-size: clamp(18px, 2.5vw, 32px) !important;
|
||||
font-weight: bold !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane .lists {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
flex-direction: column !important;
|
||||
flex-wrap: nowrap !important;
|
||||
align-items: stretch !important;
|
||||
justify-content: flex-start !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-top: none !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
flex: none !important;
|
||||
flex-basis: auto !important;
|
||||
flex-grow: 0 !important;
|
||||
flex-shrink: 0 !important;
|
||||
position: static !important;
|
||||
left: auto !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
bottom: auto !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list:first-child {
|
||||
margin-left: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list:last-child {
|
||||
margin-right: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list.ui-sortable-helper {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
height: auto !important;
|
||||
min-height: 60px !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-top: none !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
flex: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list.placeholder {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
height: auto !important;
|
||||
min-height: 60px !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-top: none !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
flex: none !important;
|
||||
}
|
||||
|
||||
/* Override any existing responsive CSS that might interfere with mobile mode */
|
||||
.mobile-mode .board-canvas .swimlane .lists {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
flex-direction: column !important;
|
||||
flex-wrap: nowrap !important;
|
||||
align-items: stretch !important;
|
||||
justify-content: flex-start !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-canvas .swimlane .lists .list {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-top: none !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
flex: none !important;
|
||||
flex-basis: auto !important;
|
||||
flex-grow: 0 !important;
|
||||
flex-shrink: 0 !important;
|
||||
position: static !important;
|
||||
left: auto !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
bottom: auto !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
/* Force mobile mode to override any media query styles */
|
||||
@media screen and (min-width: 801px) {
|
||||
.mobile-mode .board-canvas {
|
||||
display: block !important;
|
||||
flex-direction: column !important;
|
||||
flex-wrap: nowrap !important;
|
||||
align-items: stretch !important;
|
||||
justify-content: flex-start !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane .lists {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
flex-direction: column !important;
|
||||
flex-wrap: nowrap !important;
|
||||
align-items: stretch !important;
|
||||
justify-content: flex-start !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-top: none !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
flex: none !important;
|
||||
flex-basis: auto !important;
|
||||
flex-grow: 0 !important;
|
||||
flex-shrink: 0 !important;
|
||||
position: static !important;
|
||||
left: auto !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
bottom: auto !important;
|
||||
transform: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide desktop-only elements in mobile mode (like mobile media queries do) */
|
||||
.mobile-mode .board-header-btn i.fa + span {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btn span {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btn .fa + span {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btn .fa + .board-header-btn-text {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btn .fa + .board-header-btn-label {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Show only icons in mobile mode */
|
||||
.mobile-mode .board-header-btn {
|
||||
width: auto !important;
|
||||
min-width: auto !important;
|
||||
padding: 8px !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btn i {
|
||||
display: inline-block !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* Hide desktop-specific elements that shouldn't show in mobile mode */
|
||||
.mobile-mode .desktop-only,
|
||||
.mobile-mode .board-header .desktop-only {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn.desktop-only {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hide desktop-specific board header buttons in mobile mode */
|
||||
.mobile-mode .board-header-btns.left {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btns.center {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Show only the right section buttons in mobile mode, but hide text labels */
|
||||
.mobile-mode .board-header-btns.right {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btns.right .board-header-btn span {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btns.right .board-header-btn .fa + span {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btns.right .board-header-btn .fa + .board-header-btn-text {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btns.right .board-header-btn .fa + .board-header-btn-label {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hide specific desktop-only buttons that shouldn't show in mobile mode */
|
||||
.mobile-mode .board-header-btn.js-star-board span,
|
||||
.mobile-mode .board-header-btn.js-change-visibility span,
|
||||
.mobile-mode .board-header-btn.js-watch-board span,
|
||||
.mobile-mode .board-header-btn.js-sort-cards span {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Show only icons for mobile mode buttons */
|
||||
.mobile-mode .board-header-btns.right .board-header-btn {
|
||||
width: auto !important;
|
||||
min-width: auto !important;
|
||||
padding: 8px !important;
|
||||
text-align: center !important;
|
||||
margin: 0 2px !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header-btns.right .board-header-btn i {
|
||||
display: inline-block !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
/* Ensure mobile mode looks like small screen mobile view */
|
||||
.mobile-mode .board-header {
|
||||
height: 40px !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btns {
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn {
|
||||
height: 32px !important;
|
||||
line-height: 32px !important;
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn i.fa {
|
||||
line-height: 32px !important;
|
||||
}
|
||||
|
||||
/* Copy mobile media query styles to mobile mode for consistent appearance */
|
||||
.mobile-mode .board-header {
|
||||
height: 40px !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btns {
|
||||
margin-top: 0px !important;
|
||||
height: 40px !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: flex-end !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn {
|
||||
height: 32px !important;
|
||||
line-height: 32px !important;
|
||||
font-size: 15px !important;
|
||||
margin: 0 2px !important;
|
||||
padding: 4px 8px !important;
|
||||
border-radius: 4px !important;
|
||||
background: rgba(255, 255, 255, 0.1) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2) !important;
|
||||
color: #fff !important;
|
||||
text-decoration: none !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
min-width: 32px !important;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.2) !important;
|
||||
border-color: rgba(255, 255, 255, 0.3) !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn i.fa {
|
||||
line-height: 32px !important;
|
||||
font-size: 15px !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn i.fa + span {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .board-header .board-header-btn span {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hide the board title in mobile mode to match mobile view */
|
||||
.mobile-mode .header-board-menu {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Ensure the board header takes full width in mobile mode */
|
||||
.mobile-mode .board-header {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: space-between !important;
|
||||
padding: 0 10px !important;
|
||||
}
|
||||
|
||||
/* Additional Desktop Mode Styles for Other Elements */
|
||||
.desktop-mode .swimlane-header .swimlane-title {
|
||||
font-size: clamp(14px, 3vw, 18px) !important;
|
||||
}
|
||||
|
||||
.desktop-mode .swimlane-header .swimlane-description {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.desktop-mode .board-header {
|
||||
font-size: clamp(14px, 3vw, 18px) !important;
|
||||
padding: 2.5vh 1.5vw 0.5vh !important;
|
||||
}
|
||||
|
||||
.desktop-mode .board-header .board-header-title {
|
||||
font-size: clamp(14px, 3vw, 18px) !important;
|
||||
}
|
||||
|
||||
.desktop-mode .board-header .board-header-description {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.desktop-mode .board-header .board-header-btn {
|
||||
font-size: clamp(12px, 2.5vw, 16px) !important;
|
||||
padding: 0.5vh 0.8vw !important;
|
||||
}
|
||||
|
||||
.desktop-mode .board-header .board-header-btn i {
|
||||
font-size: clamp(12px, 2.5vw, 16px) !important;
|
||||
}
|
||||
@@ -51,6 +51,8 @@ template(name="boardHeaderBar")
|
||||
i.fa.fa-sign-in
|
||||
span {{_ 'log-in'}}
|
||||
|
||||
.board-header-btns.center
|
||||
|
||||
.board-header-btns.right
|
||||
if currentBoard
|
||||
if isMiniScreen
|
||||
@@ -62,15 +64,11 @@ template(name="boardHeaderBar")
|
||||
a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
|
||||
title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
|
||||
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
|
||||
if showStarCounter
|
||||
span
|
||||
= currentBoard.stars
|
||||
|
||||
a.board-header-btn(
|
||||
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
|
||||
title="{{_ currentBoard.permission}}")
|
||||
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
|
||||
span {{_ currentBoard.permission}}
|
||||
|
||||
a.board-header-btn.js-watch-board(
|
||||
title="{{_ watchLevel }}")
|
||||
@@ -80,10 +78,8 @@ template(name="boardHeaderBar")
|
||||
i.fa.fa-bell
|
||||
if $eq watchLevel "muted"
|
||||
i.fa.fa-bell-slash
|
||||
span {{_ watchLevel}}
|
||||
a.board-header-btn(title="{{_ 'sort-cards'}}" class="{{#if isSortActive }}emphasis{{else}} js-sort-cards {{/if}}")
|
||||
i.fa.fa-sort
|
||||
span {{#if isSortActive }}{{_ 'sort-is-on'}}{{else}}{{_ 'sort-cards'}}{{/if}}
|
||||
if isSortActive
|
||||
a.board-header-btn-close.js-sort-reset(title="{{_ 'remove-sort'}}")
|
||||
i.fa.fa-times-thin
|
||||
@@ -92,13 +88,11 @@ template(name="boardHeaderBar")
|
||||
a.board-header-btn.js-log-in(
|
||||
title="{{_ 'log-in'}}")
|
||||
i.fa.fa-sign-in
|
||||
span {{_ 'log-in'}}
|
||||
|
||||
if isSandstorm
|
||||
if currentUser
|
||||
a.board-header-btn.js-open-archived-board
|
||||
i.fa.fa-archive
|
||||
span {{_ 'archives'}}
|
||||
|
||||
//if showSort
|
||||
// a.board-header-btn.js-open-sort-view(title="{{_ 'sort-desc'}}")
|
||||
@@ -109,14 +103,12 @@ template(name="boardHeaderBar")
|
||||
title="{{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{else}}{{_ 'filter'}}{{/if}}"
|
||||
class="{{#if Filter.isActive}}emphasis{{/if}}")
|
||||
i.fa.fa-filter
|
||||
span {{#if Filter.isActive}}{{_ 'filter-on'}}{{else}}{{_ 'filter'}}{{/if}}
|
||||
if Filter.isActive
|
||||
a.board-header-btn-close.js-filter-reset(title="{{_ 'filter-clear'}}")
|
||||
i.fa.fa-times-thin
|
||||
|
||||
a.board-header-btn.js-open-search-view(title="{{_ 'search'}}")
|
||||
i.fa.fa-search
|
||||
span {{_ 'search'}}
|
||||
|
||||
unless currentBoard.isTemplatesBoard
|
||||
a.board-header-btn.js-toggle-board-view(
|
||||
@@ -128,14 +120,12 @@ template(name="boardHeaderBar")
|
||||
i.fa.fa-trello
|
||||
if $eq boardView 'board-view-cal'
|
||||
i.fa.fa-calendar
|
||||
span {{#if boardView}}{{_ boardView}}{{else}}{{_ 'board-view-swimlanes'}}{{/if}}
|
||||
|
||||
if canModifyBoard
|
||||
a.board-header-btn.js-multiselection-activate(
|
||||
title="{{#if MultiSelection.isActive}}{{_ 'multi-selection-on'}}{{else}}{{_ 'multi-selection'}}{{/if}}"
|
||||
class="{{#if MultiSelection.isActive}}emphasis{{/if}}")
|
||||
i.fa.fa-check-square-o
|
||||
span {{#if MultiSelection.isActive}}{{_ 'multi-selection-on'}}{{else}}{{_ 'multi-selection'}}{{/if}}
|
||||
if MultiSelection.isActive
|
||||
a.board-header-btn-close.js-multiselection-reset(title="{{_ 'filter-clear'}}")
|
||||
i.fa.fa-times-thin
|
||||
|
||||
@@ -33,6 +33,8 @@ BlazeComponent.extendComponent({
|
||||
return currentBoard && currentBoard.getWatchLevel(Meteor.userId());
|
||||
},
|
||||
|
||||
|
||||
|
||||
isStarred() {
|
||||
const boardId = Session.get('currentBoard');
|
||||
const user = ReactiveCache.getCurrentUser();
|
||||
|
||||
@@ -1,5 +1,86 @@
|
||||
@import url("../../../css/reset.css") print, screen;
|
||||
|
||||
/* Board List Header with Zoom Controls */
|
||||
.board-list-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 1vh 0 2vh 0;
|
||||
padding: 1vh 0;
|
||||
}
|
||||
|
||||
.zoom-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5vw;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 0.5vh 1vw;
|
||||
border-radius: 0.5vw;
|
||||
box-shadow: 0 0.2vh 0.5vh rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn {
|
||||
padding: 0.5vh 0.8vw !important;
|
||||
border-radius: 0.3vw !important;
|
||||
background: #fff !important;
|
||||
border: 1px solid #000 !important;
|
||||
transition: all 0.2s ease !important;
|
||||
text-decoration: none !important;
|
||||
color: #000 !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
gap: 0.3vw !important;
|
||||
height: auto !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
float: none !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn i {
|
||||
color: #000 !important;
|
||||
float: none !important;
|
||||
display: inline !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn:hover {
|
||||
background: #000 !important;
|
||||
border-color: #000 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn:hover i {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn.is-active {
|
||||
background: #0079bf;
|
||||
color: white;
|
||||
border-color: #005a8a;
|
||||
}
|
||||
|
||||
.zoom-controls .board-header-btn.is-active i {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.zoom-level {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
min-width: 3vw;
|
||||
text-align: center;
|
||||
font-size: clamp(12px, 2vw, 14px);
|
||||
cursor: pointer;
|
||||
padding: 0.3vh 0.5vw;
|
||||
border-radius: 0.3vw;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.zoom-level:hover {
|
||||
background: #f0f0f0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.board-list {
|
||||
margin: 0 8px;
|
||||
}
|
||||
@@ -192,17 +273,131 @@
|
||||
font-size: 25px;
|
||||
color: #fff;
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
/* Mobile view styles - applied when isMiniScreen is true (iPhone, etc.) */
|
||||
.board-list.mobile-view {
|
||||
height: calc(100vh - 120px);
|
||||
overflow-y: scroll !important;
|
||||
overflow-x: hidden;
|
||||
padding: 0 1rem;
|
||||
margin: 0;
|
||||
scrollbar-width: auto !important;
|
||||
scrollbar-color: #888 #f1f1f1;
|
||||
}
|
||||
.board-list.mobile-view li {
|
||||
width: 100%;
|
||||
float: none;
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
padding-right: 50px; /* Space for drag handle */
|
||||
}
|
||||
.board-list.mobile-view .board-list-item {
|
||||
overflow: visible;
|
||||
height: 8rem;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding-right: 50px; /* Ensure content doesn't overlap with drag handle */
|
||||
}
|
||||
|
||||
.board-list.mobile-view .board-list-item .details {
|
||||
padding-right: 50px; /* Extra space for drag handle */
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.board-list.mobile-view .board-list-item-sub-name {
|
||||
position: relative;
|
||||
top: -100px;
|
||||
left: -100px;
|
||||
}
|
||||
.board-list.mobile-view .board-handle {
|
||||
position: absolute;
|
||||
padding: 7px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 10px;
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
background: rgba(0,0,0,0.3);
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.board-list.mobile-view .board-handle:hover {
|
||||
background: rgba(255, 255, 0, 0.8) !important; /* Yellow hover */
|
||||
}
|
||||
|
||||
/* Force scrollbar to be visible on mobile view */
|
||||
.board-list.mobile-view::-webkit-scrollbar {
|
||||
width: 12px !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.board-list.mobile-view::-webkit-scrollbar-track {
|
||||
background: #f1f1f1 !important;
|
||||
border-radius: 6px !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.board-list.mobile-view::-webkit-scrollbar-thumb {
|
||||
background: #888 !important;
|
||||
border-radius: 6px !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.board-list.mobile-view::-webkit-scrollbar-thumb:hover {
|
||||
background: #555 !important;
|
||||
}
|
||||
|
||||
/* Force mobile view to have scrollable content */
|
||||
.board-list.mobile-view {
|
||||
min-height: 100vh; /* Force content to be tall enough to scroll */
|
||||
}
|
||||
|
||||
.board-list.mobile-view::after {
|
||||
content: '';
|
||||
display: block;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px),
|
||||
screen and (max-device-width: 800px),
|
||||
screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 800px),
|
||||
screen and (max-width: 800px) and (orientation: portrait),
|
||||
screen and (max-width: 800px) and (orientation: landscape) {
|
||||
.board-list {
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 0 1rem;
|
||||
margin: 0;
|
||||
}
|
||||
.board-list li {
|
||||
width: 50%;
|
||||
width: 100%;
|
||||
float: none;
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
padding-right: 50px; /* Space for drag handle */
|
||||
}
|
||||
.board-list .board-list-item {
|
||||
overflow: hidden;
|
||||
overflow: visible;
|
||||
height: 8rem;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding-right: 50px; /* Ensure content doesn't overlap with drag handle */
|
||||
}
|
||||
|
||||
.board-list .board-list-item .details {
|
||||
padding-right: 50px; /* Extra space for drag handle */
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.board-list .board-list-item-sub-name {
|
||||
position: relative;
|
||||
@@ -216,19 +411,296 @@
|
||||
transform: translateY(-50%);
|
||||
right: 10px;
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
background: rgba(0,0,0,0.3);
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.board-list .board-handle:hover {
|
||||
background: rgba(255, 255, 0, 0.8) !important; /* Yellow hover */
|
||||
}
|
||||
}
|
||||
/* Very small screens - ensure one board per row */
|
||||
@media screen and (max-width: 360px) {
|
||||
li {
|
||||
width: 100%;
|
||||
.board-list li {
|
||||
width: 100% !important;
|
||||
float: none !important;
|
||||
display: block !important;
|
||||
}
|
||||
.board-handle {
|
||||
.board-list .board-handle {
|
||||
position: absolute;
|
||||
padding: 7px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 10px;
|
||||
font-size: 24px;
|
||||
color: #fff;
|
||||
background: rgba(0,0,0,0.3);
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile - make all text and icons 2x bigger above #content on All Boards page */
|
||||
@media screen and (max-width: 800px),
|
||||
screen and (max-device-width: 800px),
|
||||
screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 800px),
|
||||
screen and (max-width: 800px) and (orientation: portrait),
|
||||
screen and (max-width: 800px) and (orientation: landscape) {
|
||||
.wrapper {
|
||||
font-size: 2em !important; /* 2x bigger base font size for All Boards page */
|
||||
}
|
||||
|
||||
.wrapper * {
|
||||
font-size: inherit !important; /* Inherit the 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper .fa, .wrapper .icon {
|
||||
font-size: 2em !important; /* 2x bigger icons */
|
||||
}
|
||||
|
||||
.board-list-header {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.board-list-header h1 {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.AllBoardTeamsOrgs {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.AllBoardTeamsOrgs select {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.AllBoardTeamsOrgs input {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.AllBoardTeamsOrgs .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.board-list {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.board-list .board-list-item {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.board-list .board-list-item-name {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.board-list .board-list-item-desc {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.board-list .minicard-members {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.board-list .minicard-lists {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.board-list .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.board-list .board-handle {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback for iPhone devices using JavaScript detection - All Boards page */
|
||||
.iphone-device .wrapper {
|
||||
font-size: 2em !important; /* 2x bigger base font size for All Boards page */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper * {
|
||||
font-size: inherit !important; /* Inherit the 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper .fa, .iphone-device .wrapper .icon {
|
||||
font-size: 2em !important; /* 2x bigger icons */
|
||||
}
|
||||
|
||||
.iphone-device .board-list-header {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .board-list-header h1 {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .AllBoardTeamsOrgs {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .AllBoardTeamsOrgs select {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .AllBoardTeamsOrgs input {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .AllBoardTeamsOrgs .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .board-list {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .board-list .board-list-item {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .board-list .board-list-item-name {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .board-list .board-list-item-desc {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .board-list .minicard-members {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .board-list .minicard-lists {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .board-list .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .board-list .board-handle {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
/* iPhone 12 Mini and very small screens - make everything much larger */
|
||||
@media screen and (max-width: 400px) and (max-height: 900px) {
|
||||
.board-list {
|
||||
height: calc(100vh - 120px) !important;
|
||||
overflow-y: scroll !important;
|
||||
overflow-x: hidden !important;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.board-list li {
|
||||
width: 100% !important;
|
||||
float: none !important;
|
||||
display: block !important;
|
||||
margin-bottom: 1.5rem !important;
|
||||
}
|
||||
|
||||
.board-list .board-list-item {
|
||||
height: 12rem !important; /* Much taller */
|
||||
width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 1rem !important; /* More padding */
|
||||
font-size: 18px !important; /* Much larger text */
|
||||
line-height: 1.4 !important;
|
||||
}
|
||||
|
||||
.board-list .board-list-item .board-list-item-name {
|
||||
font-size: 20px !important; /* Larger board names */
|
||||
font-weight: bold !important;
|
||||
margin-bottom: 0.5rem !important;
|
||||
}
|
||||
|
||||
.board-list .board-list-item .board-list-item-desc {
|
||||
font-size: 16px !important; /* Larger descriptions */
|
||||
line-height: 1.3 !important;
|
||||
}
|
||||
|
||||
.board-list .board-list-item .minicard-members {
|
||||
font-size: 14px !important; /* Larger member avatars */
|
||||
}
|
||||
|
||||
.board-list .board-list-item .minicard-lists {
|
||||
font-size: 14px !important; /* Larger list counters */
|
||||
}
|
||||
|
||||
.board-list .board-handle {
|
||||
position: absolute;
|
||||
padding: 10px !important;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 15px !important;
|
||||
font-size: 28px !important; /* Much larger drag handle */
|
||||
color: #fff;
|
||||
background: rgba(0,0,0,0.4) !important;
|
||||
border-radius: 50%;
|
||||
width: 50px !important; /* Larger handle */
|
||||
height: 50px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.board-list .board-handle:hover {
|
||||
background: rgba(255, 255, 0, 0.8) !important; /* Yellow hover */
|
||||
}
|
||||
|
||||
/* Force scrollbar to be visible and larger */
|
||||
.board-list::-webkit-scrollbar {
|
||||
width: 16px !important; /* Much wider scrollbar */
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.board-list::-webkit-scrollbar-track {
|
||||
background: #f1f1f1 !important;
|
||||
border-radius: 8px !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.board-list::-webkit-scrollbar-thumb {
|
||||
background: #666 !important; /* Darker for better visibility */
|
||||
border-radius: 8px !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
min-height: 50px !important; /* Minimum thumb size */
|
||||
}
|
||||
|
||||
.board-list::-webkit-scrollbar-thumb:hover {
|
||||
background: #333 !important;
|
||||
}
|
||||
|
||||
/* Ensure scrollbar is always visible */
|
||||
.board-list {
|
||||
scrollbar-gutter: stable;
|
||||
scrollbar-width: auto !important;
|
||||
min-height: 100vh !important;
|
||||
}
|
||||
|
||||
.board-list::after {
|
||||
content: '';
|
||||
display: block;
|
||||
height: 200px !important; /* More space to ensure scrolling */
|
||||
}
|
||||
}
|
||||
.AllBoardTeamsOrgs {
|
||||
@@ -279,3 +751,78 @@
|
||||
padding-right: 6px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Fix multiple scrollbars issue on mobile */
|
||||
@media screen and (max-width: 800px),
|
||||
screen and (max-device-width: 800px),
|
||||
screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 800px),
|
||||
screen and (max-width: 800px) and (orientation: portrait),
|
||||
screen and (max-width: 800px) and (orientation: landscape) {
|
||||
.wrapper {
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.board-list {
|
||||
overflow-y: scroll !important;
|
||||
overflow-x: hidden !important;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #888 #f1f1f1;
|
||||
height: calc(100vh - 120px); /* Ensure there's content to scroll */
|
||||
}
|
||||
|
||||
/* Force scrollbar to always be visible */
|
||||
.board-list::-webkit-scrollbar {
|
||||
width: 12px !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.board-list::-webkit-scrollbar-track {
|
||||
background: #f1f1f1 !important;
|
||||
border-radius: 6px !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.board-list::-webkit-scrollbar-thumb {
|
||||
background: #888 !important;
|
||||
border-radius: 6px !important;
|
||||
display: block !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.board-list::-webkit-scrollbar-thumb:hover {
|
||||
background: #555 !important;
|
||||
}
|
||||
|
||||
/* Ensure scrollbar is always visible */
|
||||
.board-list::-webkit-scrollbar-corner {
|
||||
background: #f1f1f1 !important;
|
||||
}
|
||||
|
||||
/* Force scrollbar to be visible */
|
||||
.board-list {
|
||||
scrollbar-gutter: stable;
|
||||
scrollbar-width: auto !important;
|
||||
min-height: 100vh; /* Force content to be tall enough to scroll */
|
||||
}
|
||||
|
||||
/* Ensure there's always content to scroll */
|
||||
.board-list::after {
|
||||
content: '';
|
||||
display: block;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
/* Ensure only one scrollbar is visible */
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#content {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
template(name="boardList")
|
||||
.wrapper
|
||||
.board-list-header
|
||||
|
||||
ul.AllBoardTeamsOrgs
|
||||
li.AllBoardTeams
|
||||
if userHasTeams
|
||||
@@ -29,7 +31,7 @@ template(name="boardList")
|
||||
input#filterBtn(type="button" value="{{_ 'filter'}}")
|
||||
input#resetBtn(type="button" value="{{_ 'filter-clear'}}")
|
||||
|
||||
ul.board-list.clearfix.js-boards
|
||||
ul.board-list.clearfix.js-boards(class="{{#if isMiniScreen}}mobile-view{{/if}}")
|
||||
li.js-add-board
|
||||
a.board-list-item.label(title="{{_ 'add-board'}}")
|
||||
| {{_ 'add-board'}}
|
||||
|
||||
@@ -22,6 +22,9 @@ Template.boardListHeaderBar.events({
|
||||
},
|
||||
});
|
||||
|
||||
Template.boardList.events({
|
||||
});
|
||||
|
||||
Template.boardListHeaderBar.helpers({
|
||||
title() {
|
||||
//if (FlowRouter.getRouteName() === 'template-container') {
|
||||
|
||||
@@ -106,6 +106,142 @@
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
font-size: 4em;
|
||||
}
|
||||
|
||||
/* Upload progress indicators for drag-and-drop uploads */
|
||||
.minicard-upload-progress,
|
||||
.card-details-upload-progress {
|
||||
background: #f8f9fa;
|
||||
border: 1px solid #e9ecef;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
margin: 8px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.upload-progress-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
font-weight: bold;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.upload-progress-header i {
|
||||
margin-right: 8px;
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.upload-progress-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
background: white;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.upload-progress-item.upload-error {
|
||||
border-color: #dc3545;
|
||||
background: #f8d7da;
|
||||
}
|
||||
|
||||
.upload-progress-filename {
|
||||
font-weight: 500;
|
||||
margin-bottom: 4px;
|
||||
color: #495057;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.upload-progress-bar {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
background: #e9ecef;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.upload-progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #007bff, #0056b3);
|
||||
transition: width 0.3s ease;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.upload-progress-item.upload-error .upload-progress-fill {
|
||||
background: #dc3545;
|
||||
}
|
||||
|
||||
.upload-progress-error,
|
||||
.upload-progress-success {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.upload-progress-error {
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
.upload-progress-success {
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.upload-progress-error i,
|
||||
.upload-progress-success i {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
/* Minicard specific styles */
|
||||
.minicard-upload-progress {
|
||||
margin: 4px 0;
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.minicard-upload-progress .upload-progress-item {
|
||||
padding: 6px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.minicard-upload-progress .upload-progress-filename {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
/* Card details specific styles */
|
||||
.card-details-upload-progress {
|
||||
margin: 12px 0;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.card-details-upload-progress .upload-progress-header {
|
||||
font-size: 16px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.card-details-upload-progress .upload-progress-item {
|
||||
padding: 12px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.card-details-upload-progress .upload-progress-filename {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Drag over state for minicards */
|
||||
.minicard.is-dragging-over {
|
||||
border: 2px dashed #007bff !important;
|
||||
background: rgba(0, 123, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Drag over state for card details */
|
||||
.js-card-details.is-dragging-over {
|
||||
border: 2px dashed #007bff !important;
|
||||
background: rgba(0, 123, 255, 0.05) !important;
|
||||
}
|
||||
top: 0;
|
||||
right: 8px;
|
||||
position: absolute;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
import { ObjectID } from 'bson';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { sanitizeHTML, sanitizeText } from '/imports/lib/secureDOMPurify';
|
||||
import uploadProgressManager from '../../lib/uploadProgressManager';
|
||||
|
||||
const filesize = require('filesize');
|
||||
const prettyMilliseconds = require('pretty-ms');
|
||||
@@ -268,7 +270,7 @@ Template.attachmentGallery.helpers({
|
||||
return ret;
|
||||
},
|
||||
sanitize(value) {
|
||||
return DOMPurify.sanitize(value);
|
||||
return sanitizeHTML(value);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -296,44 +298,13 @@ Template.cardAttachmentsPopup.events({
|
||||
const files = event.currentTarget.files;
|
||||
if (files) {
|
||||
let uploads = [];
|
||||
for (const file of files) {
|
||||
const fileId = new ObjectID().toString();
|
||||
let fileName = DOMPurify.sanitize(file.name);
|
||||
const uploaders = handleFileUpload(card, files);
|
||||
|
||||
// If sanitized filename is not same as original filename,
|
||||
// it could be XSS that is already fixed with sanitize,
|
||||
// or just normal mistake, so it is not a problem.
|
||||
// That is why here is no warning.
|
||||
if (fileName !== file.name) {
|
||||
// If filename is empty, only in that case add some filename
|
||||
if (fileName.length === 0) {
|
||||
fileName = 'Empty-filename-after-sanitize.txt';
|
||||
}
|
||||
}
|
||||
|
||||
const config = {
|
||||
file: file,
|
||||
fileId: fileId,
|
||||
fileName: fileName,
|
||||
meta: Utils.getCommonAttachmentMetaFrom(card),
|
||||
chunkSize: 'dynamic',
|
||||
};
|
||||
config.meta.fileId = fileId;
|
||||
const uploader = Attachments.insert(
|
||||
config,
|
||||
false,
|
||||
);
|
||||
uploaders.forEach(uploader => {
|
||||
uploader.on('start', function() {
|
||||
uploads.push(this);
|
||||
templateInstance.uploads.set(uploads);
|
||||
});
|
||||
uploader.on('uploaded', (error, fileRef) => {
|
||||
if (!error) {
|
||||
if (fileRef.isImage) {
|
||||
card.setCover(fileRef._id);
|
||||
}
|
||||
}
|
||||
});
|
||||
uploader.on('end', (error, fileRef) => {
|
||||
uploads = uploads.filter(_upload => _upload.config.fileId != fileRef._id);
|
||||
templateInstance.uploads.set(uploads);
|
||||
@@ -341,8 +312,7 @@ Template.cardAttachmentsPopup.events({
|
||||
Popup.back();
|
||||
}
|
||||
});
|
||||
uploader.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-computer-upload'(event, templateInstance) {
|
||||
@@ -356,6 +326,105 @@ const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
|
||||
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
|
||||
let pastedResults = null;
|
||||
|
||||
// Shared upload logic for drag-and-drop functionality
|
||||
export function handleFileUpload(card, files) {
|
||||
if (!files || files.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Check if board allows attachments
|
||||
const board = card.board();
|
||||
if (!board || !board.allowsAttachments) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Attachments not allowed on this board');
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// Check if user can modify the card
|
||||
if (!card.canModifyCard()) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('User does not have permission to modify this card');
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
const uploads = [];
|
||||
|
||||
for (const file of files) {
|
||||
// Basic file validation
|
||||
if (!file || !file.name) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Invalid file object');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const fileId = new ObjectID().toString();
|
||||
let fileName = sanitizeText(file.name);
|
||||
|
||||
// If sanitized filename is not same as original filename,
|
||||
// it could be XSS that is already fixed with sanitize,
|
||||
// or just normal mistake, so it is not a problem.
|
||||
// That is why here is no warning.
|
||||
if (fileName !== file.name) {
|
||||
// If filename is empty, only in that case add some filename
|
||||
if (fileName.length === 0) {
|
||||
fileName = 'Empty-filename-after-sanitize.txt';
|
||||
}
|
||||
}
|
||||
|
||||
const config = {
|
||||
file: file,
|
||||
fileId: fileId,
|
||||
fileName: fileName,
|
||||
meta: Utils.getCommonAttachmentMetaFrom(card),
|
||||
chunkSize: 'dynamic',
|
||||
};
|
||||
config.meta.fileId = fileId;
|
||||
|
||||
try {
|
||||
const uploader = Attachments.insert(
|
||||
config,
|
||||
false,
|
||||
);
|
||||
|
||||
// Add to progress manager for tracking
|
||||
const uploadId = uploadProgressManager.addUpload(card._id, uploader, file);
|
||||
|
||||
uploader.on('uploaded', (error, fileRef) => {
|
||||
if (!error) {
|
||||
if (fileRef.isImage) {
|
||||
card.setCover(fileRef._id);
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`Set cover image for card ${card._id}: ${fileRef.name}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.error('Upload error:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
uploader.on('error', (error) => {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.error('Upload error:', error);
|
||||
}
|
||||
});
|
||||
|
||||
uploads.push(uploader);
|
||||
uploader.start();
|
||||
} catch (error) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.error('Failed to create uploader:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return uploads;
|
||||
}
|
||||
|
||||
Template.previewClipboardImagePopup.onRendered(() => {
|
||||
// we can paste image from clipboard
|
||||
const handle = results => {
|
||||
@@ -498,7 +567,7 @@ BlazeComponent.extendComponent({
|
||||
const name = this.$('.js-edit-attachment-name')[0]
|
||||
.value
|
||||
.trim() + this.data().extensionWithDot;
|
||||
if (name === DOMPurify.sanitize(name)) {
|
||||
if (name === sanitizeText(name)) {
|
||||
Meteor.call('renameAttachment', this.data()._id, name);
|
||||
}
|
||||
Popup.back();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
.assignee {
|
||||
border-radius: 3px;
|
||||
border-radius: 0.4vw;
|
||||
display: block;
|
||||
position: relative;
|
||||
float: left;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
margin: .3vh;
|
||||
height: 4vw;
|
||||
width: 4vw;
|
||||
margin: 0.4vh;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
z-index: 1;
|
||||
@@ -34,11 +34,11 @@
|
||||
background-color: #b3b3b3;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 50%;
|
||||
height: 7px;
|
||||
width: 7px;
|
||||
height: 1vw;
|
||||
width: 1vw;
|
||||
position: absolute;
|
||||
right: -1px;
|
||||
bottom: -1px;
|
||||
right: -0.1vw;
|
||||
bottom: -0.1vw;
|
||||
border: 1px solid #fff;
|
||||
z-index: 15;
|
||||
}
|
||||
@@ -70,23 +70,23 @@
|
||||
}
|
||||
.copied-tooltip {
|
||||
display: none;
|
||||
padding: 0px 10px;
|
||||
padding: 0 1.3vw;
|
||||
background-color: rgba(0,0,0,0.875);
|
||||
color: #fff;
|
||||
border-radius: 5px;
|
||||
border-radius: 0.7vw;
|
||||
}
|
||||
.card-details {
|
||||
padding: 0;
|
||||
flex-shrink: 0;
|
||||
flex-basis: 600px;
|
||||
flex-basis: min(600px, 80vw);
|
||||
will-change: flex-basis;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
background: #f7f7f7;
|
||||
border-radius: bottom 3px;
|
||||
border-radius: bottom 0.4vw;
|
||||
z-index: 30;
|
||||
animation: flexGrowIn 0.1s;
|
||||
box-shadow: 0 0 7px 0 #b3b3b3;
|
||||
box-shadow: 0 0 0.9vh 0 #b3b3b3;
|
||||
transition: flex-basis 0.1s;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -95,7 +95,7 @@
|
||||
}
|
||||
.card-details .card-details-canvas {
|
||||
width: auto;
|
||||
padding: 0 20px;
|
||||
padding: 0 2.5vw;
|
||||
}
|
||||
.card-details .card-details-header {
|
||||
margin: 0 -20px 5px;
|
||||
@@ -596,3 +596,11 @@ input[type="submit"].attachment-add-link-submit {
|
||||
overflow: hidden;
|
||||
background-color: #cecece;
|
||||
}
|
||||
|
||||
/* Drag and drop file upload visual feedback */
|
||||
.js-card-details.is-dragging-over {
|
||||
border: 2px dashed #0079bf;
|
||||
background-color: #e3f2fd !important;
|
||||
transform: scale(1.01);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
@@ -65,6 +65,26 @@ template(name="cardDetails")
|
||||
else
|
||||
p.warning {{_ 'card-archived'}}
|
||||
|
||||
// Upload progress indicator for drag-and-drop uploads
|
||||
if hasActiveUploads
|
||||
.card-details-upload-progress
|
||||
.upload-progress-header
|
||||
i.fa.fa-upload
|
||||
span {{_ 'uploading-files'}} ({{uploadCount}})
|
||||
each uploads
|
||||
.upload-progress-item(class="{{#if $eq status 'error'}}upload-error{{/if}}")
|
||||
.upload-progress-filename {{file.name}}
|
||||
.upload-progress-bar
|
||||
.upload-progress-fill(style="width: {{progress}}%")
|
||||
if $eq status 'error'
|
||||
.upload-progress-error
|
||||
i.fa.fa-exclamation-triangle
|
||||
span {{_ 'upload-failed'}}
|
||||
else if $eq status 'completed'
|
||||
.upload-progress-success
|
||||
i.fa.fa-check
|
||||
span {{_ 'upload-completed'}}
|
||||
|
||||
.card-details-left
|
||||
|
||||
.card-details-items
|
||||
|
||||
@@ -12,6 +12,8 @@ import CardComments from '/models/cardComments';
|
||||
import { ALLOWED_COLORS } from '/config/const';
|
||||
import { UserAvatar } from '../users/userAvatar';
|
||||
import { DialogWithBoardSwimlaneList } from '/client/lib/dialogWithBoardSwimlaneList';
|
||||
import { handleFileUpload } from './attachments';
|
||||
import uploadProgressManager from '../../lib/uploadProgressManager';
|
||||
|
||||
const subManager = new SubsManager();
|
||||
const { calculateIndexData } = Utils;
|
||||
@@ -481,6 +483,59 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
}
|
||||
},
|
||||
// Drag and drop file upload handlers
|
||||
'dragover .js-card-details'(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
},
|
||||
'dragenter .js-card-details'(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const card = this.data();
|
||||
const board = card.board();
|
||||
// Only allow drag-and-drop if user can modify card and board allows attachments
|
||||
if (card.canModifyCard() && board && board.allowsAttachments) {
|
||||
// Check if the drag contains files
|
||||
const dataTransfer = event.originalEvent.dataTransfer;
|
||||
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||
$(event.currentTarget).addClass('is-dragging-over');
|
||||
}
|
||||
}
|
||||
},
|
||||
'dragleave .js-card-details'(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$(event.currentTarget).removeClass('is-dragging-over');
|
||||
},
|
||||
'drop .js-card-details'(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$(event.currentTarget).removeClass('is-dragging-over');
|
||||
|
||||
const card = this.data();
|
||||
const board = card.board();
|
||||
|
||||
// Check permissions
|
||||
if (!card.canModifyCard() || !board || !board.allowsAttachments) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a file drop (not a checklist item reorder)
|
||||
const dataTransfer = event.originalEvent.dataTransfer;
|
||||
if (!dataTransfer || !dataTransfer.files || dataTransfer.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the drop contains files (not just text/HTML)
|
||||
if (!dataTransfer.types.includes('Files')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const files = dataTransfer.files;
|
||||
if (files && files.length > 0) {
|
||||
handleFileUpload(card, files);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
@@ -490,6 +545,16 @@ Template.cardDetails.helpers({
|
||||
isPopup() {
|
||||
let ret = !!Utils.getPopupCardId();
|
||||
return ret;
|
||||
},
|
||||
// Upload progress helpers
|
||||
hasActiveUploads() {
|
||||
return uploadProgressManager.hasActiveUploads(this._id);
|
||||
},
|
||||
uploads() {
|
||||
return uploadProgressManager.getUploadsForCard(this._id);
|
||||
},
|
||||
uploadCount() {
|
||||
return uploadProgressManager.getUploadCountForCard(this._id);
|
||||
}
|
||||
});
|
||||
Template.cardDetailsPopup.onDestroyed(() => {
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 9px;
|
||||
margin-bottom: 1.2vh;
|
||||
}
|
||||
.minicard-wrapper.placeholder {
|
||||
background: #ccc;
|
||||
border-radius: 9px;
|
||||
border-radius: 1.2vw;
|
||||
}
|
||||
.minicard-wrapper.ui-sortable-helper {
|
||||
cursor: grabbing;
|
||||
@@ -16,28 +16,28 @@
|
||||
}
|
||||
.minicard-wrapper.ui-sortable-helper .and-n-other {
|
||||
width: 100%;
|
||||
height: 16px;
|
||||
padding: 4px;
|
||||
height: 2.5vh;
|
||||
padding: 0.5vh;
|
||||
background-color: #f2f2f2;
|
||||
text-align: center;
|
||||
border-radius: 3px;
|
||||
border-radius: 0.4vw;
|
||||
}
|
||||
.minicard-wrapper.ui-sortable-helper .multi-selection-checkbox {
|
||||
display: none;
|
||||
}
|
||||
.minicard-wrapper .multi-selection-checkbox + .minicard {
|
||||
margin-left: 8px;
|
||||
margin-left: 1vw;
|
||||
}
|
||||
@media only screen {
|
||||
.minicard {
|
||||
padding: 6px 8px 2px;
|
||||
padding: 0.8vh 1vw 0.3vh;
|
||||
position: relative;
|
||||
flex: 1;
|
||||
flex-wrap: wrap;
|
||||
background-color: #fff;
|
||||
min-height: 20px;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
|
||||
border-radius: 2px;
|
||||
min-height: 2.5vh;
|
||||
box-shadow: 0 0.2vh 0.3vh rgba(0,0,0,0.15);
|
||||
border-radius: 0.3vw;
|
||||
color: #4d4d4d;
|
||||
overflow: hidden;
|
||||
transition: transform 0.2s, border-radius 0.2s;
|
||||
@@ -45,14 +45,14 @@
|
||||
}
|
||||
.minicard-details-menu-with-handle {
|
||||
float: right;
|
||||
font-size: 18px;
|
||||
padding-right: 30px;
|
||||
padding-left: 5px;
|
||||
font-size: clamp(14px, 3vw, 18px);
|
||||
padding-right: 4vw;
|
||||
padding-left: 0.7vw;
|
||||
}
|
||||
.minicard-details-menu {
|
||||
float: right;
|
||||
font-size: 18px;
|
||||
padding-left: 5px;
|
||||
font-size: clamp(14px, 3vw, 18px);
|
||||
padding-left: 0.7vw;
|
||||
}
|
||||
@media print {
|
||||
.minicard-details-menu,
|
||||
@@ -63,7 +63,7 @@
|
||||
.minicard.linked-board .linked-icon,
|
||||
.minicard.linked-card .linked-icon {
|
||||
display: inline-block;
|
||||
margin-right: 11px;
|
||||
margin-right: 1.5vw;
|
||||
vertical-align: baseline;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
@@ -72,11 +72,11 @@
|
||||
color: #937760;
|
||||
}
|
||||
.is-selected .minicard {
|
||||
transform: translateX(11px);
|
||||
transform: translateX(1.5vw);
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-right-radius: 0;
|
||||
z-index: 25;
|
||||
box-shadow: -2px 1px 2px rgba(0,0,0,0.2);
|
||||
box-shadow: -0.3vw 0.2vh 0.3vh rgba(0,0,0,0.2);
|
||||
}
|
||||
.minicard:hover:not(.minicard-composer),
|
||||
.is-selected .minicard,
|
||||
@@ -90,20 +90,20 @@
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
height: 145px;
|
||||
height: 20vh;
|
||||
user-select: none;
|
||||
margin: 6px -8px 6px -8px;
|
||||
border-radius: top 2px;
|
||||
margin: 0.8vh -1vw 0.8vh -1vw;
|
||||
border-radius: top 0.3vw;
|
||||
}
|
||||
.minicard .minicard-labels {
|
||||
float: none;
|
||||
}
|
||||
.minicard .minicard-labels .minicard-label {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 2px;
|
||||
margin-right: 3px;
|
||||
margin-bottom: 3px;
|
||||
width: 1.5vw;
|
||||
height: 1.5vw;
|
||||
border-radius: 0.3vw;
|
||||
margin-right: 0.4vw;
|
||||
margin-bottom: 0.4vh;
|
||||
}
|
||||
.minicard .minicard-labels-no-text {
|
||||
display: flex;
|
||||
@@ -119,22 +119,22 @@
|
||||
flex-grow: 1;
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
max-width: 100px;
|
||||
margin-right: 4px;
|
||||
max-width: 13vw;
|
||||
margin-right: 0.5vw;
|
||||
}
|
||||
.minicard .minicard-custom-field-item-fullwidth {
|
||||
flex-grow: 1;
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
max-width: 100%;
|
||||
margin-right: 4px;
|
||||
margin-right: 0.5vw;
|
||||
}
|
||||
.minicard .handle {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
width: 2.5vw;
|
||||
height: 2.5vw;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
right: 0.7vw;
|
||||
top: 0.7vh;
|
||||
display: none;
|
||||
}
|
||||
@media only screen {
|
||||
@@ -143,13 +143,13 @@
|
||||
}
|
||||
}
|
||||
.minicard .handle .fa-arrows {
|
||||
font-size: 20px;
|
||||
font-size: clamp(16px, 3vw, 20px);
|
||||
color: #ccc;
|
||||
}
|
||||
.minicard .minicard-title .card-number {
|
||||
color: #b3b3b3;
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
margin-right: 0.7vw;
|
||||
}
|
||||
@media only screen {
|
||||
.minicard .minicard-title p:last-child {
|
||||
@@ -166,11 +166,11 @@
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.minicard .date {
|
||||
margin-right: 3px;
|
||||
margin-right: 0.4vw;
|
||||
}
|
||||
.minicard .badges {
|
||||
float: left;
|
||||
margin-top: 7px;
|
||||
margin-top: 1vh;
|
||||
color: #808080;
|
||||
}
|
||||
.minicard .badges:empty {
|
||||
@@ -178,14 +178,14 @@
|
||||
}
|
||||
.minicard .badges .badge {
|
||||
float: left;
|
||||
margin-right: 11px;
|
||||
margin-bottom: 3px;
|
||||
margin-right: 1.5vw;
|
||||
margin-bottom: 0.4vh;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.minicard .badges .badge.is-finished {
|
||||
background: #3cb500;
|
||||
padding: 0px 3px;
|
||||
border-radius: 3px;
|
||||
padding: 0 0.4vw;
|
||||
border-radius: 0.4vw;
|
||||
color: #fff;
|
||||
}
|
||||
.minicard .badges .badge:last-of-type {
|
||||
@@ -201,41 +201,41 @@
|
||||
}
|
||||
.minicard .badges .badge .badge-text {
|
||||
font-size: 0.9em;
|
||||
padding-left: 2px;
|
||||
line-height: 14px;
|
||||
padding-left: 0.3vw;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.minicard .badges .badge .check-list-text {
|
||||
padding-left: 0px;
|
||||
line-height: 12px;
|
||||
line-height: 1.1;
|
||||
}
|
||||
.minicard .minicard-members,
|
||||
.minicard .minicard-assignees,
|
||||
.minicard .minicard-creator {
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
margin-bottom: 4px;
|
||||
margin-left: 0.7vw;
|
||||
margin-bottom: 0.5vh;
|
||||
}
|
||||
.minicard .minicard-members .member,
|
||||
.minicard .minicard-assignees .member,
|
||||
.minicard .minicard-creator .member {
|
||||
float: right;
|
||||
border-radius: 50%;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
margin-bottom: 4px;
|
||||
height: 3.5vw;
|
||||
width: 3.5vw;
|
||||
margin-bottom: 0.5vh;
|
||||
}
|
||||
.minicard .minicard-members .assignee,
|
||||
.minicard .minicard-assignees .assignee,
|
||||
.minicard .minicard-creator .assignee {
|
||||
float: right;
|
||||
border-radius: 50%;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
height: 3.5vw;
|
||||
width: 3.5vw;
|
||||
}
|
||||
.minicard .minicard-members + .badges,
|
||||
.minicard .minicard-assignees + .badges,
|
||||
.minicard .minicard-creator + .badges {
|
||||
margin-top: 5px;
|
||||
margin-top: 0.7vh;
|
||||
}
|
||||
.minicard .minicard-assignees {
|
||||
border-bottom: 1px solid #f00;
|
||||
@@ -248,13 +248,13 @@
|
||||
display: none;
|
||||
}
|
||||
.minicard .minicard-description {
|
||||
padding: 6px 0 0 8px;
|
||||
padding: 0.8vh 0 0 1vw;
|
||||
color: #000;
|
||||
background-color: #eee;
|
||||
width: 100%;
|
||||
margin-bottom: 2px;
|
||||
margin-left: -4px;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 0.3vh;
|
||||
margin-left: -0.5vw;
|
||||
border-radius: 0.4vw;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
@@ -262,7 +262,7 @@
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
.minicard.minicard-composer {
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 1.3vh;
|
||||
}
|
||||
.minicard.minicard-composer textarea.minicard-composer-textarea,
|
||||
.minicard.minicard-composer textarea.minicard-composer-textarea:focus {
|
||||
@@ -273,9 +273,9 @@
|
||||
height: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-height: 162px;
|
||||
min-height: 36px;
|
||||
margin-bottom: 20px;
|
||||
max-height: 22vh;
|
||||
min-height: 5vh;
|
||||
margin-bottom: 2.5vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.parent-prefix {
|
||||
@@ -580,3 +580,11 @@
|
||||
.text-green {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
/* Drag and drop file upload visual feedback */
|
||||
.minicard.is-dragging-over {
|
||||
border: 2px dashed #0079bf;
|
||||
background-color: #e3f2fd !important;
|
||||
transform: scale(1.02);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
@@ -31,6 +31,27 @@ template(name="minicard")
|
||||
if cover
|
||||
if currentBoard.allowsCoverAttachmentOnMinicard
|
||||
.minicard-cover(style="background-image: url('{{cover.link 'original'}}?dummyReloadAfterSessionEstablished={{sess}}');")
|
||||
|
||||
// Upload progress indicator for drag-and-drop uploads
|
||||
if hasActiveUploads
|
||||
.minicard-upload-progress
|
||||
.upload-progress-header
|
||||
i.fa.fa-upload
|
||||
span {{_ 'uploading-files'}} ({{uploadCount}})
|
||||
each uploads
|
||||
.upload-progress-item(class="{{#if $eq status 'error'}}upload-error{{/if}}")
|
||||
.upload-progress-filename {{file.name}}
|
||||
.upload-progress-bar
|
||||
.upload-progress-fill(style="width: {{progress}}%")
|
||||
if $eq status 'error'
|
||||
.upload-progress-error
|
||||
i.fa.fa-exclamation-triangle
|
||||
span {{_ 'upload-failed'}}
|
||||
else if $eq status 'completed'
|
||||
.upload-progress-success
|
||||
i.fa.fa-check
|
||||
span {{_ 'upload-completed'}}
|
||||
|
||||
.minicard-title
|
||||
if $eq 'prefix-with-full-path' currentBoard.presentParentTask
|
||||
.parent-prefix
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
import { TAPi18n } from '/imports/i18n';
|
||||
import { CustomFieldStringTemplate } from '/client/lib/customFields'
|
||||
import { CustomFieldStringTemplate } from '/client/lib/customFields';
|
||||
import { handleFileUpload } from './attachments';
|
||||
import uploadProgressManager from '../../lib/uploadProgressManager';
|
||||
|
||||
// Template.cards.events({
|
||||
// 'click .member': Popup.open('cardMember')
|
||||
@@ -107,6 +109,59 @@ BlazeComponent.extendComponent({
|
||||
'click span.badge-icon.fa.fa-sort, click span.badge-text.check-list-sort' : Popup.open("editCardSortOrder"),
|
||||
'click .minicard-labels' : this.cardLabelsPopup,
|
||||
'click .js-open-minicard-details-menu': Popup.open('minicardDetailsActions'),
|
||||
// Drag and drop file upload handlers
|
||||
'dragover .minicard'(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
},
|
||||
'dragenter .minicard'(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const card = this.data();
|
||||
const board = card.board();
|
||||
// Only allow drag-and-drop if user can modify card and board allows attachments
|
||||
if (card.canModifyCard() && board && board.allowsAttachments) {
|
||||
// Check if the drag contains files
|
||||
const dataTransfer = event.originalEvent.dataTransfer;
|
||||
if (dataTransfer && dataTransfer.types && dataTransfer.types.includes('Files')) {
|
||||
$(event.currentTarget).addClass('is-dragging-over');
|
||||
}
|
||||
}
|
||||
},
|
||||
'dragleave .minicard'(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$(event.currentTarget).removeClass('is-dragging-over');
|
||||
},
|
||||
'drop .minicard'(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
$(event.currentTarget).removeClass('is-dragging-over');
|
||||
|
||||
const card = this.data();
|
||||
const board = card.board();
|
||||
|
||||
// Check permissions
|
||||
if (!card.canModifyCard() || !board || !board.allowsAttachments) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a file drop (not a card reorder)
|
||||
const dataTransfer = event.originalEvent.dataTransfer;
|
||||
if (!dataTransfer || !dataTransfer.files || dataTransfer.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the drop contains files (not just text/HTML)
|
||||
if (!dataTransfer.types.includes('Files')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const files = dataTransfer.files;
|
||||
if (files && files.length > 0) {
|
||||
handleFileUpload(card, files);
|
||||
}
|
||||
},
|
||||
}
|
||||
];
|
||||
},
|
||||
@@ -131,6 +186,16 @@ Template.minicard.helpers({
|
||||
},
|
||||
isWatching() {
|
||||
return this.findWatcher(Meteor.userId());
|
||||
},
|
||||
// Upload progress helpers
|
||||
hasActiveUploads() {
|
||||
return uploadProgressManager.hasActiveUploads(this._id);
|
||||
},
|
||||
uploads() {
|
||||
return uploadProgressManager.getUploadsForCard(this._id);
|
||||
},
|
||||
uploadCount() {
|
||||
return uploadProgressManager.getUploadCountForCard(this._id);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ button {
|
||||
box-sizing: border-box;
|
||||
background-color: #ebebeb;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
border-radius: 0.4vw;
|
||||
display: block;
|
||||
margin-bottom: 12px;
|
||||
min-height: 34px;
|
||||
padding: 7px;
|
||||
margin-bottom: 1.5vh;
|
||||
min-height: 4.5vh;
|
||||
padding: 1vh 1vw;
|
||||
}
|
||||
select.full,
|
||||
textarea.full,
|
||||
@@ -31,7 +31,7 @@ button:focus {
|
||||
outline: 0;
|
||||
}
|
||||
input[type="file"] {
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 2vh;
|
||||
}
|
||||
input[type="radio"] {
|
||||
-webkit-appearance: radio;
|
||||
@@ -42,7 +42,7 @@ input[type="text"],
|
||||
input[type="password"],
|
||||
input[type="email"] {
|
||||
transition: background 85ms ease-in, border-color 85ms ease-in;
|
||||
width: 250px;
|
||||
width: min(250px, 30vw);
|
||||
}
|
||||
input[type="text"].inline-input,
|
||||
input[type="password"].inline-input,
|
||||
@@ -50,10 +50,10 @@ input[type="email"].inline-input {
|
||||
background: none;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
padding: 0.3vh;
|
||||
min-height: 0;
|
||||
height: 18px;
|
||||
width: 200px;
|
||||
height: 2.5vh;
|
||||
width: min(200px, 25vw);
|
||||
}
|
||||
input[type="text"].full-line,
|
||||
input[type="password"].full-line,
|
||||
@@ -103,9 +103,9 @@ textarea:disabled {
|
||||
user-select: none;
|
||||
}
|
||||
select {
|
||||
max-height: 300px;
|
||||
width: 256px;
|
||||
margin-bottom: 8px;
|
||||
max-height: 40vh;
|
||||
width: min(256px, 32vw);
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
select.inline {
|
||||
width: 100%;
|
||||
@@ -114,14 +114,14 @@ option[disabled] {
|
||||
color: #222;
|
||||
}
|
||||
textarea {
|
||||
height: 150px;
|
||||
height: 20vh;
|
||||
transition: background 85ms ease-in, border-color 85ms ease-in;
|
||||
resize: vertical;
|
||||
width: 100%;
|
||||
}
|
||||
textarea.editor {
|
||||
resize: none;
|
||||
padding-bottom: 22px;
|
||||
padding-bottom: 3vh;
|
||||
}
|
||||
.button {
|
||||
border-radius: 3px;
|
||||
@@ -136,14 +136,14 @@ button {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-weight: 700;
|
||||
line-height: 22px;
|
||||
padding: 7px 20px;
|
||||
line-height: 1.3;
|
||||
padding: 1vh 2.5vw;
|
||||
text-align: center;
|
||||
}
|
||||
input[type="submit"] .wide,
|
||||
button .wide {
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
padding-left: 4vw;
|
||||
padding-right: 4vw;
|
||||
}
|
||||
input[type="submit"]:hover,
|
||||
button:hover,
|
||||
@@ -224,8 +224,8 @@ button.disabled:active,
|
||||
}
|
||||
fieldset {
|
||||
border: 1px solid #bfbfbf;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
padding: 2vh 2vw;
|
||||
margin-bottom: 2vh;
|
||||
}
|
||||
input[type="hidden"] {
|
||||
display: none;
|
||||
@@ -233,18 +233,18 @@ input[type="hidden"] {
|
||||
.radio-div,
|
||||
.check-div {
|
||||
display: block;
|
||||
margin: 0 0 4px 20px;
|
||||
min-height: 20px;
|
||||
margin: 0 0 0.5vh 2.5vw;
|
||||
min-height: 2.5vh;
|
||||
position: relative;
|
||||
}
|
||||
.radio-div input,
|
||||
.check-div input {
|
||||
left: -18px;
|
||||
left: -2.5vw;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
top: 0.3vh;
|
||||
}
|
||||
.radio-div label,
|
||||
.check-div label {
|
||||
@@ -253,7 +253,7 @@ input[type="hidden"] {
|
||||
label {
|
||||
display: block;
|
||||
font-weight: 700;
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 0.5vh;
|
||||
}
|
||||
label.form-error {
|
||||
color: #d32f2f;
|
||||
@@ -269,7 +269,7 @@ textarea::-moz-placeholder {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 1.5vh;
|
||||
}
|
||||
@media print {
|
||||
.add-controls {
|
||||
@@ -281,13 +281,13 @@ textarea::-moz-placeholder {
|
||||
.edit-controls input[type=button],
|
||||
.add-controls input[type=button] {
|
||||
float: left;
|
||||
height: 32px;
|
||||
height: 4.5vh;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.edit-controls .fa-times-thin,
|
||||
.add-controls .fa-times-thin {
|
||||
font-size: 26px;
|
||||
margin: 3px 10px;
|
||||
font-size: clamp(20px, 4vw, 26px);
|
||||
margin: 0.5vh 1.5vw;
|
||||
}
|
||||
[type="checkbox"]:not(:checked),
|
||||
[type="checkbox"]:checked {
|
||||
|
||||
Vendored
+8
-8
@@ -5,17 +5,17 @@
|
||||
.map-members .mapping-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 0 -4px;
|
||||
margin: 0 -0.5vw;
|
||||
}
|
||||
.map-members .mapping-list .mapping-item {
|
||||
max-width: 300px;
|
||||
min-width: 200px;
|
||||
padding: 6px;
|
||||
margin: 5px;
|
||||
max-width: min(300px, 40vw);
|
||||
min-width: min(200px, 26vw);
|
||||
padding: 0.8vh 0.8vw;
|
||||
margin: 0.7vh;
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
|
||||
border-radius: 0.4vw;
|
||||
box-shadow: 0 0.2vh 0.3vh rgba(0,0,0,0.15);
|
||||
}
|
||||
.map-members .mapping-list .mapping-item:hover {
|
||||
background: #f2f2f2;
|
||||
@@ -37,7 +37,7 @@
|
||||
}
|
||||
.map-members .mapping-list .wekan {
|
||||
display: inline-block;
|
||||
width: 35px;
|
||||
width: 4.5vw;
|
||||
}
|
||||
.map-members .mapping-list .wekan .member {
|
||||
float: none;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
float: left;
|
||||
}
|
||||
[id^="swimlane-"] .list:first-child {
|
||||
min-width: 20px;
|
||||
min-width: 2.5vw;
|
||||
}
|
||||
.list.list-auto-width {
|
||||
flex: 1;
|
||||
@@ -33,7 +33,7 @@
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
height: 100px;
|
||||
height: 15vh;
|
||||
}
|
||||
.list.list-collapsed {
|
||||
flex: none;
|
||||
@@ -45,24 +45,24 @@
|
||||
.list.list-composer .list-name-input,
|
||||
.list .list-composer .list-name-input {
|
||||
background: #fff;
|
||||
margin: -3px 0 8px;
|
||||
margin: -0.4vh 0 1vh;
|
||||
}
|
||||
.list-header-add {
|
||||
flex: 0 0 auto;
|
||||
padding: 12px;
|
||||
padding: 1.5vh 1.5vw;
|
||||
position: relative;
|
||||
min-height: 20px;
|
||||
min-height: 2.5vh;
|
||||
}
|
||||
.list-header {
|
||||
flex: 0 0 auto;
|
||||
padding: 20px 12px 4px;
|
||||
padding: 2.5vh 1.5vw 0.5vh;
|
||||
position: relative;
|
||||
min-height: 20px;
|
||||
min-height: 2.5vh;
|
||||
background-color: #e4e4e4;
|
||||
border-bottom: 6px solid #e4e4e4;
|
||||
border-bottom: 0.8vh solid #e4e4e4;
|
||||
}
|
||||
.list-header.list-header-card-count {
|
||||
min-height: 35px;
|
||||
min-height: 4.5vh;
|
||||
height: auto;
|
||||
}
|
||||
.list-header.ui-sortable-handle {
|
||||
@@ -73,21 +73,21 @@
|
||||
}
|
||||
.list-header .list-header-name {
|
||||
display: inline;
|
||||
font-size: 16px;
|
||||
line-height: 17px;
|
||||
font-size: clamp(14px, 3vw, 18px);
|
||||
line-height: 1.2;
|
||||
margin: 0;
|
||||
font-weight: bold;
|
||||
min-height: 9px;
|
||||
min-width: 30px;
|
||||
min-height: 1.2vh;
|
||||
min-width: 4vw;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.list-rotated {
|
||||
width: 10px;
|
||||
height: 250px;
|
||||
margin-top: -90px;
|
||||
margin-left: -110px;
|
||||
width: 1.3vw;
|
||||
height: 35vh;
|
||||
margin-top: -12vh;
|
||||
margin-left: -14vw;
|
||||
margin-right: 0;
|
||||
transform: rotate(90deg);
|
||||
position: relative;
|
||||
@@ -214,11 +214,137 @@
|
||||
#js-list-width-edit .list-width-error {
|
||||
display: none;
|
||||
}
|
||||
/* Mobile view styles - applied when isMiniScreen is true (iPhone, etc.) */
|
||||
.mini-list.mobile-view {
|
||||
flex: 0 0 60px;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
border-left: 0px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.list.mobile-view {
|
||||
display: contents;
|
||||
flex-basis: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
border-left: 0px;
|
||||
}
|
||||
.list.mobile-view:first-child {
|
||||
margin-left: 0px;
|
||||
}
|
||||
.list.mobile-view.ui-sortable-helper {
|
||||
flex: 0 0 60px;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
border-left: 0px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.list.mobile-view.ui-sortable-helper .list-header.ui-sortable-handle {
|
||||
cursor: grabbing;
|
||||
}
|
||||
.list.mobile-view.placeholder {
|
||||
flex: 0 0 60px;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
border-left: 0px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
.list.mobile-view .list-body {
|
||||
padding: 15px 19px;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
.list.mobile-view .list-header {
|
||||
/*Updated padding values for mobile devices, this should fix text grouping issue*/
|
||||
padding: 20px 0px 20px 0px;
|
||||
border-bottom: 0px solid #e4e4e4;
|
||||
min-height: 30px;
|
||||
margin-top: 10px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
/* Force grid layout for iPhone */
|
||||
display: grid !important;
|
||||
grid-template-columns: 30px 1fr auto auto !important;
|
||||
gap: 10px !important;
|
||||
}
|
||||
.list.mobile-view .list-header .list-header-left-icon {
|
||||
padding: 7px;
|
||||
padding-right: 27px;
|
||||
margin-top: 1px;
|
||||
top: -7px;
|
||||
left: -7px;
|
||||
}
|
||||
.list.mobile-view .list-header .list-header-menu-icon {
|
||||
padding: 14px;
|
||||
font-size: 40px !important;
|
||||
text-align: center;
|
||||
/* Force positioning for iPhone */
|
||||
position: absolute !important;
|
||||
right: 60px !important;
|
||||
top: 50% !important;
|
||||
transform: translateY(-50%) !important;
|
||||
z-index: 10;
|
||||
}
|
||||
.list.mobile-view .list-header .list-header-handle {
|
||||
padding: 14px;
|
||||
font-size: 48px !important;
|
||||
text-align: center;
|
||||
/* Force positioning for iPhone */
|
||||
position: absolute !important;
|
||||
right: 10px !important;
|
||||
top: 50% !important;
|
||||
transform: translateY(-50%) !important;
|
||||
z-index: 10;
|
||||
}
|
||||
.list.mobile-view .list-header .list-header-left-icon {
|
||||
display: grid;
|
||||
grid-row: 1/3;
|
||||
grid-column: 1;
|
||||
}
|
||||
.list.mobile-view .list-header .list-header-name {
|
||||
grid-row: 1;
|
||||
grid-column: 2;
|
||||
align-self: end;
|
||||
font-size: 20px !important;
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.list.mobile-view .list-header .cardCount {
|
||||
grid-row: 2;
|
||||
grid-column: 2;
|
||||
align-self: start;
|
||||
font-size: 16px !important;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.list.mobile-view .list-header .list-header-menu {
|
||||
grid-row: 1/3;
|
||||
grid-column: 3;
|
||||
}
|
||||
.list.mobile-view .list-header .list-header-menu-icon {
|
||||
grid-row: 1/3;
|
||||
grid-column: 3;
|
||||
}
|
||||
.list.mobile-view .list-header .list-header-handle {
|
||||
grid-row: 1/3;
|
||||
grid-column: 4;
|
||||
}
|
||||
.list.mobile-view .list-header .inlined-form {
|
||||
grid-row: 1/3;
|
||||
grid-column: 1/4;
|
||||
}
|
||||
.list.mobile-view .list-header .edit-controls {
|
||||
align-items: initial;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
.mini-list {
|
||||
flex: 0 0 60px;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
border-left: 0px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
@@ -226,6 +352,7 @@
|
||||
display: contents;
|
||||
flex-basis: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
border-left: 0px;
|
||||
}
|
||||
.list:first-child {
|
||||
@@ -250,6 +377,8 @@
|
||||
}
|
||||
.list-body {
|
||||
padding: 15px 19px;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
.list-header {
|
||||
/*Updated padding values for mobile devices, this should fix text grouping issue*/
|
||||
@@ -258,6 +387,8 @@
|
||||
min-height: 30px;
|
||||
margin-top: 10px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
}
|
||||
.list-header .list-header-left-icon {
|
||||
padding: 7px;
|
||||
@@ -267,24 +398,29 @@
|
||||
left: -7px;
|
||||
}
|
||||
.list-header .list-header-menu-icon {
|
||||
padding: 14px;
|
||||
font-size: 40px;
|
||||
text-align: center;
|
||||
/* iOS Safari fallback positioning */
|
||||
position: absolute;
|
||||
padding: 7px;
|
||||
right: 60px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 47px;
|
||||
font-size: 20px;
|
||||
}
|
||||
.list-header .list-header-handle {
|
||||
padding: 14px;
|
||||
font-size: 48px;
|
||||
text-align: center;
|
||||
/* iOS Safari fallback positioning */
|
||||
position: absolute;
|
||||
padding: 7px;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 10px;
|
||||
font-size: 24px;
|
||||
}
|
||||
.list-header {
|
||||
display: grid;
|
||||
grid-template-columns: 30px 5fr 1fr;
|
||||
grid-template-columns: 30px 1fr auto auto;
|
||||
gap: 10px;
|
||||
}
|
||||
.list-header .list-header-left-icon {
|
||||
display: grid;
|
||||
@@ -295,16 +431,30 @@
|
||||
grid-row: 1;
|
||||
grid-column: 2;
|
||||
align-self: end;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.list-header .cardCount {
|
||||
grid-row: 2;
|
||||
grid-column: 2;
|
||||
align-self: start;
|
||||
font-size: 16px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
.list-header .list-header-menu {
|
||||
grid-row: 1/3;
|
||||
grid-column: 3;
|
||||
}
|
||||
.list-header .list-header-menu-icon {
|
||||
grid-row: 1/3;
|
||||
grid-column: 3;
|
||||
}
|
||||
.list-header .list-header-handle {
|
||||
grid-row: 1/3;
|
||||
grid-column: 4;
|
||||
}
|
||||
.list-header .inlined-form {
|
||||
grid-row: 1/3;
|
||||
grid-column: 1/4;
|
||||
@@ -313,6 +463,132 @@
|
||||
align-items: initial;
|
||||
}
|
||||
}
|
||||
|
||||
/* iPhone 12 Mini specific - fix icon positioning in stacked lists view */
|
||||
@media screen and (device-width: 375px) and (device-height: 812px), /* iPhone 12 Mini exact */
|
||||
screen and (max-width: 375px) and (max-height: 812px), /* iPhone 12 Mini viewport */
|
||||
screen and (-webkit-min-device-pixel-ratio: 3) and (max-width: 375px) /* iPhone 12 Mini Retina */ {
|
||||
.list.mobile-view .list-header {
|
||||
/* Force grid layout for iPhone 12 Mini */
|
||||
display: grid !important;
|
||||
grid-template-columns: 30px 1fr auto auto !important;
|
||||
gap: 10px !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
|
||||
.list.mobile-view .list-header .list-header-menu-icon {
|
||||
/* Remove absolute positioning for iPhone 12 Mini */
|
||||
position: static !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
transform: none !important;
|
||||
/* Use grid positioning */
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 3 !important;
|
||||
padding: 14px !important;
|
||||
font-size: 40px !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.list.mobile-view .list-header .list-header-handle {
|
||||
/* Remove absolute positioning for iPhone 12 Mini */
|
||||
position: static !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
transform: none !important;
|
||||
/* Use grid positioning */
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 4 !important;
|
||||
padding: 14px !important;
|
||||
font-size: 48px !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.list.mobile-view .list-header .list-header-name {
|
||||
grid-row: 1 !important;
|
||||
grid-column: 2 !important;
|
||||
align-self: end !important;
|
||||
font-size: 20px !important;
|
||||
font-weight: bold !important;
|
||||
line-height: 1.2 !important;
|
||||
padding-bottom: 2px !important;
|
||||
}
|
||||
|
||||
.list.mobile-view .list-header .cardCount {
|
||||
grid-row: 2 !important;
|
||||
grid-column: 2 !important;
|
||||
align-self: start !important;
|
||||
font-size: 16px !important;
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
.list.mobile-view .list-header .list-header-left-icon {
|
||||
display: grid !important;
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* iPhone device JavaScript detection fallback - fix icon positioning */
|
||||
.iphone-device .list.mobile-view .list-header {
|
||||
/* Force grid layout for iPhone devices */
|
||||
display: grid !important;
|
||||
grid-template-columns: 30px 1fr auto auto !important;
|
||||
gap: 10px !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
|
||||
.iphone-device .list.mobile-view .list-header .list-header-menu-icon {
|
||||
/* Remove absolute positioning for iPhone devices */
|
||||
position: static !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
transform: none !important;
|
||||
/* Use grid positioning */
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 3 !important;
|
||||
padding: 14px !important;
|
||||
font-size: 40px !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.iphone-device .list.mobile-view .list-header .list-header-handle {
|
||||
/* Remove absolute positioning for iPhone devices */
|
||||
position: static !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
transform: none !important;
|
||||
/* Use grid positioning */
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 4 !important;
|
||||
padding: 14px !important;
|
||||
font-size: 48px !important;
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.iphone-device .list.mobile-view .list-header .list-header-name {
|
||||
grid-row: 1 !important;
|
||||
grid-column: 2 !important;
|
||||
align-self: end !important;
|
||||
font-size: 20px !important;
|
||||
font-weight: bold !important;
|
||||
line-height: 1.2 !important;
|
||||
padding-bottom: 2px !important;
|
||||
}
|
||||
|
||||
.iphone-device .list.mobile-view .list-header .cardCount {
|
||||
grid-row: 2 !important;
|
||||
grid-column: 2 !important;
|
||||
align-self: start !important;
|
||||
font-size: 16px !important;
|
||||
line-height: 1.2 !important;
|
||||
}
|
||||
|
||||
.iphone-device .list.mobile-view .list-header .list-header-left-icon {
|
||||
display: grid !important;
|
||||
grid-row: 1/3 !important;
|
||||
grid-column: 1 !important;
|
||||
}
|
||||
.link-board-wrapper {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
template(name='list')
|
||||
.list.js-list(id="js-list-{{_id}}"
|
||||
style="{{#unless collapsed}}min-width:{{listWidth}}px;max-width:{{listConstraint}}px;{{/unless}}"
|
||||
class="{{#if collapsed}}list-collapsed{{/if}} {{#if autoWidth}}list-auto-width{{/if}}")
|
||||
class="{{#if collapsed}}list-collapsed{{/if}} {{#if autoWidth}}list-auto-width{{/if}} {{#if isMiniScreen}}mobile-view{{/if}}")
|
||||
+listHeader
|
||||
+listBody
|
||||
|
||||
template(name='miniList')
|
||||
a.mini-list.js-select-list.js-list(id="js-list-{{_id}}")
|
||||
a.mini-list.js-select-list.js-list(id="js-list-{{_id}}" class="{{#if isMiniScreen}}mobile-view{{/if}}")
|
||||
+listHeader
|
||||
@@ -1,27 +1,27 @@
|
||||
.my-cards-board-wrapper {
|
||||
border-radius: 0 0 4px 4px;
|
||||
min-width: 400px;
|
||||
margin-bottom: 2rem;
|
||||
border-radius: 0 0 0.5vw 0.5vw;
|
||||
min-width: min(400px, 52vw);
|
||||
margin-bottom: 2.5vh;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
border-width: 2px;
|
||||
border-width: 0.3vw;
|
||||
border-style: solid;
|
||||
border-color: #a2a2a2;
|
||||
}
|
||||
.my-cards-board-title {
|
||||
font-size: 1.4rem;
|
||||
font-size: clamp(1.2rem, 3vw, 1.6rem);
|
||||
font-weight: bold;
|
||||
padding: 0.5rem;
|
||||
padding: 0.7vh 0.7vw;
|
||||
background-color: #808080;
|
||||
color: #fff;
|
||||
}
|
||||
.my-cards-swimlane-title {
|
||||
font-size: 1.1rem;
|
||||
font-size: clamp(1rem, 2.5vw, 1.3rem);
|
||||
font-weight: bold;
|
||||
padding: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
padding: 0.7vh 0.7vw;
|
||||
padding-bottom: 0.5vh;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-bottom: 0.7vh;
|
||||
text-align: center;
|
||||
}
|
||||
.swimlane-default-color {
|
||||
@@ -29,23 +29,23 @@
|
||||
}
|
||||
.my-cards-list-title {
|
||||
font-weight: bold;
|
||||
font-size: 1.1rem;
|
||||
font-size: clamp(1rem, 2.5vw, 1.3rem);
|
||||
text-align: center;
|
||||
margin-bottom: 0.7rem;
|
||||
margin-bottom: 0.9vh;
|
||||
}
|
||||
.my-cards-list-wrapper {
|
||||
margin: 1rem;
|
||||
border-radius: 5px;
|
||||
margin: 1.3vh 1.3vw;
|
||||
border-radius: 0.7vw;
|
||||
display: inline-grid;
|
||||
min-width: 250px;
|
||||
max-width: 350px;
|
||||
min-width: min(250px, 32vw);
|
||||
max-width: min(350px, 45vw);
|
||||
}
|
||||
.my-cards-card-wrapper {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 1.3vh;
|
||||
}
|
||||
.my-cards-dueat-list-wrapper {
|
||||
max-width: 500px;
|
||||
max-width: min(500px, 65vw);
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
.broken-cards-card-wrapper {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
border-width: 3px !important;
|
||||
margin-bottom: 1.3vh;
|
||||
border-width: 0.4vw !important;
|
||||
border-color: #808080 !important;
|
||||
border-style: solid;
|
||||
border-radius: 5px;
|
||||
padding: 1.5rem;
|
||||
border-radius: 0.7vw;
|
||||
padding: 2vh 2vw;
|
||||
background-color: #fff;
|
||||
}
|
||||
.broken-cards-wrapper {
|
||||
max-width: 500px;
|
||||
max-width: min(500px, 65vw);
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.due-cards-dueat-list-wrapper {
|
||||
max-width: 500px;
|
||||
max-width: min(500px, 65vw);
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
@@ -325,6 +325,7 @@ BlazeComponent.extendComponent({
|
||||
}).register('editor');
|
||||
|
||||
import DOMPurify from 'dompurify';
|
||||
import { sanitizeHTML } from '/imports/lib/secureDOMPurify';
|
||||
|
||||
// Additional safeAttrValue function to allow for other specific protocols
|
||||
// See https://github.com/leizongmin/js-xss/issues/52#issuecomment-241354114
|
||||
@@ -371,9 +372,7 @@ Blaze.Template.registerHelper(
|
||||
let content = Blaze.toHTML(view.templateContentBlock);
|
||||
const currentBoard = Utils.getCurrentBoard();
|
||||
if (!currentBoard)
|
||||
return HTML.Raw(
|
||||
DOMPurify.sanitize(content, { ALLOW_UNKNOWN_PROTOCOLS: true }),
|
||||
);
|
||||
return HTML.Raw(sanitizeHTML(content));
|
||||
const knowedUsers = _.union(currentBoard.members.map(member => {
|
||||
const u = ReactiveCache.getUser(member.userId);
|
||||
if (u) {
|
||||
@@ -417,9 +416,7 @@ Blaze.Template.registerHelper(
|
||||
content = content.replace(fullMention, Blaze.toHTML(link));
|
||||
}
|
||||
|
||||
return HTML.Raw(
|
||||
DOMPurify.sanitize(content, { ALLOW_UNKNOWN_PROTOCOLS: true }),
|
||||
);
|
||||
return HTML.Raw(sanitizeHTML(content));
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -99,7 +99,36 @@
|
||||
display: flex;
|
||||
z-index: 1000;
|
||||
padding: 10px 0px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap; /* Allow wrapping on mobile */
|
||||
min-height: 28px; /* Allow height to grow */
|
||||
}
|
||||
#header-quick-access .home-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon a:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon .fa-home {
|
||||
font-size: 16px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#header-quick-access .allBoards {
|
||||
font-size: 14px;
|
||||
padding: 4px 15px;
|
||||
@@ -196,6 +225,197 @@
|
||||
margin: 4px 8px 0 0;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* Zoom Controls in Header */
|
||||
#header-quick-access .zoom-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5vw;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
padding: 0.5vh 1vw;
|
||||
border-radius: 0.5vw;
|
||||
box-shadow: 0 0.2vh 0.5vh rgba(0,0,0,0.1);
|
||||
margin: 0 1vw;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .board-header-btn {
|
||||
padding: 0.5vh 0.8vw !important;
|
||||
border-radius: 0.3vw !important;
|
||||
background: #fff !important;
|
||||
border: 1px solid #000 !important;
|
||||
transition: all 0.2s ease !important;
|
||||
color: #000 !important;
|
||||
height: auto !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
float: none !important;
|
||||
overflow: visible !important;
|
||||
text-decoration: none !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
gap: 0.3vw !important;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .board-header-btn i {
|
||||
color: #000 !important;
|
||||
float: none !important;
|
||||
display: inline !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .board-header-btn:hover {
|
||||
background: #000 !important;
|
||||
border-color: #000 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .board-header-btn:hover i {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-level {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
min-width: 3vw;
|
||||
text-align: center;
|
||||
font-size: clamp(12px, 2vw, 14px);
|
||||
cursor: pointer;
|
||||
padding: 0.3vh 0.5vw;
|
||||
border-radius: 0.3vw;
|
||||
transition: all 0.2s ease;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-level:hover {
|
||||
background: #f0f0f0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-display {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-input {
|
||||
background: #fff;
|
||||
color: #000;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 0.3vw;
|
||||
padding: 0.3vh 0.5vw;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
min-width: 3vw;
|
||||
font-size: clamp(12px, 2vw, 14px);
|
||||
}
|
||||
|
||||
/* Make zoom input wider on all mobile screens */
|
||||
@media screen and (max-width: 800px) {
|
||||
#header-quick-access .zoom-controls .zoom-input {
|
||||
min-width: 50px !important; /* Wider on mobile */
|
||||
width: 50px !important; /* Fixed width to show all numbers */
|
||||
font-size: 14px !important; /* Slightly larger text */
|
||||
}
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-input:focus {
|
||||
outline: 2px solid #005fcc;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
/* Mobile Mode Toggle in Header */
|
||||
#header-quick-access .mobile-mode-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 1vw;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn {
|
||||
padding: 0.5vh 0.8vw !important;
|
||||
border-radius: 0.3vw !important;
|
||||
background: #fff !important;
|
||||
border: 1px solid #000 !important;
|
||||
transition: all 0.2s ease !important;
|
||||
color: #000 !important;
|
||||
height: auto !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
float: none !important;
|
||||
overflow: visible !important;
|
||||
text-decoration: none !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
gap: 6px !important;
|
||||
position: relative !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn i {
|
||||
color: #666 !important;
|
||||
float: none !important;
|
||||
display: inline !important;
|
||||
line-height: normal !important;
|
||||
margin: 0 !important;
|
||||
transition: all 0.2s ease !important;
|
||||
font-size: clamp(14px, 2.8vw, 18px) !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn i.active {
|
||||
color: #000 !important;
|
||||
font-weight: bold !important;
|
||||
transform: scale(1.1) !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn:hover {
|
||||
background: #000 !important;
|
||||
border-color: #000 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn:hover i {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn:hover i.active {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn.mobile-active {
|
||||
background: #fff !important;
|
||||
border-color: #000 !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn.mobile-active i.mobile-icon {
|
||||
color: #000 !important;
|
||||
font-weight: bold !important;
|
||||
transform: scale(1.1) !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn.mobile-active i.desktop-icon {
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn.desktop-active {
|
||||
background: #fff !important;
|
||||
border-color: #000 !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn.desktop-active i.mobile-icon {
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn.desktop-active i.desktop-icon {
|
||||
color: #000 !important;
|
||||
font-weight: bold !important;
|
||||
transform: scale(1.1) !important;
|
||||
}
|
||||
#header-quick-access #header-user-bar .header-user-bar-name i.fa-chevron-down {
|
||||
margin-right: 4px;
|
||||
}
|
||||
@@ -227,6 +447,650 @@
|
||||
width: 100%;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
/* Mobile home icon styling */
|
||||
#header-quick-access .home-icon {
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon .fa-home {
|
||||
font-size: 16px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon a {
|
||||
padding: 4px 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Ensure All Boards text is visible on mobile */
|
||||
#header-quick-access .home-icon.allBoards {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* Adjust for very small screens */
|
||||
@media screen and (max-width: 480px) {
|
||||
#header-quick-access .home-icon a {
|
||||
font-size: 11px;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon .fa-home {
|
||||
font-size: 14px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile - make all text and icons 2x bigger above #content by default */
|
||||
@media screen and (max-width: 800px),
|
||||
screen and (max-device-width: 800px),
|
||||
screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 800px),
|
||||
screen and (max-width: 800px) and (orientation: portrait),
|
||||
screen and (max-width: 800px) and (orientation: landscape) {
|
||||
#header-quick-access {
|
||||
height: auto !important; /* Allow height to grow */
|
||||
min-height: 48px !important; /* Minimum height for mobile */
|
||||
flex-wrap: wrap !important; /* Force wrapping */
|
||||
align-items: flex-start !important; /* Align to top when wrapping */
|
||||
padding: 8px 0px !important; /* Adjust padding for mobile */
|
||||
}
|
||||
#header-quick-access {
|
||||
font-size: 2em !important; /* 2x bigger base font size */
|
||||
}
|
||||
|
||||
#header-quick-access * {
|
||||
font-size: inherit !important; /* Inherit the 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .fa,
|
||||
#header-quick-access .icon {
|
||||
font-size: 2em !important; /* 2x bigger icons */
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon a {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon .fa-home {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-level {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-input {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn i {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
/* Mobile header wrapping and spacing */
|
||||
#header-quick-access .home-icon {
|
||||
flex-shrink: 0 !important;
|
||||
margin-right: 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
#header-quick-access #notifications {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
#header-quick-access #header-user-bar {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
#header-quick-access ul.header-quick-access-list {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile All Boards page - make logo row elements 2x bigger */
|
||||
@media screen and (max-width: 800px),
|
||||
screen and (max-device-width: 800px),
|
||||
screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 800px),
|
||||
screen and (max-width: 800px) and (orientation: portrait),
|
||||
screen and (max-width: 800px) and (orientation: landscape) {
|
||||
.wrapper ~ #header-quick-access,
|
||||
body:not(.board-view) #header-quick-access {
|
||||
font-size: 2em !important; /* 2x bigger base font size for logo row */
|
||||
}
|
||||
|
||||
/* iPhone 12 Mini specific - 3x bigger for All Boards page */
|
||||
@media screen and (device-width: 375px) and (device-height: 812px), /* iPhone 12 Mini exact */
|
||||
screen and (max-width: 375px) and (max-height: 812px), /* iPhone 12 Mini viewport */
|
||||
screen and (-webkit-min-device-pixel-ratio: 3) and (max-width: 375px) /* iPhone 12 Mini Retina */ {
|
||||
.wrapper ~ #header-quick-access,
|
||||
body:not(.board-view) #header-quick-access {
|
||||
font-size: 3em !important; /* 3x bigger base font size for iPhone 12 Mini All Boards page */
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access *,
|
||||
body:not(.board-view) #header-quick-access * {
|
||||
font-size: inherit !important; /* Inherit the 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access .fa,
|
||||
.wrapper ~ #header-quick-access .icon,
|
||||
body:not(.board-view) #header-quick-access .fa,
|
||||
body:not(.board-view) #header-quick-access .icon {
|
||||
font-size: 2em !important; /* 2x bigger icons in logo row */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access .home-icon a,
|
||||
body:not(.board-view) #header-quick-access .home-icon a {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access .home-icon .fa-home,
|
||||
body:not(.board-view) #header-quick-access .home-icon .fa-home {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access .zoom-controls,
|
||||
body:not(.board-view) #header-quick-access .zoom-controls {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access .zoom-controls .zoom-level,
|
||||
body:not(.board-view) #header-quick-access .zoom-controls .zoom-level {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access .zoom-controls .zoom-input,
|
||||
body:not(.board-view) #header-quick-access .zoom-controls .zoom-input {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access .mobile-mode-toggle .board-header-btn,
|
||||
body:not(.board-view) #header-quick-access .mobile-mode-toggle .board-header-btn {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access .mobile-mode-toggle .board-header-btn i,
|
||||
body:not(.board-view) #header-quick-access .mobile-mode-toggle .board-header-btn i {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access #notifications,
|
||||
body:not(.board-view) #header-quick-access #notifications {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access #notifications .fa,
|
||||
body:not(.board-view) #header-quick-access #notifications .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access #header-user-bar,
|
||||
body:not(.board-view) #header-quick-access #header-user-bar {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.wrapper ~ #header-quick-access #header-user-bar .fa,
|
||||
body:not(.board-view) #header-quick-access #header-user-bar .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
}
|
||||
|
||||
/* iPhone 12 Mini specific - make header elements 3x bigger */
|
||||
@media screen and (device-width: 375px) and (device-height: 812px), /* iPhone 12 Mini exact */
|
||||
screen and (max-width: 375px) and (max-height: 812px), /* iPhone 12 Mini viewport */
|
||||
screen and (-webkit-min-device-pixel-ratio: 3) and (max-width: 375px), /* iPhone 12 Mini Retina */
|
||||
screen and (max-width: 375px) and (orientation: portrait), /* iPhone 12 Mini portrait */
|
||||
screen and (max-width: 375px) and (orientation: landscape) /* iPhone 12 Mini landscape */ {
|
||||
#header-quick-access {
|
||||
font-size: 3em !important; /* 3x bigger base font size for iPhone 12 Mini */
|
||||
height: auto !important; /* Allow height to grow */
|
||||
min-height: 84px !important; /* Much taller minimum height for iPhone 12 Mini */
|
||||
flex-wrap: wrap !important; /* Force wrapping */
|
||||
align-items: flex-start !important; /* Align to top when wrapping */
|
||||
padding: 18px 0px !important; /* More padding for iPhone 12 Mini */
|
||||
}
|
||||
|
||||
#header-quick-access * {
|
||||
font-size: inherit !important; /* Inherit the 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .fa,
|
||||
#header-quick-access .icon {
|
||||
font-size: 3em !important; /* 3x bigger icons for iPhone 12 Mini */
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon a {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon .fa-home {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-level {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-input {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn i {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access #notifications {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access #notifications .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access #header-user-bar {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access #header-user-bar .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
/* iPhone 12 Mini header wrapping and spacing */
|
||||
#header-quick-access .home-icon {
|
||||
flex-shrink: 0 !important;
|
||||
margin-right: 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
#header-quick-access #notifications {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
#header-quick-access #header-user-bar {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
#header-quick-access ul.header-quick-access-list {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* iPhone 12 Mini and very small screens - make header elements much larger */
|
||||
@media screen and (max-width: 400px) and (max-height: 900px),
|
||||
screen and (max-device-width: 400px) and (max-device-height: 900px),
|
||||
screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 400px),
|
||||
screen and (max-width: 400px) and (orientation: portrait),
|
||||
screen and (max-width: 400px) and (orientation: landscape),
|
||||
screen and (max-width: 430px) and (max-height: 950px), /* iPhone 12 Mini range */
|
||||
screen and (max-width: 450px) and (max-height: 1000px), /* iPhone range */
|
||||
screen and (-webkit-min-device-pixel-ratio: 3) and (max-width: 450px), /* Retina displays */
|
||||
screen and (device-width: 375px) and (device-height: 812px), /* iPhone 12 Mini exact */
|
||||
screen and (device-width: 390px) and (device-height: 844px), /* iPhone 12/13 */
|
||||
screen and (device-width: 428px) and (device-height: 926px) /* iPhone 12 Pro Max */ {
|
||||
#header-quick-access {
|
||||
height: 40px !important; /* Taller header */
|
||||
padding: 12px 0px !important;
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon a {
|
||||
font-size: 16px !important; /* Much larger text */
|
||||
padding: 8px 12px !important;
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon .fa-home {
|
||||
font-size: 20px !important; /* Much larger icon */
|
||||
margin-right: 6px !important;
|
||||
}
|
||||
|
||||
#header-quick-access .home-icon {
|
||||
margin-right: 1rem !important;
|
||||
}
|
||||
|
||||
/* Make zoom controls larger */
|
||||
#header-quick-access .zoom-controls {
|
||||
padding: 0.8vh 1.5vw !important;
|
||||
margin: 0 1.5vw !important;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-level {
|
||||
font-size: 16px !important; /* Larger zoom text */
|
||||
padding: 0.5vh 0.8vw !important;
|
||||
min-width: 4vw !important;
|
||||
}
|
||||
|
||||
#header-quick-access .zoom-controls .zoom-input {
|
||||
font-size: 16px !important; /* Larger input text */
|
||||
padding: 0.5vh 0.8vw !important;
|
||||
min-width: 6vw !important; /* Much wider for mobile */
|
||||
width: 60px !important; /* Fixed width to show all numbers */
|
||||
}
|
||||
|
||||
/* Make mobile mode toggle larger */
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn {
|
||||
padding: 0.8vh 1.2vw !important;
|
||||
font-size: 16px !important;
|
||||
}
|
||||
|
||||
#header-quick-access .mobile-mode-toggle .board-header-btn i {
|
||||
font-size: 18px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback for iPhone devices using JavaScript detection */
|
||||
.iphone-device #header-quick-access {
|
||||
font-size: 2em !important; /* 2x bigger base font size */
|
||||
height: auto !important; /* Allow height to grow */
|
||||
min-height: 48px !important; /* Minimum height for mobile */
|
||||
flex-wrap: wrap !important; /* Force wrapping */
|
||||
align-items: flex-start !important; /* Align to top when wrapping */
|
||||
padding: 8px 0px !important; /* Adjust padding for mobile */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access * {
|
||||
font-size: inherit !important; /* Inherit the 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .fa,
|
||||
.iphone-device #header-quick-access .icon {
|
||||
font-size: 2em !important; /* 2x bigger icons */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .home-icon a {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .home-icon .fa-home {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .zoom-controls {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .zoom-controls .zoom-level {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .zoom-controls .zoom-input {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .mobile-mode-toggle .board-header-btn {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .mobile-mode-toggle .board-header-btn i {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
/* iPhone device header wrapping and spacing */
|
||||
.iphone-device #header-quick-access .home-icon {
|
||||
flex-shrink: 0 !important;
|
||||
margin-right: 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .zoom-controls {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .mobile-mode-toggle {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access #notifications {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access #header-user-bar {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access ul.header-quick-access-list {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 4px !important;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
/* iPhone 12 Mini specific - JavaScript detection fallback */
|
||||
.iphone-device #header-quick-access {
|
||||
font-size: 3em !important; /* 3x bigger base font size for iPhone 12 Mini */
|
||||
height: auto !important; /* Allow height to grow */
|
||||
min-height: 84px !important; /* Much taller minimum height for iPhone 12 Mini */
|
||||
flex-wrap: wrap !important; /* Force wrapping */
|
||||
align-items: flex-start !important; /* Align to top when wrapping */
|
||||
padding: 18px 0px !important; /* More padding for iPhone 12 Mini */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access * {
|
||||
font-size: inherit !important; /* Inherit the 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .fa,
|
||||
.iphone-device #header-quick-access .icon {
|
||||
font-size: 3em !important; /* 3x bigger icons for iPhone 12 Mini */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .home-icon a {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .home-icon .fa-home {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .zoom-controls {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .zoom-controls .zoom-level {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .zoom-controls .zoom-input {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .mobile-mode-toggle .board-header-btn {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .mobile-mode-toggle .board-header-btn i {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access #notifications {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access #notifications .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access #header-user-bar {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access #header-user-bar .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
/* iPhone 12 Mini header wrapping and spacing - JavaScript fallback */
|
||||
.iphone-device #header-quick-access .home-icon {
|
||||
flex-shrink: 0 !important;
|
||||
margin-right: 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .zoom-controls {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access .mobile-mode-toggle {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access #notifications {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access #header-user-bar {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
}
|
||||
|
||||
.iphone-device #header-quick-access ul.header-quick-access-list {
|
||||
flex-shrink: 0 !important;
|
||||
margin: 0 0.5rem !important;
|
||||
margin-bottom: 6px !important;
|
||||
width: auto !important;
|
||||
}
|
||||
|
||||
/* iPhone 12 Mini All Boards page - make logo row elements 3x bigger */
|
||||
.iphone-device .wrapper ~ #header-quick-access,
|
||||
.iphone-device body:not(.board-view) #header-quick-access {
|
||||
font-size: 3em !important; /* 3x bigger base font size for logo row */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access *,
|
||||
.iphone-device body:not(.board-view) #header-quick-access * {
|
||||
font-size: inherit !important; /* Inherit the 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access .fa,
|
||||
.iphone-device .wrapper ~ #header-quick-access .icon,
|
||||
.iphone-device body:not(.board-view) #header-quick-access .fa,
|
||||
.iphone-device body:not(.board-view) #header-quick-access .icon {
|
||||
font-size: 2em !important; /* 2x bigger icons in logo row */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access .home-icon a,
|
||||
.iphone-device body:not(.board-view) #header-quick-access .home-icon a {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access .home-icon .fa-home,
|
||||
.iphone-device body:not(.board-view) #header-quick-access .home-icon .fa-home {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access .zoom-controls,
|
||||
.iphone-device body:not(.board-view) #header-quick-access .zoom-controls {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access .zoom-controls .zoom-level,
|
||||
.iphone-device body:not(.board-view) #header-quick-access .zoom-controls .zoom-level {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access .zoom-controls .zoom-input,
|
||||
.iphone-device body:not(.board-view) #header-quick-access .zoom-controls .zoom-input {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access .mobile-mode-toggle .board-header-btn,
|
||||
.iphone-device body:not(.board-view) #header-quick-access .mobile-mode-toggle .board-header-btn {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access .mobile-mode-toggle .board-header-btn i,
|
||||
.iphone-device body:not(.board-view) #header-quick-access .mobile-mode-toggle .board-header-btn i {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access #notifications,
|
||||
.iphone-device body:not(.board-view) #header-quick-access #notifications {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access #notifications .fa,
|
||||
.iphone-device body:not(.board-view) #header-quick-access #notifications .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access #header-user-bar,
|
||||
.iphone-device body:not(.board-view) #header-quick-access #header-user-bar {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
.iphone-device .wrapper ~ #header-quick-access #header-user-bar .fa,
|
||||
.iphone-device body:not(.board-view) #header-quick-access #header-user-bar .fa {
|
||||
font-size: 1em !important; /* Use inherited 2x scaling */
|
||||
}
|
||||
|
||||
#header-quick-access ul {
|
||||
width: calc(100% - 60px);
|
||||
margin-right: 10px;
|
||||
@@ -237,12 +1101,6 @@
|
||||
#header-quick-access ul li a {
|
||||
height: 100%;
|
||||
}
|
||||
#header-quick-access span .fa-home {
|
||||
font-size: 26px;
|
||||
margin-top: -2px;
|
||||
margin-right: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
#header-quick-access #header-new-board-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -6,10 +6,31 @@ template(name="header")
|
||||
The first link goes to the boards page.
|
||||
if currentUser
|
||||
#header-quick-access(class=currentBoard.colorClass)
|
||||
// Home icon - always at left side of logo
|
||||
span.home-icon.allBoards
|
||||
a(href="{{pathFor 'home'}}")
|
||||
span.fa.fa-home
|
||||
| {{_ 'all-boards'}}
|
||||
|
||||
// Logo - always visible in desktop mode
|
||||
unless currentSetting.hideLogo
|
||||
if currentSetting.customTopLeftCornerLogoImageUrl
|
||||
if currentSetting.customTopLeftCornerLogoLinkUrl
|
||||
a(href="{{currentSetting.customTopLeftCornerLogoLinkUrl}}" alt="{{currentSetting.productName}}" title="{{currentSetting.productName}}")
|
||||
img(src="{{currentSetting.customTopLeftCornerLogoImageUrl}}" height="{{#if currentSetting.customTopLeftCornerLogoHeight}}#{currentSetting.customTopLeftCornerLogoHeight}{{else}}27{{/if}}" width="auto" margin="0" padding="0")
|
||||
unless currentSetting.customTopLeftCornerLogoLinkUrl
|
||||
img(src="{{currentSetting.customTopLeftCornerLogoImageUrl}}" height="{{#if currentSetting.customTopLeftCornerLogoHeight}}#{currentSetting.customTopLeftCornerLogoHeight}{{else}}27{{/if}}" width="auto" margin="0" padding="0" alt="{{currentSetting.productName}}" title="{{currentSetting.productName}}")
|
||||
unless currentSetting.customTopLeftCornerLogoImageUrl
|
||||
div#headerIsSettingDatabaseCallDone
|
||||
img(src="{{pathFor '/logo-header.png'}}" alt="{{currentSetting.productName}}" title="{{currentSetting.productName}}")
|
||||
|
||||
// Zoom controls - always visible
|
||||
.zoom-controls
|
||||
span.zoom-level.js-zoom-level-click(title="{{_ 'click-to-change-zoom'}}")
|
||||
span.zoom-display {{zoomLevel}}%
|
||||
input.zoom-input.js-zoom-input(type="number" value=zoomLevel min="50" max="300" step="10" style="display: none;")
|
||||
|
||||
if isMiniScreen
|
||||
span
|
||||
a(href="{{pathFor 'home'}}")
|
||||
span.fa.fa-home
|
||||
ul.header-quick-access-list
|
||||
if currentList
|
||||
each currentBoard.lists
|
||||
@@ -23,32 +44,14 @@ template(name="header")
|
||||
a(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
+viewer
|
||||
= title
|
||||
a.js-toggle-desktop-drag-handles(title="{{_ 'show-desktop-drag-handles'}}" alt="{{_ 'show-desktop-drag-handles'}}")
|
||||
i.fa.fa-arrows
|
||||
if isShowDesktopDragHandles
|
||||
i.fa.fa-check-square-o
|
||||
unless isShowDesktopDragHandles
|
||||
i.fa.fa-ban
|
||||
//a.js-toggle-desktop-drag-handles(title="{{_ 'show-desktop-drag-handles'}}" alt="{{_ 'show-desktop-drag-handles'}}")
|
||||
// i.fa.fa-arrows
|
||||
// if isShowDesktopDragHandles
|
||||
// i.fa.fa-check-square-o
|
||||
// unless isShowDesktopDragHandles
|
||||
// i.fa.fa-ban
|
||||
#header-new-board-icon
|
||||
else
|
||||
//-
|
||||
On sandstorm, the logo shouldn't be clickable, because we only have one
|
||||
page/document on it, and we don't want to see the home page containing
|
||||
the list of all boards.
|
||||
unless currentSetting.hideLogo
|
||||
if currentSetting.customTopLeftCornerLogoImageUrl
|
||||
if currentSetting.customTopLeftCornerLogoLinkUrl
|
||||
a(href="{{currentSetting.customTopLeftCornerLogoLinkUrl}}" alt="{{currentSetting.productName}}" title="{{currentSetting.productName}}")
|
||||
img(src="{{currentSetting.customTopLeftCornerLogoImageUrl}}" height="{{#if currentSetting.customTopLeftCornerLogoHeight}}#{currentSetting.customTopLeftCornerLogoHeight}{{else}}27{{/if}}" width="auto" margin="0" padding="0")
|
||||
unless currentSetting.customTopLeftCornerLogoLinkUrl
|
||||
img(src="{{currentSetting.customTopLeftCornerLogoImageUrl}}" height="{{#if currentSetting.customTopLeftCornerLogoHeight}}#{currentSetting.customTopLeftCornerLogoHeight}{{else}}27{{/if}}" width="auto" margin="0" padding="0" alt="{{currentSetting.productName}}" title="{{currentSetting.productName}}")
|
||||
unless currentSetting.customTopLeftCornerLogoImageUrl
|
||||
div#headerIsSettingDatabaseCallDone
|
||||
img(src="{{pathFor '/logo-header.png'}}" alt="{{currentSetting.productName}}" title="{{currentSetting.productName}}")
|
||||
span.allBoards
|
||||
a(href="{{pathFor 'home'}}")
|
||||
span.fa.fa-home
|
||||
| {{_ 'all-boards'}}
|
||||
ul.header-quick-access-list
|
||||
//li
|
||||
// a(href="{{pathFor 'public'}}")
|
||||
@@ -61,12 +64,12 @@ template(name="header")
|
||||
= title
|
||||
else
|
||||
li.current.empty {{_ 'quick-access-description'}}
|
||||
a.js-toggle-desktop-drag-handles(title="{{_ 'show-desktop-drag-handles'}}" alt="{{_ 'show-desktop-drag-handles'}}")
|
||||
i.fa.fa-arrows
|
||||
if isShowDesktopDragHandles
|
||||
i.fa.fa-check-square-o
|
||||
unless isShowDesktopDragHandles
|
||||
i.fa.fa-ban
|
||||
//a.js-toggle-desktop-drag-handles(title="{{_ 'show-desktop-drag-handles'}}" alt="{{_ 'show-desktop-drag-handles'}}")
|
||||
// i.fa.fa-arrows
|
||||
// if isShowDesktopDragHandles
|
||||
// i.fa.fa-check-square-o
|
||||
// unless isShowDesktopDragHandles
|
||||
// i.fa.fa-ban
|
||||
// Next line is used only for spacing at header,
|
||||
// there is no visible clickable icon.
|
||||
#header-new-board-icon
|
||||
@@ -75,6 +78,10 @@ template(name="header")
|
||||
//a#header-new-board-icon.js-create-board
|
||||
// i.fa.fa-plus(title="Create a new board")
|
||||
|
||||
.mobile-mode-toggle
|
||||
a.board-header-btn.js-mobile-mode-toggle(title="{{_ 'mobile-desktop-toggle'}}" class="{{#if mobileMode}}mobile-active{{else}}desktop-active{{/if}}")
|
||||
i.fa.fa-mobile.mobile-icon(class="{{#if mobileMode}}active{{/if}}")
|
||||
i.fa.fa-desktop.desktop-icon(class="{{#unless mobileMode}}active{{/unless}}")
|
||||
+notifications
|
||||
|
||||
if currentSetting.customHelpLinkUrl
|
||||
|
||||
@@ -44,10 +44,66 @@ Template.header.helpers({
|
||||
const announcements = Announcements.findOne();
|
||||
return announcements && announcements.body;
|
||||
},
|
||||
|
||||
zoomLevel() {
|
||||
const sessionZoom = Session.get('wekan-zoom-level');
|
||||
if (sessionZoom !== undefined) {
|
||||
return Math.round(sessionZoom * 100);
|
||||
}
|
||||
return Math.round(Utils.getZoomLevel() * 100);
|
||||
},
|
||||
|
||||
mobileMode() {
|
||||
const sessionMode = Session.get('wekan-mobile-mode');
|
||||
if (sessionMode !== undefined) {
|
||||
return sessionMode;
|
||||
}
|
||||
return Utils.getMobileMode();
|
||||
},
|
||||
});
|
||||
|
||||
Template.header.events({
|
||||
'click .js-create-board': Popup.open('headerBarCreateBoard'),
|
||||
'click .js-zoom-level-click'(evt) {
|
||||
const $zoomDisplay = $(evt.currentTarget).find('.zoom-display');
|
||||
const $zoomInput = $(evt.currentTarget).find('.zoom-input');
|
||||
|
||||
// Hide display, show input
|
||||
$zoomDisplay.hide();
|
||||
$zoomInput.show().focus().select();
|
||||
},
|
||||
|
||||
'keypress .js-zoom-input'(evt) {
|
||||
if (evt.which === 13) { // Enter key
|
||||
const newZoomPercent = parseInt(evt.target.value);
|
||||
|
||||
if (!isNaN(newZoomPercent) && newZoomPercent >= 50 && newZoomPercent <= 300) {
|
||||
const newZoom = newZoomPercent / 100;
|
||||
Utils.setZoomLevel(newZoom);
|
||||
|
||||
// Hide input, show display
|
||||
const $zoomDisplay = $(evt.target).siblings('.zoom-display');
|
||||
const $zoomInput = $(evt.target);
|
||||
$zoomInput.hide();
|
||||
$zoomDisplay.show();
|
||||
} else {
|
||||
alert('Please enter a zoom level between 50% and 300%');
|
||||
evt.target.focus().select();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'blur .js-zoom-input'(evt) {
|
||||
// When input loses focus, hide it and show display
|
||||
const $zoomDisplay = $(evt.target).siblings('.zoom-display');
|
||||
const $zoomInput = $(evt.target);
|
||||
$zoomInput.hide();
|
||||
$zoomDisplay.show();
|
||||
},
|
||||
'click .js-mobile-mode-toggle'() {
|
||||
const currentMode = Utils.getMobileMode();
|
||||
Utils.setMobileMode(!currentMode);
|
||||
},
|
||||
'click .js-close-announcement'() {
|
||||
$('.announcement').hide();
|
||||
},
|
||||
|
||||
@@ -52,8 +52,8 @@ input,
|
||||
select,
|
||||
textarea,
|
||||
button {
|
||||
font: 14px Roboto, Poppins, "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
line-height: 18px;
|
||||
font: clamp(12px, 2.5vw, 16px) Roboto, Poppins, "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
line-height: 1.3;
|
||||
color: #4d4d4d;
|
||||
}
|
||||
html {
|
||||
@@ -85,8 +85,8 @@ body {
|
||||
margin-top: 30vh;
|
||||
}
|
||||
#content > .wrapper {
|
||||
margin-top: 10px;
|
||||
padding: 15px;
|
||||
margin-top: 1vh;
|
||||
padding: 2vh 2vw;
|
||||
}
|
||||
#modal {
|
||||
position: absolute;
|
||||
@@ -99,56 +99,56 @@ body {
|
||||
overflow-y: auto;
|
||||
}
|
||||
#modal .modal-content {
|
||||
width: 500px;
|
||||
min-height: 160px;
|
||||
margin: 42px auto;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
width: min(500px, 90vw);
|
||||
min-height: 20vh;
|
||||
margin: 5vh auto;
|
||||
padding: 2vh 2vw;
|
||||
border-radius: 0.5vw;
|
||||
background: #dedede;
|
||||
z-index: 110;
|
||||
}
|
||||
#modal .modal-content h2 {
|
||||
margin-bottom: 25px;
|
||||
margin-bottom: 3vh;
|
||||
}
|
||||
#modal .modal-content .modal-close-btn {
|
||||
display: block;
|
||||
float: right;
|
||||
font-size: 24px;
|
||||
font-size: clamp(18px, 4vw, 24px);
|
||||
}
|
||||
#modal .modal-content-wide {
|
||||
width: 800px;
|
||||
width: min(800px, 95vw);
|
||||
min-height: 0px;
|
||||
margin: 42px auto;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
margin: 5vh auto;
|
||||
padding: 2vh 2vw;
|
||||
border-radius: 0.5vw;
|
||||
background: #dedede;
|
||||
z-index: 110;
|
||||
}
|
||||
#modal .modal-content-wide h2 {
|
||||
margin-bottom: 25px;
|
||||
margin-bottom: 3vh;
|
||||
}
|
||||
#modal .modal-content-wide .modal-close-btn {
|
||||
display: block;
|
||||
float: right;
|
||||
font-size: 24px;
|
||||
font-size: clamp(18px, 4vw, 24px);
|
||||
}
|
||||
h1 {
|
||||
font-size: 22px;
|
||||
font-size: clamp(18px, 4vw, 24px);
|
||||
line-height: 1.2em;
|
||||
margin: 0 0 10px;
|
||||
margin: 0 0 1vh;
|
||||
}
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
font-size: clamp(16px, 3.5vw, 20px);
|
||||
line-height: 1.2em;
|
||||
margin: 0 0 9px;
|
||||
margin: 0 0 0.8vh;
|
||||
}
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 16px;
|
||||
font-size: clamp(14px, 3vw, 18px);
|
||||
line-height: 1.25em;
|
||||
margin: 0 0 6px;
|
||||
margin: 0 0 0.6vh;
|
||||
}
|
||||
.quiet,
|
||||
.quiet a {
|
||||
@@ -160,14 +160,14 @@ h6 {
|
||||
}
|
||||
.no-items-message {
|
||||
color: #666;
|
||||
margin: 30px 0;
|
||||
margin: 4vh 0;
|
||||
text-align: center;
|
||||
}
|
||||
.warning {
|
||||
background: #f0ecdb;
|
||||
border-radius: 3px;
|
||||
border-radius: 0.4vw;
|
||||
color: #aa8f09;
|
||||
padding: 6px 8px;
|
||||
padding: 1vh 1.2vw;
|
||||
}
|
||||
.warning a {
|
||||
color: #aa8f09;
|
||||
@@ -194,7 +194,7 @@ strong {
|
||||
p {
|
||||
-webkit-user-select: text;
|
||||
user-select: text;
|
||||
|
||||
|
||||
|
||||
}
|
||||
p a {
|
||||
@@ -203,12 +203,12 @@ p a {
|
||||
}
|
||||
table,
|
||||
p {
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
pre {
|
||||
margin: 15px 0;
|
||||
margin: 2vh 0;
|
||||
white-space: pre;
|
||||
max-height: 516px;
|
||||
max-height: 60vh;
|
||||
}
|
||||
pre,
|
||||
code,
|
||||
@@ -217,10 +217,10 @@ tt {
|
||||
line-height: 1.3em;
|
||||
}
|
||||
blockquote {
|
||||
margin: 8px 0 8px 8px;
|
||||
margin: 1vh 0 1vh 1vw;
|
||||
border-left: 1px solid #ccc;
|
||||
color: #666;
|
||||
padding: 0 0 0 8px;
|
||||
padding: 0 0 0 1vw;
|
||||
}
|
||||
hr {
|
||||
height: 1px;
|
||||
@@ -229,7 +229,7 @@ hr {
|
||||
width: 100%;
|
||||
background: #dbdbdb;
|
||||
color: #dbdbdb;
|
||||
margin: 15px 0;
|
||||
margin: 2vh 0;
|
||||
padding: 0;
|
||||
}
|
||||
table,
|
||||
@@ -241,7 +241,7 @@ th {
|
||||
}
|
||||
td,
|
||||
th {
|
||||
padding: 5px;
|
||||
padding: 0.8vh 0.8vw;
|
||||
border-right: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
@@ -257,20 +257,20 @@ tbody {
|
||||
}
|
||||
dl,
|
||||
dt {
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 1vh;
|
||||
}
|
||||
dd {
|
||||
margin: 0 0 16px 24px;
|
||||
margin: 0 0 2vh 3vw;
|
||||
}
|
||||
kbd {
|
||||
padding: 1px 3px;
|
||||
margin: 3px;
|
||||
padding: 0.2vh 0.5vw;
|
||||
margin: 0.5vh;
|
||||
font-weight: bold;
|
||||
background: #fafafa;
|
||||
border-radius: 3px;
|
||||
border-radius: 0.4vw;
|
||||
border: 1px solid #e6e6e6;
|
||||
color: unset;
|
||||
box-shadow: 0px 2px 3px rgba(0,0,0,0.15);
|
||||
box-shadow: 0px 0.3vh 0.5vh rgba(0,0,0,0.15);
|
||||
}
|
||||
.clear {
|
||||
clear: both;
|
||||
@@ -310,7 +310,7 @@ kbd {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.wrapper {
|
||||
width: calc(100% - 20px);
|
||||
width: calc(100% - 2vw);
|
||||
margin: 0 auto;
|
||||
}
|
||||
.relative {
|
||||
@@ -401,23 +401,23 @@ a:not(.disabled).is-active i.fa {
|
||||
}
|
||||
.big-message {
|
||||
display: block;
|
||||
margin: 75px auto;
|
||||
margin: 10vh auto;
|
||||
text-align: center;
|
||||
max-width: 600px;
|
||||
max-width: min(600px, 90vw);
|
||||
}
|
||||
.big-message h1 {
|
||||
font-size: 26px;
|
||||
margin-bottom: 24px;
|
||||
font-size: clamp(20px, 5vw, 28px);
|
||||
margin-bottom: 3vh;
|
||||
}
|
||||
.big-message p {
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
font-size: clamp(16px, 3.5vw, 20px);
|
||||
line-height: 1.3;
|
||||
}
|
||||
.gutter {
|
||||
margin-left: 38px;
|
||||
margin-left: 5vw;
|
||||
}
|
||||
.viewer {
|
||||
min-height: 18px;
|
||||
min-height: 2.5vh;
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
@@ -427,13 +427,13 @@ a:not(.disabled).is-active i.fa {
|
||||
}
|
||||
.viewer ol {
|
||||
list-style-type: decimal;
|
||||
padding-left: 20px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 3vw;
|
||||
padding-bottom: 1.5vh;
|
||||
}
|
||||
.viewer ul {
|
||||
list-style-type: initial;
|
||||
padding-left: 20px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 3vw;
|
||||
padding-bottom: 1.5vh;
|
||||
}
|
||||
.viewer em {
|
||||
font-style: italic;
|
||||
|
||||
@@ -52,14 +52,6 @@ template(name="userFormsLayout")
|
||||
else
|
||||
// ARIA live region for error messages
|
||||
div#login-error-message(role="alert" aria-live="assertive" style="color: #d32f2f; margin-bottom: 1em;")
|
||||
// Add autocomplete attribute to login input for WCAG compliance
|
||||
script.
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var loginInput = document.querySelector('input[type="text"], input[type="email"]');
|
||||
if (loginInput && loginInput.name && (loginInput.name.toLowerCase().includes('user') || loginInput.name.toLowerCase().includes('email'))) {
|
||||
loginInput.setAttribute('autocomplete', 'username email');
|
||||
}
|
||||
});
|
||||
+Template.dynamic(template=content)
|
||||
if currentSetting.displayAuthenticationMethod
|
||||
+connectionMethod(authenticationMethod=currentSetting.defaultAuthenticationMethod)
|
||||
@@ -71,8 +63,8 @@ template(name="userFormsLayout")
|
||||
if getLegalNoticeWithWritTraduction
|
||||
div
|
||||
div.at-form-lang
|
||||
label(for="userform-set-language-select") {{_ 'choose_language'}}
|
||||
select.select-lang.js-userform-set-language#userform-set-language-select(aria-label="{{_ 'choose_language'}}")
|
||||
label(for="userform-set-language-select") {{_ 'changeLanguagePopup-title'}}
|
||||
select.select-lang.js-userform-set-language#userform-set-language-select(aria-label="{{_ 'changeLanguagePopup-title'}}")
|
||||
each languages
|
||||
if isCurrentLanguage
|
||||
option(value="{{tag}}" selected="selected") {{name}}
|
||||
|
||||
@@ -86,6 +86,12 @@ Template.userFormsLayout.onRendered(() => {
|
||||
validator,
|
||||
);
|
||||
EscapeActions.executeAll();
|
||||
|
||||
// Add autocomplete attribute to login input for WCAG compliance
|
||||
const loginInput = document.querySelector('input[type="text"], input[type="email"]');
|
||||
if (loginInput && loginInput.name && (loginInput.name.toLowerCase().includes('user') || loginInput.name.toLowerCase().includes('email'))) {
|
||||
loginInput.setAttribute('autocomplete', 'username email');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
.my-cards-board-wrapper {
|
||||
border-radius: 0 0 4px 4px;
|
||||
min-width: 400px;
|
||||
margin-bottom: 2rem;
|
||||
border-radius: 0 0 0.5vw 0.5vw;
|
||||
min-width: min(400px, 52vw);
|
||||
margin-bottom: 2.5vh;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
border-width: 2px;
|
||||
border-width: 0.3vw;
|
||||
border-style: solid;
|
||||
border-color: #a2a2a2;
|
||||
}
|
||||
.my-cards-board-title {
|
||||
font-size: 1.4rem;
|
||||
font-size: clamp(1.2rem, 3vw, 1.6rem);
|
||||
font-weight: bold;
|
||||
padding: 0.5rem;
|
||||
padding: 0.7vh 0.7vw;
|
||||
background-color: #808080;
|
||||
color: #fff;
|
||||
}
|
||||
.my-cards-swimlane-title {
|
||||
font-size: 1.1rem;
|
||||
font-size: clamp(1rem, 2.5vw, 1.3rem);
|
||||
font-weight: bold;
|
||||
padding: 0.5rem;
|
||||
padding-bottom: 0.4rem;
|
||||
padding: 0.7vh 0.7vw;
|
||||
padding-bottom: 0.5vh;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-bottom: 0.7vh;
|
||||
text-align: center;
|
||||
}
|
||||
.swimlane-default-color {
|
||||
@@ -29,23 +29,23 @@
|
||||
}
|
||||
.my-cards-list-title {
|
||||
font-weight: bold;
|
||||
font-size: 1.1rem;
|
||||
font-size: clamp(1rem, 2.5vw, 1.3rem);
|
||||
text-align: center;
|
||||
margin-bottom: 0.7rem;
|
||||
margin-bottom: 0.9vh;
|
||||
}
|
||||
.my-cards-list-wrapper {
|
||||
margin: 1rem;
|
||||
border-radius: 5px;
|
||||
margin: 1.3vh 1.3vw;
|
||||
border-radius: 0.7vw;
|
||||
display: inline-grid;
|
||||
min-width: 250px;
|
||||
max-width: 350px;
|
||||
min-width: min(250px, 32vw);
|
||||
max-width: min(350px, 45vw);
|
||||
}
|
||||
.my-cards-card-wrapper {
|
||||
margin-top: 0;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 1.3vh;
|
||||
}
|
||||
.my-cards-dueat-list-wrapper {
|
||||
max-width: 500px;
|
||||
max-width: min(500px, 65vw);
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
.pop-over {
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
border-radius: 0.4vw;
|
||||
border: 1px solid #dbdbdb;
|
||||
border-bottom-color: #c2c2c2;
|
||||
box-shadow: 0 1px 6px rgba(0,0,0,0.3);
|
||||
box-shadow: 0 0.2vh 0.8vh rgba(0,0,0,0.3);
|
||||
position: absolute;
|
||||
width: 300px;
|
||||
width: min(300px, 40vw);
|
||||
z-index: 99999;
|
||||
margin-top: 5px;
|
||||
margin-top: 0.7vh;
|
||||
}
|
||||
.pop-over hr {
|
||||
margin: 4px 0px;
|
||||
margin: 0.5vh 0px;
|
||||
}
|
||||
.pop-over p,
|
||||
.pop-over textarea,
|
||||
@@ -22,27 +22,27 @@
|
||||
}
|
||||
.pop-over select {
|
||||
width: 100%;
|
||||
margin-bottom: 14px;
|
||||
margin-bottom: 1.8vh;
|
||||
}
|
||||
.pop-over textarea {
|
||||
height: 72px;
|
||||
height: 9vh;
|
||||
}
|
||||
.pop-over form a span {
|
||||
padding: 0 0.5rem;
|
||||
padding: 0 0.7vw;
|
||||
}
|
||||
.pop-over .header {
|
||||
height: 36px;
|
||||
height: 4.5vh;
|
||||
position: relative;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 1vh;
|
||||
background: #f7f7f7;
|
||||
border-bottom: 1px solid #dcdcdc;
|
||||
color: #666;
|
||||
}
|
||||
.pop-over .header .header-title {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
padding-top: 4px;
|
||||
margin: 0 10px;
|
||||
line-height: 4vh;
|
||||
padding-top: 0.5vh;
|
||||
margin: 0 1.3vw;
|
||||
font-weight: bold;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -51,18 +51,18 @@
|
||||
.pop-over .header .back-btn {
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
width: 30px;
|
||||
width: 4vw;
|
||||
transition: width 0.2s;
|
||||
}
|
||||
.pop-over .header .back-btn i.fa {
|
||||
margin: 10px;
|
||||
margin-top: 12px;
|
||||
margin: 1.3vw;
|
||||
margin-top: 1.5vh;
|
||||
}
|
||||
.pop-over .header .back-btn.is-hidden {
|
||||
width: 0;
|
||||
}
|
||||
.pop-over .header .close-btn {
|
||||
padding: 10px 10px 10px 4px;
|
||||
padding: 1.3vh 1.3vw 1.3vh 0.5vw;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
@@ -76,23 +76,23 @@
|
||||
}
|
||||
.pop-over .content-container {
|
||||
width: 5000px;
|
||||
max-height: 550px;
|
||||
max-height: 70vh;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.pop-over .content-container .content {
|
||||
width: 280px;
|
||||
padding: 0 10px 10px;
|
||||
width: min(280px, 37vw);
|
||||
padding: 0 1.3vw 1.3vh;
|
||||
float: left;
|
||||
}
|
||||
.pop-over .content-container .content.no-height {
|
||||
height: 20px;
|
||||
height: 2.5vh;
|
||||
}
|
||||
.pop-over .quiet {
|
||||
/* padding: 6px 6px 4px;*/
|
||||
}
|
||||
.pop-over.search-over {
|
||||
background: #f0f0f0;
|
||||
min-height: 114px;
|
||||
min-height: 14vh;
|
||||
}
|
||||
.pop-over.search-over .header {
|
||||
display: none;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#notifications-drawer .notification {
|
||||
display: flex;
|
||||
float: none;
|
||||
padding: 15px 8px 8px;
|
||||
padding: 2vh 1vw 1vh;
|
||||
color: #000;
|
||||
border-bottom: 1px solid #dbdbdb;
|
||||
}
|
||||
@@ -12,18 +12,18 @@
|
||||
display: none;
|
||||
}
|
||||
#notifications-drawer .notification .read-status {
|
||||
width: 30px;
|
||||
padding: 0px 10px 0px 0px;
|
||||
width: 4vw;
|
||||
padding: 0 1.3vw 0 0;
|
||||
}
|
||||
#notifications-drawer .notification .read-status input {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
width: 3vw;
|
||||
height: 3vw;
|
||||
}
|
||||
#notifications-drawer .notification .read-status .activity-type {
|
||||
margin: 16px 0 0;
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
font-size: 17px;
|
||||
margin: 2vh 0 0;
|
||||
width: 2.2vw;
|
||||
height: 2.2vw;
|
||||
font-size: clamp(14px, 2.5vw, 17px);
|
||||
display: block;
|
||||
color: #bbb;
|
||||
}
|
||||
@@ -32,20 +32,20 @@
|
||||
padding: 0px;
|
||||
}
|
||||
#notifications-drawer .notification .details .activity a.member svg {
|
||||
padding: 3px;
|
||||
padding: 0.4vw;
|
||||
}
|
||||
#notifications-drawer .notification .details .activity .activity-desc {
|
||||
margin: 0px 0px 0px 5px;
|
||||
margin: 0 0 0 0.7vw;
|
||||
}
|
||||
#notifications-drawer .notification .details .activity .activity-comment {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
border-radius: 0.4vw;
|
||||
background: #fff;
|
||||
text-decoration: none;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||
margin-top: 5px;
|
||||
padding: 5px;
|
||||
box-shadow: 0 0.2vh 0.3vh rgba(0,0,0,0.2);
|
||||
margin-top: 0.7vh;
|
||||
padding: 0.7vh 0.7vw;
|
||||
}
|
||||
#notifications-drawer .notification .details .activity .activity-meta {
|
||||
display: block;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.rules-list {
|
||||
overflow: hidden;
|
||||
overflow-y: scroll;
|
||||
max-height: 400px;
|
||||
padding-right: 5px;
|
||||
max-height: 50vh;
|
||||
padding-right: 0.7vw;
|
||||
}
|
||||
.rules-lists-item {
|
||||
display: block;
|
||||
@@ -33,14 +33,14 @@
|
||||
.rules-add {
|
||||
display: block;
|
||||
overflow: auto;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 5px;
|
||||
margin-top: 2vh;
|
||||
margin-bottom: 0.7vh;
|
||||
}
|
||||
.rules-add input {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
margin: auto;
|
||||
margin-right: 10px;
|
||||
margin-right: 1.3vw;
|
||||
}
|
||||
.rules-add button {
|
||||
display: inline-block;
|
||||
|
||||
@@ -1269,23 +1269,30 @@ Template.settingsUserPopup.events({
|
||||
},
|
||||
'click #deleteButton'(event) {
|
||||
event.preventDefault();
|
||||
Users.remove(this.userId);
|
||||
/*
|
||||
// Delete user is enabled, but you should remove user from all boards
|
||||
// before deleting user, because there is possibility of leaving empty user avatars
|
||||
// to boards. You can remove non-existing user ids manually from database,
|
||||
// if that happens.
|
||||
//. See:
|
||||
// - wekan/client/components/settings/peopleBody.jade deleteButton
|
||||
// - wekan/client/components/settings/peopleBody.js deleteButton
|
||||
// - wekan/client/components/sidebar/sidebar.js Popup.afterConfirm('removeMember'
|
||||
// that does now remove member from board, card members and assignees correctly,
|
||||
// but that should be used to remove user from all boards similarly
|
||||
// - wekan/models/users.js Delete is not enabled
|
||||
//
|
||||
//
|
||||
*/
|
||||
Popup.back();
|
||||
|
||||
// Use secure server method instead of direct client-side removal
|
||||
Meteor.call('removeUser', this.userId, (error, result) => {
|
||||
if (error) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.error('Error removing user:', error);
|
||||
}
|
||||
// Show error message to user
|
||||
if (error.error === 'not-authorized') {
|
||||
alert('You are not authorized to delete this user.');
|
||||
} else if (error.error === 'user-not-found') {
|
||||
alert('User not found.');
|
||||
} else if (error.error === 'not-authorized' && error.reason === 'Cannot delete the last administrator') {
|
||||
alert('Cannot delete the last administrator.');
|
||||
} else {
|
||||
alert('Error deleting user: ' + error.reason);
|
||||
}
|
||||
} else {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('User deleted successfully:', result);
|
||||
}
|
||||
Popup.back();
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -17,34 +17,34 @@
|
||||
position: absolute;
|
||||
}
|
||||
.setting-content .content-title {
|
||||
font-size: 20px;
|
||||
font-size: clamp(16px, 3.5vw, 22px);
|
||||
}
|
||||
.setting-content .content-body {
|
||||
display: flex;
|
||||
padding-top: 15px;
|
||||
padding-top: 2vh;
|
||||
height: 100%;
|
||||
gap: 10px;
|
||||
gap: 1.3vw;
|
||||
}
|
||||
.setting-content .content-body .side-menu {
|
||||
background-color: #f7f7f7;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 4px;
|
||||
width: 250px;
|
||||
box-shadow: inset -1px -1px 3px rgba(0,0,0,0.05);
|
||||
border-radius: 0.5vw;
|
||||
width: min(250px, 32vw);
|
||||
box-shadow: inset -0.2vh -0.2vh 0.4vh rgba(0,0,0,0.05);
|
||||
}
|
||||
.setting-content .content-body .side-menu ul li {
|
||||
margin: 0.1rem 0.2rem;
|
||||
margin: 0.2vh 0.3vw;
|
||||
}
|
||||
.setting-content .content-body .side-menu ul li.active {
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
|
||||
box-shadow: 0 0.2vh 0.3vh rgba(0,0,0,0.15);
|
||||
}
|
||||
.setting-content .content-body .side-menu ul li:hover {
|
||||
background: #fff;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
|
||||
box-shadow: 0 0.2vh 0.3vh rgba(0,0,0,0.15);
|
||||
}
|
||||
.setting-content .content-body .side-menu ul li a {
|
||||
padding: 1rem 0 1rem 1rem;
|
||||
padding: 1.3vh 0 1.3vh 1.3vw;
|
||||
width: 95%;
|
||||
}
|
||||
.setting-content .content-body .side-menu ul li a span {
|
||||
|
||||
@@ -652,6 +652,7 @@ template(name="addMemberPopup")
|
||||
p.quiet {{_ 'no-results'}}
|
||||
button.js-email-invite.primary.full {{_ 'email-invite'}}
|
||||
|
||||
|
||||
template(name="changePermissionsPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
|
||||
@@ -1948,3 +1948,4 @@ Template.changePermissionsPopup.helpers({
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
font-size: 50%;
|
||||
color: #a6a6a6;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 100px;
|
||||
top: 0.7vh;
|
||||
left: 13vw;
|
||||
}
|
||||
.swimlane-header-menu .swimlane-header-collapse-up {
|
||||
font-size: 50%;
|
||||
color: #a6a6a6;
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 100px;
|
||||
bottom: 0.7vh;
|
||||
left: 13vw;
|
||||
}
|
||||
.swimlane-header-menu .swimlane-header-uncollapse-up {
|
||||
font-size: 50%;
|
||||
@@ -35,10 +35,10 @@
|
||||
background-color: rgba(0,0,0,0.2);
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
height: 100px;
|
||||
height: 15vh;
|
||||
}
|
||||
.swimlane.ui-sortable-helper {
|
||||
box-shadow: -2px 2px 8px rgba(0,0,0,0.3), 0 0 1px rgba(0,0,0,0.5);
|
||||
box-shadow: -0.3vw 0.3vh 1vh rgba(0,0,0,0.3), 0 0 0.1vw rgba(0,0,0,0.5);
|
||||
transform: rotate(2deg);
|
||||
cursor: grabbing;
|
||||
}
|
||||
@@ -50,12 +50,17 @@
|
||||
flex-direction: row;
|
||||
flex: 1 0 100%;
|
||||
background-color: #ccc;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: 33px;
|
||||
}
|
||||
.swimlane .swimlane-header-wrap .swimlane-header {
|
||||
font-size: 14px;
|
||||
padding: 5px 5px;
|
||||
font-weight: bold;
|
||||
min-height: 9px;
|
||||
min-height: 33px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
-o-text-overflow: ellipsis;
|
||||
@@ -86,9 +91,12 @@
|
||||
position: absolute;
|
||||
padding: 7px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 230px;
|
||||
font-size: 18px;
|
||||
font-size: clamp(16px, 3vw, 20px);
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.swimlane .swimlane-header-wrap .swimlane-header-miniscreen-handle {
|
||||
position: absolute;
|
||||
|
||||
@@ -63,7 +63,7 @@ function initSortable(boardComponent, $listsDom) {
|
||||
};
|
||||
|
||||
$listsDom.sortable({
|
||||
connectWith: '.board-canvas',
|
||||
connectWith: '.js-swimlane, .js-lists',
|
||||
tolerance: 'pointer',
|
||||
helper: 'clone',
|
||||
items: '.js-list:not(.js-list-composer)',
|
||||
@@ -82,10 +82,31 @@ function initSortable(boardComponent, $listsDom) {
|
||||
const nextListDom = ui.item.next('.js-list').get(0);
|
||||
const sortIndex = calculateIndex(prevListDom, nextListDom, 1);
|
||||
|
||||
$listsDom.sortable('cancel');
|
||||
const listDomElement = ui.item.get(0);
|
||||
const list = Blaze.getData(listDomElement);
|
||||
|
||||
// Detect if the list was dropped in a different swimlane
|
||||
const targetSwimlaneDom = ui.item.closest('.js-swimlane');
|
||||
let targetSwimlaneId = null;
|
||||
|
||||
if (targetSwimlaneDom.length > 0) {
|
||||
// List was dropped in a swimlane
|
||||
targetSwimlaneId = targetSwimlaneDom.attr('id').replace('swimlane-', '');
|
||||
} else {
|
||||
// List was dropped in lists view (not swimlanes view)
|
||||
// In this case, assign to the default swimlane
|
||||
const currentBoard = ReactiveCache.getBoard(Session.get('currentBoard'));
|
||||
if (currentBoard) {
|
||||
const defaultSwimlane = currentBoard.getDefaultSwimline();
|
||||
if (defaultSwimlane) {
|
||||
targetSwimlaneId = defaultSwimlane._id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the original swimlane ID of the list
|
||||
const originalSwimlaneId = list.swimlaneId;
|
||||
|
||||
/*
|
||||
Reverted incomplete change list width,
|
||||
removed from below Lists.update:
|
||||
@@ -95,10 +116,44 @@ function initSortable(boardComponent, $listsDom) {
|
||||
height: list._id.height(),
|
||||
*/
|
||||
|
||||
// Prepare update object
|
||||
const updateData = {
|
||||
sort: sortIndex.base,
|
||||
};
|
||||
|
||||
// Check if the list was dropped in a different swimlane
|
||||
const isDifferentSwimlane = targetSwimlaneId && targetSwimlaneId !== originalSwimlaneId;
|
||||
|
||||
// If the list was dropped in a different swimlane, update the swimlaneId
|
||||
if (isDifferentSwimlane) {
|
||||
updateData.swimlaneId = targetSwimlaneId;
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`Moving list "${list.title}" from swimlane ${originalSwimlaneId} to swimlane ${targetSwimlaneId}`);
|
||||
}
|
||||
|
||||
// Move all cards in the list to the new swimlane
|
||||
const cardsInList = ReactiveCache.getCards({
|
||||
listId: list._id,
|
||||
archived: false
|
||||
});
|
||||
|
||||
cardsInList.forEach(card => {
|
||||
card.move(list.boardId, targetSwimlaneId, list._id);
|
||||
});
|
||||
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`Moved ${cardsInList.length} cards to swimlane ${targetSwimlaneId}`);
|
||||
}
|
||||
|
||||
// Don't cancel the sortable when moving to a different swimlane
|
||||
// The DOM move should be allowed to complete
|
||||
} else {
|
||||
// If staying in the same swimlane, cancel the sortable to prevent DOM manipulation issues
|
||||
$listsDom.sortable('cancel');
|
||||
}
|
||||
|
||||
Lists.update(list._id, {
|
||||
$set: {
|
||||
sort: sortIndex.base,
|
||||
},
|
||||
$set: updateData,
|
||||
});
|
||||
|
||||
boardComponent.setIsDragging(false);
|
||||
@@ -109,10 +164,12 @@ function initSortable(boardComponent, $listsDom) {
|
||||
if (Utils.isTouchScreenOrShowDesktopDragHandles()) {
|
||||
$listsDom.sortable({
|
||||
handle: '.js-list-handle',
|
||||
connectWith: '.js-swimlane, .js-lists',
|
||||
});
|
||||
} else {
|
||||
$listsDom.sortable({
|
||||
handle: '.js-list-header',
|
||||
connectWith: '.js-swimlane, .js-lists',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -228,7 +285,7 @@ BlazeComponent.extendComponent({
|
||||
const user = ReactiveCache.getCurrentUser();
|
||||
const swimlane = Template.currentData();
|
||||
const height = user.getSwimlaneHeight(swimlane.boardId, swimlane._id);
|
||||
return height == -1 ? "auto" : (height + "px");
|
||||
return height == -1 ? "auto" : (height + 5 + "px");
|
||||
},
|
||||
}).register('swimlane');
|
||||
|
||||
@@ -281,7 +338,7 @@ BlazeComponent.extendComponent({
|
||||
boardId: Session.get('currentBoard'),
|
||||
sort: sortIndex,
|
||||
type: this.isListTemplatesSwimlane ? 'template-list' : 'list',
|
||||
swimlaneId: this.currentBoard.isTemplatesBoard() ? this.currentSwimlane._id : '',
|
||||
swimlaneId: this.currentSwimlane._id, // Always set swimlaneId for per-swimlane list titles
|
||||
});
|
||||
|
||||
titleInput.value = '';
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
.auth-layout .at-form-landing-logo {
|
||||
width: 249px;
|
||||
width: min(249px, 32vw);
|
||||
margin: auto;
|
||||
margin-top: 50px;
|
||||
margin-bottom: 20px;
|
||||
margin-top: 6vh;
|
||||
margin-bottom: 2.5vh;
|
||||
}
|
||||
.auth-layout .auth-dialog {
|
||||
width: 275px;
|
||||
padding: 25px;
|
||||
width: min(275px, 36vw);
|
||||
padding: 3vh 3vw;
|
||||
margin: auto;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 2.5vh;
|
||||
background: #fff;
|
||||
border-radius: 3px;
|
||||
border-radius: 0.4vw;
|
||||
border: 1px solid #dbdbdb;
|
||||
border-bottom-color: #c2c2c2;
|
||||
box-shadow: 0 1px 6px rgba(0,0,0,0.3);
|
||||
box-shadow: 0 0.2vh 0.8vh rgba(0,0,0,0.3);
|
||||
}
|
||||
.auth-layout .auth-dialog .at-form .at-link {
|
||||
color: #17683a;
|
||||
}
|
||||
.auth-layout .auth-dialog .at-form label {
|
||||
margin-bottom: 3px;
|
||||
margin-bottom: 0.4vh;
|
||||
}
|
||||
.auth-layout .auth-dialog .at-form input {
|
||||
width: 100%;
|
||||
@@ -31,9 +31,9 @@
|
||||
}
|
||||
.auth-layout .auth-dialog .at-form .at-title {
|
||||
background: #f7f7f7;
|
||||
margin: -25px;
|
||||
padding: 15px 25px 5px;
|
||||
margin-bottom: 20px;
|
||||
margin: -3vh -3vw;
|
||||
padding: 2vh 3vw 0.7vh;
|
||||
margin-bottom: 2.5vh;
|
||||
border-bottom: 1px solid #dcdcdc;
|
||||
color: #4d4d4d;
|
||||
font-weight: bold;
|
||||
@@ -42,7 +42,7 @@
|
||||
.auth-layout .auth-dialog .at-form .at-signin-link,
|
||||
.auth-layout .auth-dialog .at-form .at-forgotPwd {
|
||||
font-size: 0.9em;
|
||||
margin-top: 15px;
|
||||
margin-top: 2vh;
|
||||
color: #4d4d4d;
|
||||
}
|
||||
.auth-layout .auth-dialog .at-form .at-signup-link .at-signUp,
|
||||
|
||||
@@ -241,8 +241,21 @@ Template.editProfilePopup.events({
|
||||
},
|
||||
'click #deleteButton': Popup.afterConfirm('userDelete', function() {
|
||||
Popup.back();
|
||||
Users.remove(Meteor.userId());
|
||||
AccountsTemplates.logout();
|
||||
|
||||
// Use secure server method for self-deletion
|
||||
Meteor.call('removeUser', Meteor.userId(), (error, result) => {
|
||||
if (error) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.error('Error removing user:', error);
|
||||
}
|
||||
alert('Error deleting account: ' + error.reason);
|
||||
} else {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('User deleted successfully:', result);
|
||||
}
|
||||
AccountsTemplates.logout();
|
||||
}
|
||||
});
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
// Centralized secure DOMPurify configuration to prevent XSS and CSS injection attacks
|
||||
export function getSecureDOMPurifyConfig() {
|
||||
return {
|
||||
// Block dangerous elements that can cause XSS and CSS injection
|
||||
FORBID_TAGS: [
|
||||
'svg', 'defs', 'use', 'g', 'symbol', 'marker', 'pattern', 'mask', 'clipPath',
|
||||
'linearGradient', 'radialGradient', 'stop', 'animate', 'animateTransform',
|
||||
'animateMotion', 'set', 'switch', 'foreignObject', 'script', 'style', 'link',
|
||||
'meta', 'iframe', 'object', 'embed', 'applet', 'form', 'input', 'textarea',
|
||||
'select', 'option', 'button', 'label', 'fieldset', 'legend', 'frameset',
|
||||
'frame', 'noframes', 'base', 'basefont', 'isindex', 'dir', 'menu', 'menuitem'
|
||||
],
|
||||
// Block dangerous attributes that can cause XSS and CSS injection
|
||||
FORBID_ATTR: [
|
||||
'xlink:href', 'href', 'onload', 'onerror', 'onclick', 'onmouseover',
|
||||
'onfocus', 'onblur', 'onchange', 'onsubmit', 'onreset', 'onselect',
|
||||
'onunload', 'onresize', 'onscroll', 'onkeydown', 'onkeyup', 'onkeypress',
|
||||
'onmousedown', 'onmouseup', 'onmouseover', 'onmouseout', 'onmousemove',
|
||||
'ondblclick', 'oncontextmenu', 'onwheel', 'ontouchstart', 'ontouchend',
|
||||
'ontouchmove', 'ontouchcancel', 'onabort', 'oncanplay', 'oncanplaythrough',
|
||||
'ondurationchange', 'onemptied', 'onended', 'onerror', 'onloadeddata',
|
||||
'onloadedmetadata', 'onloadstart', 'onpause', 'onplay', 'onplaying',
|
||||
'onprogress', 'onratechange', 'onseeked', 'onseeking', 'onstalled',
|
||||
'onsuspend', 'ontimeupdate', 'onvolumechange', 'onwaiting', 'onbeforeunload',
|
||||
'onhashchange', 'onpagehide', 'onpageshow', 'onpopstate', 'onstorage',
|
||||
'onunload', 'style', 'class', 'id', 'data-*', 'aria-*'
|
||||
],
|
||||
// Allow only safe image formats and protocols
|
||||
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i,
|
||||
// Remove dangerous protocols
|
||||
ALLOW_UNKNOWN_PROTOCOLS: false,
|
||||
// Sanitize URLs to prevent malicious content loading
|
||||
SANITIZE_DOM: true,
|
||||
// Remove dangerous elements completely
|
||||
KEEP_CONTENT: false,
|
||||
// Additional security measures
|
||||
ADD_ATTR: [],
|
||||
// Block data URIs that could contain malicious content
|
||||
ALLOW_DATA_ATTR: false,
|
||||
// Custom hook to further sanitize content
|
||||
HOOKS: {
|
||||
uponSanitizeElement: function(node, data) {
|
||||
// Block any remaining dangerous elements
|
||||
const dangerousTags = ['svg', 'style', 'script', 'link', 'meta', 'iframe', 'object', 'embed', 'applet'];
|
||||
if (node.tagName && dangerousTags.includes(node.tagName.toLowerCase())) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked potentially dangerous element:', node.tagName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Block img tags with SVG data URIs
|
||||
if (node.tagName && node.tagName.toLowerCase() === 'img') {
|
||||
const src = node.getAttribute('src');
|
||||
if (src && (src.startsWith('data:image/svg') || src.endsWith('.svg'))) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked potentially malicious SVG image:', src);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Block elements with dangerous attributes
|
||||
const dangerousAttrs = ['style', 'onload', 'onerror', 'onclick', 'onmouseover', 'onfocus', 'onblur'];
|
||||
for (const attr of dangerousAttrs) {
|
||||
if (node.hasAttribute && node.hasAttribute(attr)) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked element with dangerous attribute:', node.tagName, attr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
uponSanitizeAttribute: function(node, data) {
|
||||
// Block style attributes completely
|
||||
if (data.attrName === 'style') {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked style attribute');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Block class and id attributes that might be used for CSS injection
|
||||
if (data.attrName === 'class' || data.attrName === 'id') {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked class/id attribute:', data.attrName, data.attrValue);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Block data attributes
|
||||
if (data.attrName && data.attrName.startsWith('data-')) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.warn('Blocked data attribute:', data.attrName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Convenience function for secure sanitization
|
||||
export function sanitizeHTML(html) {
|
||||
return DOMPurify.sanitize(html, getSecureDOMPurifyConfig());
|
||||
}
|
||||
|
||||
// Convenience function for sanitizing text (no HTML)
|
||||
export function sanitizeText(text) {
|
||||
return DOMPurify.sanitize(text, {
|
||||
ALLOWED_TAGS: [],
|
||||
ALLOWED_ATTR: [],
|
||||
KEEP_CONTENT: true
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
import { ReactiveVar } from 'meteor/reactive-var';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
|
||||
/**
|
||||
* Global upload progress manager for drag-and-drop file uploads
|
||||
* Tracks upload progress across all cards and provides reactive data
|
||||
*/
|
||||
class UploadProgressManager {
|
||||
constructor() {
|
||||
// Map of cardId -> array of upload objects
|
||||
this.cardUploads = new ReactiveVar(new Map());
|
||||
|
||||
// Map of uploadId -> upload object for easy lookup
|
||||
this.uploadMap = new ReactiveVar(new Map());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new upload to track
|
||||
* @param {string} cardId - The card ID
|
||||
* @param {Object} uploader - The uploader object from Attachments.insert
|
||||
* @param {File} file - The file being uploaded
|
||||
* @returns {string} uploadId - Unique identifier for this upload
|
||||
*/
|
||||
addUpload(cardId, uploader, file) {
|
||||
const uploadId = `upload_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
|
||||
const upload = {
|
||||
id: uploadId,
|
||||
cardId: cardId,
|
||||
file: file,
|
||||
uploader: uploader,
|
||||
progress: new ReactiveVar(0),
|
||||
status: new ReactiveVar('uploading'), // 'uploading', 'completed', 'error'
|
||||
error: new ReactiveVar(null),
|
||||
startTime: Date.now(),
|
||||
endTime: null
|
||||
};
|
||||
|
||||
// Update card uploads
|
||||
const currentCardUploads = this.cardUploads.get();
|
||||
const cardUploads = currentCardUploads.get(cardId) || [];
|
||||
cardUploads.push(upload);
|
||||
currentCardUploads.set(cardId, cardUploads);
|
||||
this.cardUploads.set(currentCardUploads);
|
||||
|
||||
// Update upload map
|
||||
const currentUploadMap = this.uploadMap.get();
|
||||
currentUploadMap.set(uploadId, upload);
|
||||
this.uploadMap.set(currentUploadMap);
|
||||
|
||||
// Set up uploader event listeners
|
||||
uploader.on('progress', (progress) => {
|
||||
upload.progress.set(progress);
|
||||
});
|
||||
|
||||
uploader.on('uploaded', (error, fileRef) => {
|
||||
upload.status.set(error ? 'error' : 'completed');
|
||||
upload.endTime = Date.now();
|
||||
upload.error.set(error);
|
||||
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`Upload ${uploadId} completed:`, error ? 'error' : 'success');
|
||||
}
|
||||
|
||||
// Remove from tracking after a delay to show completion
|
||||
setTimeout(() => {
|
||||
this.removeUpload(uploadId);
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
uploader.on('error', (error) => {
|
||||
upload.status.set('error');
|
||||
upload.endTime = Date.now();
|
||||
upload.error.set(error);
|
||||
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`Upload ${uploadId} failed:`, error);
|
||||
}
|
||||
|
||||
// Remove from tracking after a delay to show error
|
||||
setTimeout(() => {
|
||||
this.removeUpload(uploadId);
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`Added upload ${uploadId} for card ${cardId}: ${file.name}`);
|
||||
}
|
||||
|
||||
return uploadId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an upload from tracking
|
||||
* @param {string} uploadId - The upload ID to remove
|
||||
*/
|
||||
removeUpload(uploadId) {
|
||||
const upload = this.uploadMap.get().get(uploadId);
|
||||
if (!upload) return;
|
||||
|
||||
const cardId = upload.cardId;
|
||||
|
||||
// Remove from card uploads
|
||||
const currentCardUploads = this.cardUploads.get();
|
||||
const cardUploads = currentCardUploads.get(cardId) || [];
|
||||
const filteredCardUploads = cardUploads.filter(u => u.id !== uploadId);
|
||||
|
||||
if (filteredCardUploads.length === 0) {
|
||||
currentCardUploads.delete(cardId);
|
||||
} else {
|
||||
currentCardUploads.set(cardId, filteredCardUploads);
|
||||
}
|
||||
this.cardUploads.set(currentCardUploads);
|
||||
|
||||
// Remove from upload map
|
||||
const currentUploadMap = this.uploadMap.get();
|
||||
currentUploadMap.delete(uploadId);
|
||||
this.uploadMap.set(currentUploadMap);
|
||||
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`Removed upload ${uploadId} from tracking`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all uploads for a specific card
|
||||
* @param {string} cardId - The card ID
|
||||
* @returns {Array} Array of upload objects
|
||||
*/
|
||||
getUploadsForCard(cardId) {
|
||||
return this.cardUploads.get().get(cardId) || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get upload count for a specific card
|
||||
* @param {string} cardId - The card ID
|
||||
* @returns {number} Number of active uploads
|
||||
*/
|
||||
getUploadCountForCard(cardId) {
|
||||
return this.getUploadsForCard(cardId).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a card has any active uploads
|
||||
* @param {string} cardId - The card ID
|
||||
* @returns {boolean} True if card has active uploads
|
||||
*/
|
||||
hasActiveUploads(cardId) {
|
||||
return this.getUploadCountForCard(cardId) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all uploads across all cards
|
||||
* @returns {Array} Array of all upload objects
|
||||
*/
|
||||
getAllUploads() {
|
||||
const allUploads = [];
|
||||
this.cardUploads.get().forEach(cardUploads => {
|
||||
allUploads.push(...cardUploads);
|
||||
});
|
||||
return allUploads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all uploads (useful for cleanup)
|
||||
*/
|
||||
clearAllUploads() {
|
||||
this.cardUploads.set(new Map());
|
||||
this.uploadMap.set(new Map());
|
||||
}
|
||||
}
|
||||
|
||||
// Create global instance
|
||||
const uploadProgressManager = new UploadProgressManager();
|
||||
|
||||
export default uploadProgressManager;
|
||||
|
||||
+187
-10
@@ -51,6 +51,146 @@ Utils = {
|
||||
const ret = ReactiveCache.getCard(cardId);
|
||||
return ret;
|
||||
},
|
||||
|
||||
// Zoom and mobile mode utilities
|
||||
getZoomLevel() {
|
||||
const user = ReactiveCache.getCurrentUser();
|
||||
if (user && user.profile && user.profile.zoomLevel !== undefined) {
|
||||
return user.profile.zoomLevel;
|
||||
}
|
||||
// For non-logged-in users, check localStorage
|
||||
const stored = localStorage.getItem('wekan-zoom-level');
|
||||
return stored ? parseFloat(stored) : 1.0;
|
||||
},
|
||||
|
||||
setZoomLevel(level) {
|
||||
const user = ReactiveCache.getCurrentUser();
|
||||
if (user) {
|
||||
// Update user profile
|
||||
user.setZoomLevel(level);
|
||||
} else {
|
||||
// Store in localStorage for non-logged-in users
|
||||
localStorage.setItem('wekan-zoom-level', level.toString());
|
||||
}
|
||||
Utils.applyZoomLevel(level);
|
||||
|
||||
// Trigger reactive updates for UI components
|
||||
Session.set('wekan-zoom-level', level);
|
||||
},
|
||||
|
||||
getMobileMode() {
|
||||
const user = ReactiveCache.getCurrentUser();
|
||||
if (user && user.profile && user.profile.mobileMode !== undefined) {
|
||||
return user.profile.mobileMode;
|
||||
}
|
||||
// For non-logged-in users, check localStorage
|
||||
const stored = localStorage.getItem('wekan-mobile-mode');
|
||||
return stored ? stored === 'true' : false;
|
||||
},
|
||||
|
||||
setMobileMode(enabled) {
|
||||
const user = ReactiveCache.getCurrentUser();
|
||||
if (user) {
|
||||
// Update user profile
|
||||
user.setMobileMode(enabled);
|
||||
} else {
|
||||
// Store in localStorage for non-logged-in users
|
||||
localStorage.setItem('wekan-mobile-mode', enabled.toString());
|
||||
}
|
||||
Utils.applyMobileMode(enabled);
|
||||
// Trigger reactive updates for UI components
|
||||
Session.set('wekan-mobile-mode', enabled);
|
||||
},
|
||||
|
||||
applyZoomLevel(level) {
|
||||
const boardWrapper = document.querySelector('.board-wrapper');
|
||||
const body = document.body;
|
||||
const isMobileMode = body.classList.contains('mobile-mode');
|
||||
|
||||
if (boardWrapper) {
|
||||
if (isMobileMode) {
|
||||
// On mobile mode, only apply zoom to text and icons, not the entire layout
|
||||
// Remove any existing transform from board-wrapper
|
||||
boardWrapper.style.transform = '';
|
||||
boardWrapper.style.transformOrigin = '';
|
||||
|
||||
// Apply zoom to text and icon elements instead
|
||||
const textElements = boardWrapper.querySelectorAll('h1, h2, h3, h4, h5, h6, p, span, div, .minicard, .list-header-name, .board-header-btn, .fa, .icon');
|
||||
textElements.forEach(element => {
|
||||
element.style.transform = `scale(${level})`;
|
||||
element.style.transformOrigin = 'center';
|
||||
});
|
||||
|
||||
// Reset board-canvas height
|
||||
const boardCanvas = document.querySelector('.board-canvas');
|
||||
if (boardCanvas) {
|
||||
boardCanvas.style.height = '';
|
||||
}
|
||||
} else {
|
||||
// Desktop mode: apply zoom to entire board-wrapper as before
|
||||
boardWrapper.style.transform = `scale(${level})`;
|
||||
boardWrapper.style.transformOrigin = 'top left';
|
||||
|
||||
// If zoom is 50% or lower, make board wrapper full width like content
|
||||
if (level <= 0.5) {
|
||||
boardWrapper.style.width = '100%';
|
||||
boardWrapper.style.maxWidth = '100%';
|
||||
boardWrapper.style.margin = '0';
|
||||
} else {
|
||||
// Reset to normal width for higher zoom levels
|
||||
boardWrapper.style.width = '';
|
||||
boardWrapper.style.maxWidth = '';
|
||||
boardWrapper.style.margin = '';
|
||||
}
|
||||
|
||||
// Adjust container height to prevent scroll issues
|
||||
const boardCanvas = document.querySelector('.board-canvas');
|
||||
if (boardCanvas) {
|
||||
boardCanvas.style.height = `${100 / level}%`;
|
||||
|
||||
// For high zoom levels (200%+), enable both horizontal and vertical scrolling
|
||||
if (level >= 2.0) {
|
||||
boardCanvas.style.overflowX = 'auto';
|
||||
boardCanvas.style.overflowY = 'auto';
|
||||
// Ensure the content area can scroll both horizontally and vertically
|
||||
const content = document.querySelector('#content');
|
||||
if (content) {
|
||||
content.style.overflowX = 'auto';
|
||||
content.style.overflowY = 'auto';
|
||||
}
|
||||
} else {
|
||||
// Reset overflow for normal zoom levels
|
||||
boardCanvas.style.overflowX = '';
|
||||
boardCanvas.style.overflowY = '';
|
||||
const content = document.querySelector('#content');
|
||||
if (content) {
|
||||
content.style.overflowX = '';
|
||||
content.style.overflowY = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
applyMobileMode(enabled) {
|
||||
const body = document.body;
|
||||
if (enabled) {
|
||||
body.classList.add('mobile-mode');
|
||||
body.classList.remove('desktop-mode');
|
||||
} else {
|
||||
body.classList.add('desktop-mode');
|
||||
body.classList.remove('mobile-mode');
|
||||
}
|
||||
},
|
||||
|
||||
initializeUserSettings() {
|
||||
// Apply saved settings on page load
|
||||
const zoomLevel = Utils.getZoomLevel();
|
||||
const mobileMode = Utils.getMobileMode();
|
||||
Utils.applyZoomLevel(zoomLevel);
|
||||
Utils.applyMobileMode(mobileMode);
|
||||
},
|
||||
getCurrentList() {
|
||||
const listId = this.getCurrentListId();
|
||||
let ret = null;
|
||||
@@ -287,22 +427,50 @@ Utils = {
|
||||
},
|
||||
|
||||
windowResizeDep: new Tracker.Dependency(),
|
||||
|
||||
// in fact, what we really care is screen size
|
||||
// large mobile device like iPad or android Pad has a big screen, it should also behave like a desktop
|
||||
// in a small window (even on desktop), Wekan run in compact mode.
|
||||
// we can easily debug with a small window of desktop browser. :-)
|
||||
isMiniScreen() {
|
||||
// OLD WINDOW WIDTH DETECTION:
|
||||
this.windowResizeDep.depend();
|
||||
return $(window).width() <= 800;
|
||||
// Show mobile view when:
|
||||
// 1. Screen width is 800px or less (matches CSS media queries)
|
||||
// 2. Mobile phones in portrait mode
|
||||
// 3. iPad in very small screens (≤ 600px)
|
||||
const isSmallScreen = window.innerWidth <= 800;
|
||||
const isVerySmallScreen = window.innerWidth <= 600;
|
||||
const isPortrait = window.innerWidth < window.innerHeight || window.matchMedia("(orientation: portrait)").matches;
|
||||
const isMobilePhone = /Mobile|Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) && !/iPad/i.test(navigator.userAgent);
|
||||
const isIPhone = /iPhone|iPod/i.test(navigator.userAgent);
|
||||
const isIPad = /iPad/i.test(navigator.userAgent);
|
||||
const isUbuntuTouch = /Ubuntu/i.test(navigator.userAgent);
|
||||
|
||||
// For iPhone: always show mobile view regardless of orientation
|
||||
// For other mobile phones: show mobile view in portrait, desktop view in landscape
|
||||
// For iPad: show mobile view only in very small screens (≤ 600px)
|
||||
// For Ubuntu Touch: smartphones behave like mobile phones, tablets like iPad
|
||||
// For desktop: show mobile view when screen width <= 800px
|
||||
if (isIPhone) {
|
||||
return true; // iPhone: always mobile view
|
||||
} else if (isMobilePhone) {
|
||||
return isPortrait; // Other mobile phones: portrait = mobile, landscape = desktop
|
||||
} else if (isIPad) {
|
||||
return isVerySmallScreen; // iPad: only very small screens get mobile view
|
||||
} else if (isUbuntuTouch) {
|
||||
// Ubuntu Touch: smartphones (≤ 600px) behave like mobile phones, tablets (> 600px) like iPad
|
||||
if (isVerySmallScreen) {
|
||||
return isPortrait; // Ubuntu Touch smartphone: portrait = mobile, landscape = desktop
|
||||
} else {
|
||||
return isVerySmallScreen; // Ubuntu Touch tablet: only very small screens get mobile view
|
||||
}
|
||||
} else {
|
||||
return isSmallScreen; // Desktop: based on 800px screen width
|
||||
}
|
||||
},
|
||||
|
||||
isTouchScreen() {
|
||||
|
||||
// NEW TOUCH DEVICE DETECTION:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
|
||||
|
||||
var hasTouchScreen = false;
|
||||
if ("maxTouchPoints" in navigator) {
|
||||
hasTouchScreen = navigator.maxTouchPoints > 0;
|
||||
@@ -328,12 +496,19 @@ Utils = {
|
||||
|
||||
// returns if desktop drag handles are enabled
|
||||
isShowDesktopDragHandles() {
|
||||
//const currentUser = ReactiveCache.getCurrentUser();
|
||||
//if (currentUser) {
|
||||
// return (currentUser.profile || {}).showDesktopDragHandles;
|
||||
//} else if (window.localStorage.getItem('showDesktopDragHandles')) {
|
||||
if (this.isTouchScreen()) {
|
||||
return true;
|
||||
/*
|
||||
const currentUser = ReactiveCache.getCurrentUser();
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).showDesktopDragHandles;
|
||||
} else if (window.localStorage.getItem('showDesktopDragHandles')) {
|
||||
//
|
||||
if (window.localStorage.getItem('showDesktopDragHandles')) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
*/
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -341,8 +516,10 @@ Utils = {
|
||||
|
||||
// returns if mini screen or desktop drag handles
|
||||
isTouchScreenOrShowDesktopDragHandles() {
|
||||
// Always enable drag handles for mobile screens (touch devices)
|
||||
return this.isTouchScreen() || this.isMiniScreen();
|
||||
//return this.isTouchScreen() || this.isShowDesktopDragHandles();
|
||||
return this.isShowDesktopDragHandles();
|
||||
//return this.isShowDesktopDragHandles();
|
||||
},
|
||||
|
||||
calculateIndexData(prevData, nextData, nItems = 1) {
|
||||
|
||||
@@ -163,9 +163,12 @@ services:
|
||||
# ap-southeast-1,ap-northeast-1,sa-east-1
|
||||
#
|
||||
#- S3='{"s3":{"key": "xxx", "secret": "xxx", "bucket": "xxx", "region": "xxx"}}'
|
||||
#- S3_SECRET_FILE=/run/secrets/s3_secret
|
||||
#-----------------------------------------------------------------
|
||||
# ==== MONGO_URL ====
|
||||
- MONGO_URL=mongodb://wekandb:27017/wekan
|
||||
#- MONGO_URL=mongodb://username:password@wekandb:27017/wekan
|
||||
#- MONGO_PASSWORD_FILE=/run/secrets/mongo_password
|
||||
#---------------------------------------------------------------
|
||||
# ==== ROOT_URL SETTING ====
|
||||
# Change ROOT_URL to your real Wekan URL, for example:
|
||||
@@ -194,6 +197,7 @@ services:
|
||||
#- MAIL_SERVICE=Outlook365
|
||||
#- MAIL_SERVICE_USER=firstname.lastname@hotmail.com
|
||||
#- MAIL_SERVICE_PASSWORD=SecretPassword
|
||||
#- MAIL_SERVICE_PASSWORD_FILE=/run/secrets/mail_service_password
|
||||
#---------------------------------------------------------------
|
||||
# https://github.com/wekan/wekan/issues/3585#issuecomment-1021522132
|
||||
# Add more Node heap, this is done by default at Dockerfile:
|
||||
@@ -397,6 +401,7 @@ services:
|
||||
#- OAUTH2_CLIENT_ID=xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
|
||||
# Secret key generated during app registration:
|
||||
#- OAUTH2_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
#- OAUTH2_SECRET_FILE=/run/secrets/oauth2_secret
|
||||
#- OAUTH2_SERVER_URL=https://login.microsoftonline.com/
|
||||
#- OAUTH2_AUTH_ENDPOINT=/oauth2/v2.0/authorize
|
||||
#- OAUTH2_USERINFO_ENDPOINT=https://graph.microsoft.com/oidc/userinfo
|
||||
@@ -423,6 +428,7 @@ services:
|
||||
#- OAUTH2_CLIENT_ID=xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
|
||||
# Secret key generated during app registration:
|
||||
#- OAUTH2_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
#- OAUTH2_SECRET_FILE=/run/secrets/oauth2_secret
|
||||
#- OAUTH2_SERVER_URL=https://your-nextcloud.tld
|
||||
#- OAUTH2_AUTH_ENDPOINT=/index.php/apps/oauth2/authorize
|
||||
#- OAUTH2_USERINFO_ENDPOINT=/ocs/v2.php/cloud/user?format=json
|
||||
@@ -447,6 +453,7 @@ services:
|
||||
#- OAUTH2_USERINFO_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/userinfo
|
||||
#- OAUTH2_TOKEN_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/token
|
||||
#- OAUTH2_SECRET=<keycloak client secret>
|
||||
#- OAUTH2_SECRET_FILE=/run/secrets/oauth2_secret
|
||||
#- OAUTH2_ID_MAP=sub
|
||||
#- OAUTH2_USERNAME_MAP=preferred_username
|
||||
#- OAUTH2_EMAIL_MAP=email
|
||||
@@ -464,6 +471,7 @@ services:
|
||||
#- OAUTH2_CLIENT_ID=abcde12345
|
||||
# OAuth2 Secret.
|
||||
#- OAUTH2_SECRET=54321abcde
|
||||
#- OAUTH2_SECRET_FILE=/run/secrets/oauth2_secret
|
||||
# OAuth2 Server URL.
|
||||
#- OAUTH2_SERVER_URL=https://chat.example.com
|
||||
# OAuth2 Authorization Endpoint.
|
||||
@@ -570,6 +578,7 @@ services:
|
||||
#
|
||||
# The password for the search user
|
||||
#- LDAP_AUTHENTIFICATION_PASSWORD=pwd
|
||||
#- LDAP_AUTHENTIFICATION_PASSWORD_FILE=/run/secrets/ldap_auth_password
|
||||
#
|
||||
# Enable logs for the module
|
||||
#- LDAP_LOG_ENABLED=true
|
||||
@@ -725,6 +734,12 @@ services:
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- wekan-files:/data:rw
|
||||
secrets:
|
||||
- ldap_auth_password
|
||||
- oauth2_secret
|
||||
- mail_service_password
|
||||
- mongo_password
|
||||
- s3_secret
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# ==== OPTIONAL: SHARE DATABASE TO OFFICE LAN AND REMOTE VPN ====
|
||||
@@ -786,3 +801,19 @@ volumes:
|
||||
networks:
|
||||
wekan-tier:
|
||||
driver: bridge
|
||||
|
||||
# Docker Compose Secrets
|
||||
# Create secret files on the host system before running docker-compose up
|
||||
# Example: echo "your_password_here" > ldap_auth_password.txt
|
||||
# Then use: docker-compose up -d
|
||||
secrets:
|
||||
ldap_auth_password:
|
||||
file: ./secrets/ldap_auth_password.txt
|
||||
oauth2_secret:
|
||||
file: ./secrets/oauth2_secret.txt
|
||||
mail_service_password:
|
||||
file: ./secrets/mail_service_password.txt
|
||||
mongo_password:
|
||||
file: ./secrets/mongo_password.txt
|
||||
s3_secret:
|
||||
file: ./secrets/s3_secret.txt
|
||||
@@ -167,9 +167,12 @@ services:
|
||||
# ap-southeast-1,ap-northeast-1,sa-east-1
|
||||
#
|
||||
#- S3='{"s3":{"key": "xxx", "secret": "xxx", "bucket": "xxx", "region": "xxx"}}'
|
||||
#- S3_SECRET_FILE=/run/secrets/s3_secret
|
||||
#-----------------------------------------------------------------
|
||||
# ==== MONGO_URL ====
|
||||
- MONGO_URL=mongodb://wekandb:27017/wekan
|
||||
#- MONGO_URL=mongodb://username:password@wekandb:27017/wekan
|
||||
#- MONGO_PASSWORD_FILE=/run/secrets/mongo_password
|
||||
#---------------------------------------------------------------
|
||||
# ==== ROOT_URL SETTING ====
|
||||
# Change ROOT_URL to your real Wekan URL, for example:
|
||||
@@ -198,6 +201,7 @@ services:
|
||||
#- MAIL_SERVICE=Outlook365
|
||||
#- MAIL_SERVICE_USER=firstname.lastname@hotmail.com
|
||||
#- MAIL_SERVICE_PASSWORD=SecretPassword
|
||||
#- MAIL_SERVICE_PASSWORD_FILE=/run/secrets/mail_service_password
|
||||
#---------------------------------------------------------------
|
||||
# https://github.com/wekan/wekan/issues/3585#issuecomment-1021522132
|
||||
# Add more Node heap, this is done by default at Dockerfile:
|
||||
@@ -399,6 +403,7 @@ services:
|
||||
#- OAUTH2_CLIENT_ID=xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
|
||||
# Secret key generated during app registration:
|
||||
#- OAUTH2_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
#- OAUTH2_SECRET_FILE=/run/secrets/oauth2_secret
|
||||
#- OAUTH2_SERVER_URL=https://login.microsoftonline.com/
|
||||
#- OAUTH2_AUTH_ENDPOINT=/oauth2/v2.0/authorize
|
||||
#- OAUTH2_USERINFO_ENDPOINT=https://graph.microsoft.com/oidc/userinfo
|
||||
@@ -425,6 +430,7 @@ services:
|
||||
#- OAUTH2_CLIENT_ID=xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
|
||||
# Secret key generated during app registration:
|
||||
#- OAUTH2_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
#- OAUTH2_SECRET_FILE=/run/secrets/oauth2_secret
|
||||
#- OAUTH2_SERVER_URL=https://your-nextcloud.tld
|
||||
#- OAUTH2_AUTH_ENDPOINT=/index.php/apps/oauth2/authorize
|
||||
#- OAUTH2_USERINFO_ENDPOINT=/ocs/v2.php/cloud/user?format=json
|
||||
@@ -449,6 +455,7 @@ services:
|
||||
#- OAUTH2_USERINFO_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/userinfo
|
||||
#- OAUTH2_TOKEN_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/token
|
||||
#- OAUTH2_SECRET=<keycloak client secret>
|
||||
#- OAUTH2_SECRET_FILE=/run/secrets/oauth2_secret
|
||||
#-----------------------------------------------------------------
|
||||
# ==== OAUTH2 DOORKEEPER ====
|
||||
# https://github.com/wekan/wekan/issues/1874
|
||||
@@ -462,6 +469,7 @@ services:
|
||||
#- OAUTH2_CLIENT_ID=abcde12345
|
||||
# OAuth2 Secret.
|
||||
#- OAUTH2_SECRET=54321abcde
|
||||
#- OAUTH2_SECRET_FILE=/run/secrets/oauth2_secret
|
||||
# OAuth2 Server URL.
|
||||
#- OAUTH2_SERVER_URL=https://chat.example.com
|
||||
# OAuth2 Authorization Endpoint.
|
||||
@@ -568,6 +576,7 @@ services:
|
||||
#
|
||||
# The password for the search user
|
||||
#- LDAP_AUTHENTIFICATION_PASSWORD=pwd
|
||||
#- LDAP_AUTHENTIFICATION_PASSWORD_FILE=/run/secrets/ldap_auth_password
|
||||
#
|
||||
# Enable logs for the module
|
||||
#- LDAP_LOG_ENABLED=true
|
||||
@@ -723,6 +732,12 @@ services:
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- wekan-files:/data:rw
|
||||
secrets:
|
||||
- ldap_auth_password
|
||||
- oauth2_secret
|
||||
- mail_service_password
|
||||
- mongo_password
|
||||
- s3_secret
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# ==== OPTIONAL: SHARE DATABASE TO OFFICE LAN AND REMOTE VPN ====
|
||||
@@ -784,3 +799,19 @@ volumes:
|
||||
networks:
|
||||
wekan-tier:
|
||||
driver: bridge
|
||||
|
||||
# Docker Compose Secrets
|
||||
# Create secret files on the host system before running docker-compose up
|
||||
# Example: echo "your_password_here" > ldap_auth_password.txt
|
||||
# Then use: docker-compose up -d
|
||||
secrets:
|
||||
ldap_auth_password:
|
||||
file: ./secrets/ldap_auth_password.txt
|
||||
oauth2_secret:
|
||||
file: ./secrets/oauth2_secret.txt
|
||||
mail_service_password:
|
||||
file: ./secrets/mail_service_password.txt
|
||||
mongo_password:
|
||||
file: ./secrets/mongo_password.txt
|
||||
s3_secret:
|
||||
file: ./secrets/s3_secret.txt
|
||||
@@ -0,0 +1,169 @@
|
||||
# Attachment Backward Compatibility
|
||||
|
||||
This document describes the backward compatibility implementation for Wekan attachments, allowing the system to read attachments from both the old CollectionFS structure (Wekan v6.09 and earlier) and the new Meteor-Files structure (Wekan v7.x and later).
|
||||
|
||||
## Overview
|
||||
|
||||
When Wekan migrated from CollectionFS to Meteor-Files (ostrio-files), the database structure for attachments changed significantly. This backward compatibility layer ensures that:
|
||||
|
||||
1. Old attachments can still be accessed and downloaded
|
||||
2. No database migration is required
|
||||
3. Both old and new attachments can coexist
|
||||
4. The UI works seamlessly with both structures
|
||||
|
||||
## Database Structure Changes
|
||||
|
||||
### Old Structure (CollectionFS)
|
||||
- **CollectionFS Files**: `cfs_gridfs.attachments.files`
|
||||
- **CollectionFS Records**: `cfs.attachments.filerecord`
|
||||
- **File Storage**: GridFS with bucket name `cfs_gridfs.attachments`
|
||||
|
||||
### New Structure (Meteor-Files)
|
||||
- **Files Collection**: `attachments`
|
||||
- **File Storage**: Configurable (Filesystem, GridFS, or S3)
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Files Added/Modified
|
||||
|
||||
1. **`models/lib/attachmentBackwardCompatibility.js`**
|
||||
- Main backward compatibility layer
|
||||
- Handles reading from old CollectionFS structure
|
||||
- Converts old data format to new format
|
||||
- Provides GridFS streaming for downloads
|
||||
|
||||
2. **`models/attachments.js`**
|
||||
- Added backward compatibility methods to Attachments collection
|
||||
- Imports compatibility functions
|
||||
|
||||
3. **`imports/reactiveCache.js`**
|
||||
- Updated to use backward compatibility layer
|
||||
- Falls back to old structure when new structure has no results
|
||||
|
||||
4. **`server/routes/legacyAttachments.js`**
|
||||
- Handles legacy attachment downloads via `/cfs/files/attachments/:id`
|
||||
- Provides proper HTTP headers and streaming
|
||||
|
||||
5. **`server/migrations/migrateAttachments.js`**
|
||||
- Migration methods for converting old attachments to new structure
|
||||
- Optional migration tools for users who want to fully migrate
|
||||
|
||||
### Key Functions
|
||||
|
||||
#### `getAttachmentWithBackwardCompatibility(attachmentId)`
|
||||
- Tries new structure first, falls back to old structure
|
||||
- Returns attachment data in new format
|
||||
- Handles both single attachment lookups
|
||||
|
||||
#### `getAttachmentsWithBackwardCompatibility(query)`
|
||||
- Queries both old and new structures
|
||||
- Combines and deduplicates results
|
||||
- Used for card attachment lists
|
||||
|
||||
#### `getOldAttachmentData(attachmentId)`
|
||||
- Reads from old CollectionFS structure
|
||||
- Converts old format to new format
|
||||
- Handles file type detection and metadata
|
||||
|
||||
#### `getOldAttachmentStream(attachmentId)`
|
||||
- Creates GridFS download stream for old attachments
|
||||
- Used for file downloads
|
||||
|
||||
## Usage
|
||||
|
||||
### Automatic Fallback
|
||||
The system automatically falls back to the old structure when:
|
||||
- An attachment is not found in the new structure
|
||||
- Querying attachments for a card returns no results
|
||||
|
||||
### Legacy Download URLs
|
||||
Old attachment download URLs (`/cfs/files/attachments/:id`) continue to work and are handled by the legacy route.
|
||||
|
||||
### Migration (Optional)
|
||||
Users can optionally migrate their old attachments to the new structure using the migration methods:
|
||||
|
||||
```javascript
|
||||
// Migrate a single attachment
|
||||
Meteor.call('migrateAttachment', attachmentId);
|
||||
|
||||
// Migrate all attachments for a card
|
||||
Meteor.call('migrateCardAttachments', cardId);
|
||||
|
||||
// Check migration status
|
||||
Meteor.call('getAttachmentMigrationStatus', cardId);
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
1. **Query Optimization**: The system queries the new structure first, only falling back to old structure when necessary
|
||||
2. **Caching**: ReactiveCache handles caching for both old and new attachments
|
||||
3. **Streaming**: Large files are streamed efficiently using GridFS streams
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Graceful fallback when old structure is not available
|
||||
- Proper error logging for debugging
|
||||
- HTTP error codes for download failures
|
||||
- Permission checks for both old and new attachments
|
||||
|
||||
## Security
|
||||
|
||||
- Permission checks are maintained for both old and new attachments
|
||||
- Board access rules apply to legacy attachments
|
||||
- File type validation is preserved
|
||||
|
||||
## Testing
|
||||
|
||||
To test the backward compatibility:
|
||||
|
||||
1. Ensure you have old Wekan v6.09 data with attachments
|
||||
2. Upgrade to Wekan v7.x
|
||||
3. Verify that old attachments are visible in the UI
|
||||
4. Test downloading old attachments
|
||||
5. Verify that new attachments work normally
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Old attachments not showing**
|
||||
- Check that old CollectionFS collections exist in database
|
||||
- Verify GridFS bucket is accessible
|
||||
- Check server logs for errors
|
||||
|
||||
2. **Download failures**
|
||||
- Verify GridFS connection
|
||||
- Check file permissions
|
||||
- Ensure legacy route is loaded
|
||||
|
||||
3. **Performance issues**
|
||||
- Consider migrating old attachments to new structure
|
||||
- Check database indexes
|
||||
- Monitor query performance
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable debug logging by setting:
|
||||
```javascript
|
||||
console.log('Legacy attachments route loaded');
|
||||
```
|
||||
|
||||
This will help identify if the backward compatibility layer is properly loaded.
|
||||
|
||||
## Future Considerations
|
||||
|
||||
- The backward compatibility layer can be removed in future versions
|
||||
- Users should be encouraged to migrate old attachments
|
||||
- Consider adding migration tools to the admin interface
|
||||
- Monitor usage of old vs new structures
|
||||
|
||||
## Migration Path
|
||||
|
||||
For users who want to fully migrate to the new structure:
|
||||
|
||||
1. Use the migration methods to convert old attachments
|
||||
2. Verify all attachments are working
|
||||
3. Remove old CollectionFS collections (optional)
|
||||
4. Update any hardcoded URLs to use new structure
|
||||
|
||||
The backward compatibility layer ensures that migration is optional and can be done gradually.
|
||||
@@ -10,7 +10,7 @@ This is without container (without Docker or Snap).
|
||||
|
||||
Right click and download files 1-4:
|
||||
|
||||
1. [wekan-7.96-amd64-windows.zip](https://github.com/wekan/wekan/releases/download/v7.96/wekan-7.96-amd64-windows.zip)
|
||||
1. [wekan-7.99-amd64-windows.zip](https://github.com/wekan/wekan/releases/download/v7.99/wekan-7.99-amd64-windows.zip)
|
||||
|
||||
2. [node.exe](https://nodejs.org/dist/latest-v14.x/win-x64/node.exe)
|
||||
|
||||
@@ -22,7 +22,7 @@ Right click and download files 1-4:
|
||||
|
||||
6. Double click `mongodb-windows-x86_64-7.0.25-signed.msi` . In installer, uncheck downloading MongoDB compass.
|
||||
|
||||
7. Unzip `wekan-7.96-amd64-windows.zip` , inside it is directory `bundle`, to it copy other files:
|
||||
7. Unzip `wekan-7.99-amd64-windows.zip` , inside it is directory `bundle`, to it copy other files:
|
||||
|
||||
```
|
||||
bundle (directory)
|
||||
|
||||
+16
-1
@@ -4,5 +4,20 @@ import { TAPi18n } from './tap';
|
||||
Blaze.registerHelper('_', (...args) => {
|
||||
const { hash } = args.pop();
|
||||
const [key] = args.splice(0, 1);
|
||||
return TAPi18n.__(key, { ...hash, sprintf: args });
|
||||
|
||||
// If TAPi18n is not initialized yet, return the key as fallback
|
||||
if (!TAPi18n.i18n) {
|
||||
return key;
|
||||
}
|
||||
|
||||
const translation = TAPi18n.__(key, { ...hash, sprintf: args });
|
||||
|
||||
// If translation is the same as key (meaning not found), return a formatted version
|
||||
if (translation === key) {
|
||||
return key.split('-').map(word =>
|
||||
word.charAt(0).toUpperCase() + word.slice(1)
|
||||
).join(' ');
|
||||
}
|
||||
|
||||
return translation;
|
||||
});
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "عرض اللوحات",
|
||||
"boards": "لوحات",
|
||||
"board-view": "عرض اللوحات",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "التقويم",
|
||||
"board-view-swimlanes": "خطوط السباحة",
|
||||
"board-view-collapse": "انهيار",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Изглед на таблото",
|
||||
"boards": "Табла",
|
||||
"board-view": "Изглед на таблото",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Календар",
|
||||
"board-view-swimlanes": "Коридори",
|
||||
"board-view-collapse": "Събери",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Visió del tauler",
|
||||
"boards": "Taulers",
|
||||
"board-view": "Visió del tauler",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendari",
|
||||
"board-view-swimlanes": "Carrils",
|
||||
"board-view-collapse": "Contraure",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Náhled tabla",
|
||||
"boards": "Tabla",
|
||||
"board-view": "Náhled tabla",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Kalendář",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Sbalit",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Náhled tabla",
|
||||
"boards": "Tabla",
|
||||
"board-view": "Náhled tabla",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Kalendář",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Sbalit",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Tavlevisning",
|
||||
"boards": "Tavler",
|
||||
"board-view": "Tavlevisning",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Kalender",
|
||||
"board-view-swimlanes": "Svømmebaner",
|
||||
"board-view-collapse": "Sammenfold",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Boardansicht",
|
||||
"boards": "Boards",
|
||||
"board-view": "Boardansicht",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Kalender",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Einklappen",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Boardansicht",
|
||||
"boards": "Boards",
|
||||
"board-view": "Boardansicht",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Kalender",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Einklappen",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Boardansicht",
|
||||
"boards": "Boards",
|
||||
"board-view": "Boardansicht",
|
||||
"desktop-mode": "Desktop Modus",
|
||||
"mobile-mode": "Mobil Modus",
|
||||
"mobile-desktop-toggle": "Wechseln zwischen Mobil und Desktop Modus",
|
||||
"zoom-in": "Zoom vergrößern",
|
||||
"zoom-out": "Zoom verkleinern",
|
||||
"click-to-change-zoom": "Klicken um die Zoom Stufe zu ändern",
|
||||
"zoom-level": "Zoom Stufe",
|
||||
"enter-zoom-level": "Eingabe Zoom Stufe (50-300%):",
|
||||
"board-view-cal": "Kalender",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Einklappen",
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
"archive": "Ins Archiv verschieben",
|
||||
"archive-all": "Alles ins Archiv verschieben",
|
||||
"archive-board": "Board ins Archiv verschieben",
|
||||
"archive-board-confirm": "Are you sure you want to archive this board?",
|
||||
"archive-board-confirm": "Wollen Sie das Board wirklich archivieren?",
|
||||
"archive-card": "Karte ins Archiv verschieben",
|
||||
"archive-list": "Liste ins Archiv verschieben",
|
||||
"archive-swimlane": "Swimlane ins Archiv verschieben",
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Boardansicht",
|
||||
"boards": "Boards",
|
||||
"board-view": "Boardansicht",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Vergrößern",
|
||||
"zoom-out": "Verkleinern",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Kalender",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Einklappen",
|
||||
@@ -897,7 +905,7 @@
|
||||
"oidc-button-text": "Benutzerdefinierter Text der OIDC-Schaltfläche",
|
||||
"default-authentication-method": "Standardauthentifizierungsverfahren",
|
||||
"duplicate-board": "Board duplizieren",
|
||||
"duplicate-board-confirm": "Are you sure you want to duplicate this board?",
|
||||
"duplicate-board-confirm": "Wollen Sie das Board wirklich duplizieren?",
|
||||
"org-number": "Die Anzahl der Organisationen ist:",
|
||||
"team-number": "Die Anzahl der Teams ist:",
|
||||
"people-number": "Die Anzahl der Personen ist:",
|
||||
@@ -1268,37 +1276,37 @@
|
||||
"hideAllChecklistItems": "Verberge alle Checklisteneinträge",
|
||||
"support": "Unterstützung",
|
||||
"supportPopup-title": "Unterstützung",
|
||||
"accessibility": "Accessibility",
|
||||
"accessibility": "Bedienungshilfe",
|
||||
"accessibility-page-enabled": "Barrierefreie Seite freigeschaltet",
|
||||
"accessibility-info-not-added-yet": "Accessibility info has not been added yet",
|
||||
"accessibility-title": "Accessibility title",
|
||||
"accessibility-info-not-added-yet": "Es wurde noch keine Information zur Bedienungshilfe hinzugefügt",
|
||||
"accessibility-title": "Bedienungshilfe Titel",
|
||||
"accessibility-content": "Barrierefreier Eintrag",
|
||||
"accounts-lockout-settings": "Brute Force Protection Settings",
|
||||
"accounts-lockout-info": "These settings control how login attempts are protected against brute force attacks.",
|
||||
"accounts-lockout-known-users": "Settings for known users (correct username, wrong password)",
|
||||
"accounts-lockout-unknown-users": "Settings for unknown users (non-existent username)",
|
||||
"accounts-lockout-failures-before": "Failures before lockout",
|
||||
"accounts-lockout-period": "Lockout period (seconds)",
|
||||
"accounts-lockout-failures-before": "Fehler vor einer Sperrung",
|
||||
"accounts-lockout-period": "Dauer der Sperrung (Sekunden)",
|
||||
"accounts-lockout-failure-window": "Failure window (seconds)",
|
||||
"accounts-lockout-settings-updated": "Brute force protection settings have been updated",
|
||||
"accounts-lockout-locked-users": "Locked Users",
|
||||
"accounts-lockout-locked-users-info": "Users currently locked out due to too many failed login attempts",
|
||||
"accounts-lockout-no-locked-users": "There are currently no locked users",
|
||||
"accounts-lockout-failed-attempts": "Failed Attempts",
|
||||
"accounts-lockout-remaining-time": "Remaining Time",
|
||||
"accounts-lockout-user-unlocked": "User has been unlocked successfully",
|
||||
"accounts-lockout-confirm-unlock": "Are you sure you want to unlock this user?",
|
||||
"accounts-lockout-locked-users": "Gesperrte Benutzer",
|
||||
"accounts-lockout-locked-users-info": "Kürzlich gesperrte Benutzer aufgrund von zu vielen fehlerhaften Logins",
|
||||
"accounts-lockout-no-locked-users": "Es gibt aktuell keine gesperrten Benutzer",
|
||||
"accounts-lockout-failed-attempts": "Fehlversuche",
|
||||
"accounts-lockout-remaining-time": "Verbleibende Zeit",
|
||||
"accounts-lockout-user-unlocked": "Benutzer wurde erfolgreich entsperrt",
|
||||
"accounts-lockout-confirm-unlock": "Wollen Sie den Benutzer wirklich entsperren?",
|
||||
"accounts-lockout-confirm-unlock-all": "Are you sure you want to unlock all locked users?",
|
||||
"accounts-lockout-show-locked-users": "Show locked users only",
|
||||
"accounts-lockout-user-locked": "User is locked",
|
||||
"accounts-lockout-click-to-unlock": "Click to unlock this user",
|
||||
"accounts-lockout-user-locked": "Benutzer ist gesperrt",
|
||||
"accounts-lockout-click-to-unlock": "Klicken Sie, um den Benutzer zu entsperren",
|
||||
"accounts-lockout-status": "Status",
|
||||
"admin-people-filter-show": "Show:",
|
||||
"admin-people-filter-all": "alle Benutzer",
|
||||
"admin-people-filter-locked": "Locked Users Only",
|
||||
"admin-people-filter-active": "Aktiv",
|
||||
"admin-people-filter-inactive": "Not Active",
|
||||
"admin-people-active-status": "Active Status",
|
||||
"admin-people-active-status": "Aktiv Status",
|
||||
"admin-people-user-active": "User is active - click to deactivate",
|
||||
"admin-people-user-inactive": "User is inactive - click to activate",
|
||||
"accounts-lockout-all-users-unlocked": "All locked users have been unlocked",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Προβολή Πίνακα",
|
||||
"boards": "Πίνακες",
|
||||
"board-view": "Προβολή Πίνακα",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Ημερολόγιο",
|
||||
"board-view-swimlanes": "Λωρίδες",
|
||||
"board-view-collapse": "Σύμπτυξη",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Προβολή Πίνακα",
|
||||
"boards": "Πίνακες",
|
||||
"board-view": "Προβολή Πίνακα",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Ημερολόγιο",
|
||||
"board-view-swimlanes": "Λωρίδες",
|
||||
"board-view-collapse": "Σύμπτυξη",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
@@ -623,6 +631,9 @@
|
||||
"upload": "Upload",
|
||||
"upload-avatar": "Upload an avatar",
|
||||
"uploaded-avatar": "Uploaded an avatar",
|
||||
"uploading-files": "Uploading files",
|
||||
"upload-failed": "Upload failed",
|
||||
"upload-completed": "Upload completed",
|
||||
"custom-top-left-corner-logo-image-url": "Custom Top Left Corner Logo Image URL",
|
||||
"custom-top-left-corner-logo-link-url": "Custom Top Left Corner Logo Link URL",
|
||||
"custom-top-left-corner-logo-height": "Custom Top Left Corner Logo Height. Default: 27",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
@@ -177,6 +177,14 @@
|
||||
"boardChangeViewPopup-title": "Board View",
|
||||
"boards": "Boards",
|
||||
"board-view": "Board View",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"zoom-in": "Zoom In",
|
||||
"zoom-out": "Zoom Out",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Collapse",
|
||||
|
||||
Loaded 100 of 251 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user