summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJannis M. Hoffmann <jannis@fehcom.de>2023-08-17 11:36:55 +0200
committerJannis M. Hoffmann <jannis@fehcom.de>2023-08-17 11:36:55 +0200
commit1229bb6a838e96eb52be7aa1cac8d692746bc783 (patch)
tree20a337622a62e43f9ac4baf6d609de5d3891cb84
parent97d10a54426d2df2de1c765948989dfc88a316eb (diff)
convert to bulma css framework
-rw-r--r--css/style.css145
-rw-r--r--lang/de.lang52
-rw-r--r--lang/en.lang52
-rw-r--r--lang/i18n.pod87
-rw-r--r--lib/JWebmail/Plugin/Paginate.pm4
-rw-r--r--lib/JWebmail/View/RenderMail.pm6
-rw-r--r--package-lock.json378
-rw-r--r--package.json20
-rw-r--r--scss/my_bulma.scss46
-rw-r--r--src/displayheaders.js35
-rw-r--r--templates/displayheaders/_bot_nav.html.ep53
-rw-r--r--templates/displayheaders/_folders.html.ep49
-rw-r--r--templates/displayheaders/_main_table.html.ep115
-rw-r--r--templates/displayheaders/_pagination1.html.ep12
-rw-r--r--templates/displayheaders/_pagination3.html.ep10
-rw-r--r--templates/displayheaders/_top_nav.html.ep71
-rw-r--r--templates/layouts/mainlayout.html.ep22
-rw-r--r--templates/not_found.html.ep25
-rw-r--r--templates/not_found.production.html.ep16
-rw-r--r--templates/webmail/about.html.ep14
-rw-r--r--templates/webmail/displayheaders.html.ep8
-rw-r--r--templates/webmail/login.html.ep67
-rw-r--r--templates/webmail/readmail.html.ep6
-rw-r--r--templates/webmail/writemail.html.ep95
24 files changed, 779 insertions, 609 deletions
diff --git a/css/style.css b/css/style.css
deleted file mode 100644
index fe26d46..0000000
--- a/css/style.css
+++ /dev/null
@@ -1,145 +0,0 @@
-@import "purecss/build/pure.css";
-@import "purecss/build/grids-responsive.css";
-
-:root {
- --jwm-color-back: #eee;
- --jwm-color-front: #ddd;
- --jwm-color-alt: #dede95;
-}
-
-body {
- padding: 1rem;
-}
-
-a {
- text-decoration-line: none;
-}
-
-a:hover {
- text-decoration-line: underline;
-}
-
-footer {
- text-align: center;
- margin-top: 2rem;
-}
-
-.pagination-box {
- list-style: none;
- padding-left: 0px;
- display: flex;
-}
- .pagination-box > li > a, .pagination-box > li > span {
- border: 1px solid blue;
- text-decoration: none;
- padding: 0.5em;
- display: block;
- margin-left: -1px;
- background-color: white;
- }
- .pagination-box > li > a:hover {
- background-color: #eee;
- }
- .pagination-box > li > a.disabled {
- pointer-events: none;
- cursor: default;
- background-color: var(--jwm-color-back);
- }
- .pagination-box > li > a.current {
- pointer-events: none;
- cursor: default;
- background-color: lightblue;
- }
-
-.jwm-base {
- background-color: var(--jwm-color-back);
- border-radius: 5px;
- max-width: 960px;
- margin: 0 auto;
- padding: 1rem;
-}
-
- .jwm-base > nav {
- margin-top: 1rem;
- }
-
-.jwm-warning {
- background-color: orange;
- padding: 1rem;
-}
-
-.jwm-post {
- background-color: var(--jwm-color-front);
- border-radius: 5px;
- padding: 0.5rem 1rem;
-}
-
-.jwm-nav {
- background-color: var(--jwm-color-back);
- border-radius: 5px;
- padding: 0 1rem;
- margin: 10px 0;
-}
-
-.jwm-mail-header {
- background-color: var(--jwm-color-front);
- padding: 1rem;
-}
-
-.jwm-mail-body {
- width: 90%;
- margin: 1rem auto;
- padding: 10px;
-}
-
-iframe.jwm-mail-body-text-html {
- width: 100%;
- height: 400px;
-}
-
-.jwm-mail-body-text-plain {
- background-color: var(--jwm-color-alt);
- /* word-wrap: break-word; */
- padding: 5pt;
-}
-
- .jwm-mail-body-text-plain > pre {
- font-family: sans-serif;
- overflow: auto;
- }
-
-/* make sure this lines up with pure-md class */
-@media screen and (max-width: 48em) {
- .hide-small {
- display: none;
- }
-}
-
-#displayheaders {
- max-width: 1280px;
- margin: 0 auto;
- padding: 1rem;
-}
-
- #mail-headers {
- width: 100%;
- margin: 15px 0;
- }
-
- #empty-folder {
- text-align: center;
- }
-
-#login {
- max-width: 640px;
-}
-
- #login > h1 {
- text-align: center;
- }
-
- #login > form {
- background-color: var(--jwm-color-front);
- padding-top: 1rem;
- padding-left: 6px;
- }
diff --git a/lang/de.lang b/lang/de.lang
deleted file mode 100644
index c508854..0000000
--- a/lang/de.lang
+++ /dev/null
@@ -1,52 +0,0 @@
-login = anmelden
-userid = nuzerkennung
-passwd = passwort
-failed = fehlgeschlagen
-about = über
-mbox_size = Mailboxgröße
-and = und
-subject = betreff
-version = version
-from = von
-to = für
-cc = CC
-date = datum
-size = größe
-content-type = inhaltsart
-send_to = senden an
-answer_to = Antworten gehen an
-content = inhalt
-check_all = alle markieren
-move = verschieben
-nr = nummer
-status = mehrteilig
-logout = abmelden
-compose = schreiben
-search = suche
-of = von
-messages = nachrichten
-new = neu
-mbox_size = mailboxgröße
-home = Übersicht
-no = nein
-yes = ja
-page = seite
-next = nächste
-last = letzte
-first = erste
-previous = vorherige
-sender = gesendet von
-back = zurück
-
-# Mailboxen
-Queue = Warteschlange
-Drafts = Vorlagen
-Home = Wurzelverzeichnis
-
-# Fehler
-no_session = Keine aktive Sitzung.
-no_folder = Dieses Verzeichnis gibt es nicht.
-error_send = Die Nachricht konnte nicht gesendet werden.
-succ_send = Die Nachricht wurde verschikt.
-succ_move = Nachrichten wurden verschoben.
-empty_folder = Dies Verzeichnis ist leer.
diff --git a/lang/en.lang b/lang/en.lang
deleted file mode 100644
index 6d0d360..0000000
--- a/lang/en.lang
+++ /dev/null
@@ -1,52 +0,0 @@
-messages = messages
-from = from
-to = to
-cc = cc
-
-failed = failed
-search = search
-move = move
-and = and
-content-type = content-type
-send_to = send to
-answer_to = answer to
-content = content
-check_all = check all
-nr = number
-mbox_size = Mailbox size
-about = about
-version = version
-first = first
-previous = previous
-next = next
-last = last
-yes = yes
-no = no
-userid = user-id
-passwd = password
-login = login
-of = of
-new = new
-compose = compose
-logout = logout
-page = page
-status = multipart
-date = date
-sender = sender
-subject = subject
-size = size
-home = home
-back = back
-
-no_session = You have no active session!
-no_folder = "no such folder"
-error_send = 'Error when sending message'
-succ_send = 'Message has been send'
-succ_move = 'Messages have been moved'
-empty_folder = This folder is empty.
-
-INBOX = inbox
-SENT = sent
-TRASH = trash
-SAVED = saved
-Home = home
diff --git a/lang/i18n.pod b/lang/i18n.pod
deleted file mode 100644
index 8f7035b..0000000
--- a/lang/i18n.pod
+++ /dev/null
@@ -1,87 +0,0 @@
-=encoding utf-8
-
-=head1 SYNOPSIS
-
- @@ de.lang
- yes = ja
- no = nein
-
-=head1 DESCRIPTION
-
-Place your translation files here.
-Use the two letter language naming convention.
-Use lower case phrases as they will be capitalized by the templates.
-
-=head1 INTERNATIONALIZATION AND LOCALIZATION
-
-=head2 Single Words
-
- Phrase Description
- --------------------------
- failed an operation failed
- and
- no
- yes
- messages mails
- of page x *of* n
- page a page consisting of multiple mails
- login header name
- userid form field label
- passwd form field label
- about about page name
- mbox_size mail box size in byte
- version version translation for JWebmail version
- subject mail field subject
- from mail field from
- to mail field to
- cc mail field cc
- date mail field date
- size mail size
- content-type mail field content-type
- sender mail field sender
- answer_to mail field reply back to
- send_to write mail to
- content the mail body rendered as html
- check_all tick/untick all mails for move
- move move mails to a different folder
- nr row number, column description
- status whether a mail is multipart
- logout close session
- compose write an email
- search search in mails
- new amount of new mails
- home back button to read the main folder
- first first page
- previous previous page
- next next page
- last last page
-
-=head2 Phrases
-
- succ_send tell the user the mail was send successfully
- succ_move tell the user the mails where moved successfully
- empty_folder tell the user the folder is empty
-
-=head2 Error Messages
-
- no_session the session has expired or did not exist at all
- no_folder the selected mail folder does not exists
- error_send error sending the message
-
-=head2 Formats
-
-Currently there are no formats.
-
-=head2 Other
-
- Common Mail Folders
- ---
- Queue
- Drafts
- Home
-
-=head1 SEE OTHER
-
-L<JWebmail::Plugin::I18N>
-
-=cut \ No newline at end of file
diff --git a/lib/JWebmail/Plugin/Paginate.pm b/lib/JWebmail/Plugin/Paginate.pm
index 9b39617..b4564b7 100644
--- a/lib/JWebmail/Plugin/Paginate.pm
+++ b/lib/JWebmail/Plugin/Paginate.pm
@@ -79,11 +79,11 @@ sub paginate {
}
sub make_link {
- my ($c, $txt, $to) = @_;
+ my ($c, $txt, $to, %args) = @_;
return $c->link_to(
$txt => $c->url_with->query({start => $c->stash('pgn')->{$to}[0]}),
- class => ($c->param('start')//0) == $c->stash('pgn')->{$to}[0] ? 'disabled' : '',
+ class => ($c->param('start')//0) == $c->stash('pgn')->{$to}[0] ? join(' ', $args{class}, $args{class_disabled}) : $args{class},
);
}
diff --git a/lib/JWebmail/View/RenderMail.pm b/lib/JWebmail/View/RenderMail.pm
index 90534dc..387e586 100644
--- a/lib/JWebmail/View/RenderMail.pm
+++ b/lib/JWebmail/View/RenderMail.pm
@@ -112,7 +112,7 @@ sub render_message {
warn "unkown mime-subtype $subtype" unless $subtype eq 'rfc822';
- my $R .= '<div clas="jwm-mail">';
+ my $R .= '<div class="jwm-mail">';
$R .= '<dl class="jwm-mail-header">';
$R .= '<dt>' . xml_escape(uc $self->c->l('subject')) . '</dt>';
@@ -127,8 +127,6 @@ sub render_message {
$R .= '<dd>' . to_mime_type($msg->{head}{mime}) . "</dd>\n";
$R .= "</dl>\n";
- #my $content = ref $msg->{body} && exists $msg->{body}{parts} ? $msg->{body}{parts} : $msg->{body};
-
$R .= $self->mime_render(to_mime_types($msg->{head}{mime}), $msg->{body}, [@$path, 0]);
return $R . "</div>\n";
@@ -149,7 +147,7 @@ sub mime_render {
my $renderer = $MIME_Render_Subs{"$maintype/$subtype"} || $MIME_Render_Subs{$maintype};
unless ($renderer) {
- return "<p>Unsupported MIME type of <code>$maintype/$subtype</code>.</p>\n";
+ return qq(<p class="jwm-body-unsupported">Unsupported MIME type of <code>$maintype/$subtype</code>.</p>\n);
}
return $renderer->($self, $subtype, $content, $path);
diff --git a/package-lock.json b/package-lock.json
index 3b222a9..43774d1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,12 +9,13 @@
"version": "1.2.2",
"license": "GPL-3.0",
"dependencies": {
- "bulma": "^0.9.4",
"crypto-js": "^4.1.1",
"purecss": "^3.0.0"
},
"devDependencies": {
- "esbuild": "^0.17.12"
+ "bulma": "^0.9.4",
+ "esbuild": "^0.17.12",
+ "sass": "^1.60.0"
}
},
"node_modules/@esbuild/android-arm": {
@@ -369,10 +370,72 @@
"node": ">=12"
}
},
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/bulma": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.9.4.tgz",
- "integrity": "sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ=="
+ "integrity": "sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ==",
+ "dev": true
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
},
"node_modules/crypto-js": {
"version": "4.1.1",
@@ -416,10 +479,167 @@
"@esbuild/win32-x64": "0.17.12"
}
},
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/immutable": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
+ "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
+ "dev": true
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/purecss": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/purecss/-/purecss-3.0.0.tgz",
"integrity": "sha512-IdYbGwbmuA7Hy9ACIO1q7ks4xGLcJSVHxJT2BXIz2c4Ve1aSrNU5bAzA1ILT4Gmdy5K59ruWoRPf9WvJZU5fbA=="
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/sass": {
+ "version": "1.60.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.60.0.tgz",
+ "integrity": "sha512-updbwW6fNb5gGm8qMXzVO7V4sWf7LMXnMly/JEyfbfERbVH46Fn6q02BX7/eHTdKpE7d+oTkMMQpFWNUMfFbgQ==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
}
},
"dependencies": {
@@ -577,10 +797,52 @@
"dev": true,
"optional": true
},
+ "anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "dev": true
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
"bulma": {
"version": "0.9.4",
"resolved": "https://registry.npmjs.org/bulma/-/bulma-0.9.4.tgz",
- "integrity": "sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ=="
+ "integrity": "sha512-86FlT5+1GrsgKbPLRRY7cGDg8fsJiP/jzTqXXVqiUZZ2aZT8uemEOHlU1CDU+TxklPEZ11HZNNWclRBBecP4CQ==",
+ "dev": true
+ },
+ "chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "requires": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "fsevents": "~2.3.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ }
},
"crypto-js": {
"version": "4.1.1",
@@ -617,10 +879,118 @@
"@esbuild/win32-x64": "0.17.12"
}
},
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "optional": true
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "immutable": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
+ "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==",
+ "dev": true
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true
+ },
+ "is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true
+ },
"purecss": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/purecss/-/purecss-3.0.0.tgz",
"integrity": "sha512-IdYbGwbmuA7Hy9ACIO1q7ks4xGLcJSVHxJT2BXIz2c4Ve1aSrNU5bAzA1ILT4Gmdy5K59ruWoRPf9WvJZU5fbA=="
+ },
+ "readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "sass": {
+ "version": "1.60.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.60.0.tgz",
+ "integrity": "sha512-updbwW6fNb5gGm8qMXzVO7V4sWf7LMXnMly/JEyfbfERbVH46Fn6q02BX7/eHTdKpE7d+oTkMMQpFWNUMfFbgQ==",
+ "dev": true,
+ "requires": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ }
+ },
+ "source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "dev": true
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
}
}
}
diff --git a/package.json b/package.json
index db91a3f..ea2861a 100644
--- a/package.json
+++ b/package.json
@@ -2,12 +2,16 @@
"name": "jwebmail",
"version": "1.2.2",
"description": "JWebmail - A Webmail Server",
- "directories": {
- },
+ "directories": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
- "build": "esbuild --bundle css/style.css src/login_cram.js --outdir=public/",
- "build-release": "esbuild --bundle --minify css/style.css src/login_cram.js --outdir=public/"
+ "build": "npm run build-js && npm run build-css && npm run build-sass",
+ "build-js": "esbuild --bundle src/login_cram.js src/displayheaders.js --outdir=public/src/",
+ "build-css": "esbuild --bundle css/my_pure.css --outdir=public/css/",
+ "build-sass": "sass --update --load-path=node_modules/ scss/my_bulma.scss public/css/my_bulma.css",
+ "build-release": "esbuild --bundle --minify css/*.css src/*.js --outdir=public/ && sass --update --no-source-maps --style=compress --load-path=node_modules/ scss/my_bulma.scss public/css/my_bulma.css",
+ "watch-sass": "sass --watch --load-path=node_modules/ scss/my_bulma.scss public/css/my_bulma.css",
+ "watch-esbuild": "esbuild --watch --bundle --sourcemap css/*.css src/*.js --outdir=public/"
},
"repository": {
"type": "git",
@@ -25,10 +29,12 @@
},
"homepage": "https://github.com/D1CED/JWebmail#readme",
"dependencies": {
- "crypto-js": "^4.1.1",
- "purecss": "^3.0.0"
+ "crypto-js": "^4.1.1"
},
"devDependencies": {
- "esbuild": "^0.17.12"
+ "bulma": "^0.9.4",
+ "esbuild": "^0.17.12",
+ "sass": "^1.60.0",
+ "purecss": "^3.0.0"
}
}
diff --git a/scss/my_bulma.scss b/scss/my_bulma.scss
new file mode 100644
index 0000000..01cdc4b
--- /dev/null
+++ b/scss/my_bulma.scss
@@ -0,0 +1,46 @@
+@use "bulma/bulma";
+
+.jwm-new-mail > .media-content {
+ @extend .has-text-weight-semibold;
+}
+
+dl.jwm-mail-header {
+ $left-xx: 130px;
+
+ & dt {
+ font-weight: bold;
+ @media screen and (min-width: bulma.$desktop) {
+ float: left;
+ clear: left;
+ text-align: right;
+ width: $left-xx;
+ }
+ }
+ & dd {
+ @media screen and (min-width: bulma.$desktop) {
+ margin-left: #{$left-xx + 10px};
+ }
+ margin-left: bulma.$size-7;
+ }
+}
+
+.jwm-mail {
+ @extend .box;
+}
+
+.jwm-mail-header {
+ @extend .block;
+}
+
+.jwm-mail-body {
+ @extend .block;
+}
+
+iframe.jwm-mail-body-text-html {
+ width: 100%;
+ height: 400px;
+}
+
+.jwm-mail-body-text-plain {
+ @extend .block;
+}
diff --git a/src/displayheaders.js b/src/displayheaders.js
new file mode 100644
index 0000000..3c0936a
--- /dev/null
+++ b/src/displayheaders.js
@@ -0,0 +1,35 @@
+function toggle_navbar() {
+ // Get the target from the "data-target" attribute
+ const target = this.dataset.target;
+ const $target = document.getElementById(target);
+
+ // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
+ this.classList.toggle('is-active');
+ $target.classList.toggle('is-active');
+}
+
+function sort_select_submit() {
+ this.children[0].form.submit();
+}
+
+function check_all() {
+ const setTo = this.checked;
+ const chkbox = document.getElementsByClassName('jwm-mail-checkbox');
+
+ for (const m of chkbox)
+ m.checked = setTo;
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+ {
+ const sort_select = document.getElementById("sort");
+ const current_option_name = new URL(document.location).searchParams.get("sort");
+ if (current_option_name)
+ sort_select.value = current_option_name;
+ }
+
+ document.getElementById("sort-select").addEventListener("change", sort_select_submit);
+ document.getElementById("navbar-toggle").addEventListener("click", toggle_navbar);
+ document.getElementById("check-all").addEventListener("click", check_all);
+});
+
diff --git a/templates/displayheaders/_bot_nav.html.ep b/templates/displayheaders/_bot_nav.html.ep
index 454941b..a6d089c 100644
--- a/templates/displayheaders/_bot_nav.html.ep
+++ b/templates/displayheaders/_bot_nav.html.ep
@@ -1,36 +1,39 @@
-<div class="pure-g jwm-nav">
+<div class="columns">
- <div class="pure-u-3-4">
- <div class="pure-u-1 pure-u-md-1-2">
+ <div class="column">
%= include 'displayheaders/_pagination1'
- </div><div class="pure-u-1 pure-u-md-1-2">
+ </div>
+
+ <div class="column">
% if (grep {$_ ne $folder} @$mail_folders) {
- %= form_for move => (id => 'move-mail') => (class => 'pure-form') => begin
- <fieldset>
- %= label_for 'select-folder' => l('move to')
- %= select_field folder => [map { $_ ? $_ : l 'Home' } grep {$_ ne $folder} @$mail_folders] => (id => 'select-folder')
- %= csrf_field
- %= submit_button l('move') => (class => 'pure-button')
- </fieldset>
+ %= form_for move => (id => 'move-mail') => begin
+
+ <div class="field is-horizontal">
+ <div class=field-label>
+ %= label_for 'select-folder' => l('move to') => (class => 'label')
+ </div>
+ <div class=field-body>
+ <div class="field is-grouped">
+ <div class=control>
+ <div class='select'>
+ %= select_field folder => [map { $_ ? $_ : l 'Home' } grep {$_ ne $folder} @$mail_folders]
+ </div>
+ </div>
+ %= csrf_field
+ <div class=control>
+ %= submit_button l('move') => (class => 'button')
+ </div>
+ </div>
+ </div>
+ </div>
+
% end
% }
</div>
- </div>
- <div class="pure-u-1-4">
+ <div class="column has-text-right">
<label for=allbox><%= l 'check all' %></label>
- <input name=allbox type=checkbox onclick="check_all(this)">
+ <input name=allbox type=checkbox id=check-all>
</div>
</div>
-
-<script type="text/javascript">
-function check_all(box) {
- const setTo = box.checked;
- const mails = document.getElementById('mail-headers').tBodies[0].rows;
-
- for (const m of mails) {
- m.lastElementChild.children[0].checked = setTo;
- }
-}
-</script>
diff --git a/templates/displayheaders/_folders.html.ep b/templates/displayheaders/_folders.html.ep
index b341768..457a838 100644
--- a/templates/displayheaders/_folders.html.ep
+++ b/templates/displayheaders/_folders.html.ep
@@ -1,29 +1,44 @@
-<div id=display-folders class="pure-g jwm-nav">
+<div class="columns">
- <div class="pure-u-1-1 pure-u-md-1-2">
- <nav class="pure-menu pure-menu-horizontal">
+ <div class="column">
+ <nav class="navbar">
- <strong class="pure-menu-heading">
- %= l($folder || '_mailbox_root')
- </strong>
+ <div class="navbar-brand">
+ <span class=navbar-item>
+ <%= l($folder || '_mailbox_root') %>
+ </span>
+ <a role="button" class="navbar-burger" data-target="navMenu" id=navbar-toggle>
+ <span aria-hidden="true"></span>
+ <span aria-hidden="true"></span>
+ <span aria-hidden="true"></span>
+ </a>
+ </div>
- <ul class="pure-menu-list">
+ <div class="navbar-menu" id="navMenu">
+ <div class=navbar-start>
% for (grep {$_ ne $folder} @$mail_folders) {
- <li class="pure-menu-item">
- %= link_to '' => {folder => $_} => (class => 'bright') => begin
+ %= link_to '' => {folder => $_} => (class => 'navbar-item') => begin
%= l($_ || '_mailbox_root')
% end
- </li>
% }
- </ul>
-
+ </div>
+ </div>
</nav>
</div>
- <p class="pure-u-1-1 pure-u-md-1-2">
- <%= l('[_1] of [_2] messages', $pgn->{this_page}[1] - $pgn->{this_page}[0], $pgn->{total_items}) %>\
- <%= l(', [_1] new', $total_new_mails) if $total_new_mails > 0 =%>
- <%= l(' - mailbox size: [_1]', $v->print_sizes10($total_size)) if $total_size %>
- </p>
+ <div class="column">
+ <div class="columns is-multiline is-mobile">
+ <span class="column is-half-mobile has-text-centered"><%= l('[_1] of [_2] messages', $pgn->{this_page}[1] - $pgn->{this_page}[0], $pgn->{total_items}) %>
+ </span>
+ <span class="column is-half-mobile has-text-centered"><%= l('[_1] new', $total_new_mails) if $total_new_mails > 0 =%>
+ </span>
+ <span class="column has-text-centered">
+ % if ($total_size) {
+ %= l('mailbox size: ')
+ %= $v->print_sizes10($total_size)
+ % }
+ </span>
+ </div>
+ </div>
</div>
diff --git a/templates/displayheaders/_main_table.html.ep b/templates/displayheaders/_main_table.html.ep
index 06bbbfc..e06e925 100644
--- a/templates/displayheaders/_main_table.html.ep
+++ b/templates/displayheaders/_main_table.html.ep
@@ -9,104 +9,43 @@
% end
-<table id=mail-headers class="pure-table pure-table-horizontal">
+<section class="box">
- <thead>
- <tr id=sort>
- <th class="hide-small">
- #
- </th>
-
- <th>
- <div class="pure-g">
-
- %# $sort_param->('status');
-
- <div class="pure-u-1 pure-u-md-4-24">
- %= $sort_param->('date');
- </div>
-
-% if ($folder ne "SENT") {
- <div class="pure-u-1 pure-u-md-8-24">
- %= $sort_param->('sender');
- </div>
-% }
-% else {
- <th class=sort-param>
- %= link_to url_with->query(sort => param('sort') ne '!sender' ? 'sender' : '!sender' ) => begin
- %= ucfirst l 'recipient'
- % if (param('sort') eq "sender") {
- %= image '/down.gif' => (width => 12) => (height => 12) => (border => 0) => (alt => 'v')
- % }
- % elsif (param('sort') eq "recipient_rev") {
- %= image '/up.gif' => (width => 12) => (height => 12) => (border => 0) => (alt => '^')
- % }
- % end
- </th>
-% }
-
- <div class="pure-u-1 pure-u-md-12-24">
- %= $sort_param->('subject');
- </div>
-
- </div>
- </th>
-
- <th class="hide-small">
- %= $sort_param->('size');
- </th>
-
- <th>
- <input type=checkbox checked=1 disabled=1>
- </th>
- </tr>
- </thead>
-
- <tbody>
% foreach my $msgnum ($pgn->{first_item} .. $pgn->{last_item}) {
% my $msg = $msgs->[$msgnum - $pgn->{first_item}];
- %= tag tr => (class => $msg->{unread} ? 'new-mail' : '') => (id => $msg->{message_handle}) => begin
- <td class="hide-small" style="text-align: right">
+ %= tag div => (class => $msg->{unread} ? 'media jwm-new-mail' : 'media') => (id => $msg->{message_handle}) => begin
+ <div class="media-left is-hidden-mobile">
%= $msgnum + 1
- </td>
-
- <td>
- <div class="pure-g">
-
- <!--
- <div class="pure-u-1-4">
- %# ucfirst($msg->{head}{mime}{content_maintype} eq 'multipart' ? l('yes') : l('no'));
- </div>
- -->
-
- <div class="pure-u-1 pure-u-md-4-24">
- % my $date = $v->parse_iso_date($msg->{head}{date});
- %= join('/', $date->{mday}, $date->{month}, $date->{year}) . " $date->{hour}:$date->{min}";
- </div>
-
- <div class="pure-u-1 pure-u-md-8-24">
- <%= $msg->{head}{sender}[0]{display_name} || $msg->{head}{sender}[0]{address} ||
- $msg->{head}{from}[0]{display_name} || $msg->{head}{from}[0]{address}; %>
- </div>
+ </div>
- <div class="pure-u-1 pure-u-md-12-24">
- %= link_to $msg->{head}{subject} || '_' => read => {id => $msg->{message_handle}}
+ <div class="media-content">
+ <div class=" columns is-gapless is-multiline">
+ <div class="column is-10">
+ <%= $msg->{head}{sender}[0]{display_name} || $msg->{head}{sender}[0]{address} ||
+ $msg->{head}{from}[0]{display_name} || $msg->{head}{from}[0]{address}; %>
+ </div>
+
+ <div class="column is-2">
+ % my $date = $v->parse_iso_date($msg->{head}{date});
+ %= join('/', $date->{mday}, $date->{month}, $date->{year}) . " $date->{hour}:$date->{min}";
+ </div>
+
+ <div class="column is-10">
+ %= link_to $msg->{head}{subject} || '_' => read => {id => $msg->{message_handle}}
+ </div>
+
+ <div class="column is-2">
+ %= $v->print_sizes10($msg->{byte_size});
+ </div>
</div>
-
</div>
- </td>
-
- <td class="hide-small" style="text-align: right; white-space: nowrap">
- %= $v->print_sizes10($msg->{byte_size});
- </td>
- <td>
- %= check_box mail => $msg->{message_handle} => (form => 'move-mail')
- </td>
+ <div class=media-right>
+ %= check_box mail => $msg->{message_handle} => (form => 'move-mail') => (class => 'jwm-mail-checkbox')
+ </div>
% end
% }
- </tbody>
-</table>
+</section>
diff --git a/templates/displayheaders/_pagination1.html.ep b/templates/displayheaders/_pagination1.html.ep
index a32afe1..6a22ba5 100644
--- a/templates/displayheaders/_pagination1.html.ep
+++ b/templates/displayheaders/_pagination1.html.ep
@@ -1,14 +1,14 @@
<nav>
- <ul class="pagination-box">
+ <ul class="pagination-list">
<li>
- %= $c->_paginate->make_link('←', 'prev_page')
+ %= $c->_paginate->make_link('←', 'prev_page', class => 'pagination-link', class_disabled => 'is-disabled')
<li>
- %= $c->_paginate->make_link('↞', 'first_page')
+ %= $c->_paginate->make_link('↞', 'first_page', class => 'pagination-link', class_disabled => 'is-disabled')
<li>
- <span><%= l('page [_1] of [_2]', $pgn->{current_page}+1, $pgn->{total_pages}) %></span>
+ <span class="pagination-link is-current"><%= l('page [_1] of [_2]', $pgn->{current_page}+1, $pgn->{total_pages}) %></span>
<li>
- %= $c->_paginate->make_link('↠', 'last_page')
+ %= $c->_paginate->make_link('↠', 'last_page', class => 'pagination-link', class_disabled => 'is-disabled')
<li>
- %= $c->_paginate->make_link('→', 'next_page')
+ %= $c->_paginate->make_link('→', 'next_page', class => 'pagination-link', class_disabled => 'is-disabled')
</ul>
</nav>
diff --git a/templates/displayheaders/_pagination3.html.ep b/templates/displayheaders/_pagination3.html.ep
index fe573ce..846a285 100644
--- a/templates/displayheaders/_pagination3.html.ep
+++ b/templates/displayheaders/_pagination3.html.ep
@@ -1,6 +1,6 @@
% my $make_link_num = begin
% my ($txt, $to) = @_;
-%= link_to $txt => url_with->query({start => $to}) => (class => (param('start')//0) == $to ? 'current' : '')
+%= link_to $txt => url_with->query({start => $to}) => (class => (param('start')//0) == $to ? 'pagination-link is-current' : 'pagination-link')
% end
% my $nbh = begin
@@ -15,13 +15,13 @@
% }
% end
-<nav>
- <ul class="pagination-box">
+<nav class="pagination is-centered">
+ <ul class="pagination-list">
<li>
- %= $c->_paginate->make_link('Prev' => 'prev_page')
+ %= $c->_paginate->make_link('Prev' => 'prev_page', class => 'pagination-link', class_disabled => 'is-disabled')
</li>
%= $nbh->()
<li>
- %= $c->_paginate->make_link('Next' => 'next_page')
+ %= $c->_paginate->make_link('Next' => 'next_page', class => 'pagination-link', class_disabled => 'is-disabled')
</ul>
</nav>
diff --git a/templates/displayheaders/_top_nav.html.ep b/templates/displayheaders/_top_nav.html.ep
index f4c66d2..e5eaab8 100644
--- a/templates/displayheaders/_top_nav.html.ep
+++ b/templates/displayheaders/_top_nav.html.ep
@@ -1,35 +1,52 @@
-<div class="pure-g">
+<div class="columns">
- <div class="pure-u-1 pure-u-md-1-4">
- <div class="pure-menu pure-menu-horizontal">
- <ul class="pure-menu-list">
- %# <a href="<%= url_with($prefsurl) %>"><%= TXT 'userconfig' %></a>
- %# <a href="<%=$prefsurl%>?action=editaddresses&folder=<%=$folder%>&sessionid=<%=$thissession%>&sort=<%=$sort%>&firstmessage=<%=$firstmessage+1%>&lang=<%=$lang%>" ><%= TXT 'addressbook' %></a>
- <li class="pure-menu-item">
- %= link_to ucfirst(l 'logout') => 'logout'
- </li>
- <li class="pure-menu-item">
- %= link_to ucfirst(l 'compose') => 'write'
- </li>
- </ul>
+ <nav class="column">
+ %# <a href="<%= url_with($prefsurl) %>"><%= TXT 'userconfig' %></a>
+ %# <a href="<%=$prefsurl%>?action=editaddresses&folder=<%=$folder%>&sessionid=<%=$thissession%>&sort=<%=$sort%>&firstmessage=<%=$firstmessage+1%>&lang=<%=$lang%>" ><%= TXT 'addressbook' %></a>
+ %= link_to ucfirst(l 'logout') => 'logout' => (class => 'button')
+ %= link_to ucfirst(l 'compose') => 'write' => (class => 'button')
+ </nav>
+
+ %# <td> <form action="<%= url_for('delete_msg') %>" name=Formdel onsubmit="return confirm('<%= TXT q(js_confirm_delete) %>')" > </form> </td>
+
+ %= form_for '' => (class => 'column') => begin
+ <div class="field is-horizontal">
+ <div class=field-label>
+ %= label_for search => ucfirst(l 'search') => (class => 'label')
+ </div>
+ <div class=field-body>
+ <div class=field>
+ <div class="control">
+ %= search_field search => (size => 8) => (class => 'input')
+ </div>
+ </div>
+ </div>
</div>
- </div>
+ % end
- <div class="pure-u-1 pure-u-md-1-4">
- %= form_for '' => (class => 'pure-form') => begin
- %= label_for search => ucfirst(l 'search')
- %= search_field search => (size => 8)
- % end
- </div>
+ %= form_for '' => (class => 'column') => begin
+ <div class="field is-horizontal">
+ <div class=field-label>
+ %= label_for sort => ucfirst(l 'sort') => (class => 'label')
+ </div>
+ <div class=field-body>
+ <div class=field>
+ <div class="select" id=sort-select>
+ <select name=sort id=sort>
+ <option value="!date">Date - Descending</option>
+ <option value="date" >Date - Ascending</option>
+ <option value="!size">Size - Descending</option>
+ <option value="!sender">Sender - Descending</option>
+ <option value="sender" >Sender - Ascending</option>
+ </select>
+ </div>
+ </div>
+ </div>
+ </div>
+ % end
- <div class="pure-u-1-1 pure-u-md-1-2">
+ <div class="column">
%= include 'displayheaders/_pagination3';
</div>
- <!-- delete button
- <td>
- %# <form action="<%= url_for('delete_msg') %>" name=Formdel onsubmit="return confirm('<%= TXT q(js_confirm_delete) %>')" > </form>
- </td>
- -->
-
</div>
diff --git a/templates/layouts/mainlayout.html.ep b/templates/layouts/mainlayout.html.ep
index 2cd4671..8cf822c 100644
--- a/templates/layouts/mainlayout.html.ep
+++ b/templates/layouts/mainlayout.html.ep
@@ -6,9 +6,7 @@
<meta charset=utf-8>
<meta name="viewport" content="width=device-width, initial-scale=1">
- %# <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/purecss@3.0.0/build/pure-min.css" integrity="sha384-X38yfunGUhNzHpBaEBsWLO+A0HDYOQi8ufWDkZ0k9e0eXz/tH3II7uKZ9msv++Ls" crossorigin="anonymous">
- %# <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/purecss@3.0.0/build/grids-responsive-min.css">
- %= stylesheet '/css/style.css'
+ %= stylesheet '/css/my_bulma.css'
<title>
%= title || 'JWebmail'
@@ -18,14 +16,16 @@
<body>
%= content
- <footer>
- %= link_to about => begin
- %= ucfirst l 'about'
- JWebmail
- % end
- <br>
- %= ucfirst l 'version'
- %= $version
+ <footer class=footer>
+ <div class="content has-text-centered">
+ %= link_to about => begin
+ %= ucfirst l 'about'
+ JWebmail
+ % end
+ <br>
+ %= ucfirst l 'version'
+ %= $version
+ </div>
</footer>
</body>
diff --git a/templates/not_found.html.ep b/templates/not_found.html.ep
new file mode 100644
index 0000000..a8eafc0
--- /dev/null
+++ b/templates/not_found.html.ep
@@ -0,0 +1,25 @@
+<html>
+
+ <head>
+ <meta charset=utf-8>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+
+ <title>Not Found</title>
+
+ %= stylesheet '/css/my_bulma.css'
+ </head>
+
+ <body>
+ <section class=hero>
+ <div class=hero-body>
+ <h1 class=title>
+ Not the page you are looking for.
+ </h1>
+ <p>
+ Go back or go to the <%= link_to 'start page' => 'login' %>.
+ </p>
+ </div>
+ </section>
+ </body>
+
+</html>
diff --git a/templates/not_found.production.html.ep b/templates/not_found.production.html.ep
deleted file mode 100644
index b96e46e..0000000
--- a/templates/not_found.production.html.ep
+++ /dev/null
@@ -1,16 +0,0 @@
-<html>
-
- <head>
- <title>Not Found</title>
- </head>
-
- <body>
- <p class=center>
- Not the page you are looking for.
- </p>
- <p class=center>
- Go back or go to the <%= link_to 'start page' => 'login' %>.
- </p>
- </body>
-
-</html>
diff --git a/templates/webmail/about.html.ep b/templates/webmail/about.html.ep
index 6221bcc..a5cd4a7 100644
--- a/templates/webmail/about.html.ep
+++ b/templates/webmail/about.html.ep
@@ -2,9 +2,9 @@
% layout 'mainlayout';
-<div class="jwm-base">
+<div class="section container">
- <div class="jwm-post">
+ <article class=content>
<h1>About JWebmail <%= $version %></h1>
@@ -38,7 +38,7 @@
and currently maintained by
<a href="mailto:jannis@fehcom.de">Jannis M. Hoffmann</a>
</p>
-
+
<p>
<h3>Supported languages</h3>
@@ -56,10 +56,12 @@
a complete rewrite of oMail-webmail.
</p>
- </div>
+ </article>
- <nav>
- %= link_to login => 'login' => (class => 'pure-button')
+ <nav class=navbar>
+ <div class=navbar-item>
+ %= link_to login => 'login' => (class => 'button')
+ </div>
</nav>
</div>
diff --git a/templates/webmail/displayheaders.html.ep b/templates/webmail/displayheaders.html.ep
index 3f650c0..8446e00 100644
--- a/templates/webmail/displayheaders.html.ep
+++ b/templates/webmail/displayheaders.html.ep
@@ -1,6 +1,8 @@
% layout 'mainlayout';
-<div id=displayheaders>
+<section class="section container">
+
+ %= javascript '/src/displayheaders.js' => (defer => undef)
%= include 'displayheaders/_folders';
@@ -16,11 +18,11 @@
%= include 'displayheaders/_main_table';
% }
% else {
- <p id=empty-folder>
+ <p class="section">
%= l 'This folder is empty!'
</p>
% }
%= include 'displayheaders/_bot_nav';
-</div>
+</section>
diff --git a/templates/webmail/login.html.ep b/templates/webmail/login.html.ep
index 706dc1c..54ab40a 100644
--- a/templates/webmail/login.html.ep
+++ b/templates/webmail/login.html.ep
@@ -2,38 +2,69 @@
% my $uses_cram = config->{session}{secure} eq 'cram';
-<div id=login class="jwm-base">
+<section class=section>
+ <div class="container is-max-desktop box">
- <h1>
- JWebmail – <%= ucfirst l 'login' %>
- </h1>
+ <h1 class=title>
+ <%= ucfirst l 'login' %>
+ </h1>
+ <h2 class=subtitle>
+ JWebmail
+ </h2>
% if (my $msg = flash('message') || stash('warning')) {
- <p class="jwm-warning">
- %= $msg
- </p>
+ <div class="message is-warning">
+ <div class=message-header>
+ %= $msg
+ </div>
+ </div>
% }
%= form_for login => (name => 'login1') => (method => 'post') => (class => 'pure-form pure-form-aligned jwm-round') => begin
- <fieldset>
- <div class="pure-control-group">
- %= label_for userid => ucfirst l 'userid'
- %= text_field 'userid' => '' => (required => '')
+
+ <div class="field is-horizontal">
+ <div class=field-label>
+ %= label_for userid => ucfirst l 'userid' => (class => 'label')
+ </div>
+ <div class=field-body>
+ <div class=field>
+ <div class=control>
+ %= text_field 'userid' => '' => (required => undef) => (class => 'input')
+ </div>
+ </div>
</div>
- <div class="pure-control-group">
- %= label_for password => ucfirst l 'password'
- %= password_field 'password' => (required => '')
+ </div>
+
+ <div class="field is-horizontal">
+ <div class=field-label>
+ %= label_for password => ucfirst l 'password' => (class => 'label')
</div>
+ <div class=field-body>
+ <div class=field>
+ <div class=control>
+ %= password_field 'password' => (required => undef) => (class => 'input')
+ </div>
+ </div>
+ </div>
+ </div>
% if ($uses_cram) {
%= hidden_field challenge => rand
% }
- <div class="pure-controls">
- %= submit_button ucfirst l('login') => (class => 'pure-button pure-button-primary') => (name => 'submit_button') => $uses_cram ? (disabled => undef) : ()
+ <div class="field is-horizontal">
+ <div class=field-label>
+ </div>
+ <div class=field-body>
+ <div class=field>
+ <div class=control>
+ %= submit_button ucfirst l('login') => (class => 'button is-primary') => (name => 'submit_button') => $uses_cram ? (disabled => undef) : ()
+ </div>
+ </div>
</div>
- </fieldset>
+ </div>
% end
-</div>
+ </div>
+</section>
% if ($uses_cram) {
%= javascript '/src/login_cram.js'
diff --git a/templates/webmail/readmail.html.ep b/templates/webmail/readmail.html.ep
index 529bbe6..c9586ac 100644
--- a/templates/webmail/readmail.html.ep
+++ b/templates/webmail/readmail.html.ep
@@ -1,14 +1,14 @@
% layout 'mainlayout';
-<div class="jwm-base">
+<div class="section container">
- <h1>Read Mail</h1>
+ <h1 class=title>Read Mail</h1>
%= $v->format_mail($msg)
<nav>
- <a href="javascript:history.back()" class="pure-button">
+ <a href="javascript:history.back()" class="button">
%= l 'back'
</a>
</nav>
diff --git a/templates/webmail/writemail.html.ep b/templates/webmail/writemail.html.ep
index 9d148c1..95b9cf8 100644
--- a/templates/webmail/writemail.html.ep
+++ b/templates/webmail/writemail.html.ep
@@ -1,47 +1,80 @@
% layout 'mainlayout';
-<div class="jwm-base">
+<div class="section container">
- <h1>Write Message</h1>
+ <h1 class=title>Write Message</h1>
% if (my $msg = stash('warning')) {
- <p class=warn> <%= $msg %> </p>
+ <p class=message> <%= $msg %> </p>
% }
- %= form_for '' => (method => 'post') => (enctype => 'multipart/form-data') => (class => 'pure-form pure-form-stacked') => begin
- <fieldset>
-
- %= label_for mail => ucfirst l 'send_to'
- %= email_field 'to' => (id => 'mail') => (multiple => '') => (required => '')
-
- %= label_for subject => ucfirst l 'subject'
- %= text_field 'subject' => (required => '')
-
- %= label_for cc => 'CC'
- %= email_field 'cc' => (multiple => '')
-
- %= label_for bcc => 'BCC'
- %= email_field 'bcc' => (multiple => '')
-
- %= label_for back_to => ucfirst l 'answer_to'
- %= email_field 'back_to'
-
- %= label_for txt => ucfirst l 'content'
- %# text_area body => (cols => 80) => (rows => 24) => (name => 'txt')
- %= text_area body => (style => 'width: 100%') => (rows => 24) => (name => 'txt')
-
- %= label_for attach => ucfirst l 'attach file'
- %= file_field 'attach'
-
- %= submit_button l('send') => (class => 'pure-button pure-button-primary')
+ %= form_for '' => (method => 'post') => (enctype => 'multipart/form-data') => (class => '') => begin
+
+ <div class=field>
+ %= label_for mail => ucfirst l('send_to') => (class => 'label')
+ <div class=control>
+ %= email_field 'to' => (id => 'mail') => (multiple => '') => (required => '') => (class => 'input')
+ </div>
+ </div>
+
+ <div class=field>
+ %= label_for subject => ucfirst l('subject') => (class => 'label')
+ <div class=control>
+ %= text_field 'subject' => (required => '') => (class => 'input')
+ </div>
+ </div>
+
+ <div class=field>
+ %= label_for cc => 'CC' => (class => 'label')
+ <div class=control>
+ %= email_field 'cc' => (multiple => '') => (class => 'input')
+ </div>
+ </div>
+
+ <div class=field>
+ %= label_for bcc => 'BCC' => (class => 'label')
+ <div class=control>
+ %= email_field 'bcc' => (multiple => '') => (class => 'input')
+ </div>
+ </div>
+
+ <div class=field>
+ %= label_for back_to => ucfirst l('answer_to') => (class => 'label')
+ <div class=control>
+ %= email_field 'back_to' => (class => 'input')
+ </div>
+ </div>
+
+ <div class=field>
+ %= label_for txt => ucfirst l('content') => (class => 'label')
+ %= text_area body => (rows => 24) => (name => 'txt') => (class => 'textarea')
+ </div>
+
+ <div class=field>
+ <div class=file>
+ <label class=file-label>
+ %= file_field 'attach' => (class => 'file-input')
+ <div class="file-cta">
+ %= tag span => (class => 'file-label') => begin
+ %= ucfirst l('attach file')
+ % end
+ </div>
+ </label>
+ </div>
+ </div>
+
+ <div class=field>
+ <div class=control>
+ %= submit_button l('send') => (class => 'button')
+ </div>
+ </div>
%= csrf_field
- </fieldset>
% end
<nav>
- <a href="javascript:history.back()" class="pure-button"> <%= ucfirst l 'back' %> </a>
+ <a href="javascript:history.back()" class="button"> <%= ucfirst l 'back' %> </a>
</nav>
</div>