edit bulma theme.
All checks were successful
Deploy / Build (push) Successful in 7m21s

This commit is contained in:
amass 2024-12-02 01:18:57 +08:00
parent 03c7a564a1
commit 109689562a
10 changed files with 127 additions and 51 deletions

View File

@ -47,7 +47,7 @@ void SystemUsage::start() {
auto receiveGigabyte = static_cast<float>(back.receiveBytes - front.receiveBytes) / gigabyte; auto receiveGigabyte = static_cast<float>(back.receiveBytes - front.receiveBytes) / gigabyte;
auto transmitGigabyte = static_cast<float>(back.transmitBytes - front.transmitBytes) / gigabyte; auto transmitGigabyte = static_cast<float>(back.transmitBytes - front.transmitBytes) / gigabyte;
auto speed = (receiveGigabyte + transmitGigabyte) / duration.count() * SpeedInterval.count(); auto speed = (receiveGigabyte + transmitGigabyte) / duration.count() * SpeedInterval.count();
LOG(info) << "network speed: " << std::fixed << std::setprecision(2) << speed << "GB/h"; // LOG(info) << "network speed: " << std::fixed << std::setprecision(2) << speed << "GB/h";
static system_clock::time_point lastNotify; static system_clock::time_point lastNotify;
auto now = system_clock::now(); auto now = system_clock::now();
if ((speed >= 1.5f) && (duration_cast<minutes>(now - lastNotify) > minutes(10))) { // 一个小时1.5GB的流量 if ((speed >= 1.5f) && (duration_cast<minutes>(now - lastNotify) > minutes(10))) { // 一个小时1.5GB的流量

View File

@ -2,7 +2,7 @@
#include "BoostLog.h" #include "BoostLog.h"
#include "BulmaTheme.h" #include "BulmaTheme.h"
#include "Database/Session.h" #include "Database/Session.h"
#include "Dialog.h" #include "HomePage.h"
#include "LoginPage.h" #include "LoginPage.h"
#include "Restful.h" #include "Restful.h"
#include "VisitorRecordsPage.h" #include "VisitorRecordsPage.h"
@ -17,8 +17,6 @@
#include <Wt/Dbo/backend/Sqlite3.h> #include <Wt/Dbo/backend/Sqlite3.h>
#include <Wt/WContainerWidget.h> #include <Wt/WContainerWidget.h>
#include <Wt/WEnvironment.h> #include <Wt/WEnvironment.h>
#include <Wt/WLineEdit.h>
#include <Wt/WPushButton.h>
#include <Wt/WServer.h> #include <Wt/WServer.h>
#include <format> #include <format>
@ -33,7 +31,6 @@ Application::Application(const Wt::WEnvironment &env, bool embedded) : Wt::WAppl
m_session->login().changed().connect(this, &Application::authEvent); m_session->login().changed().connect(this, &Application::authEvent);
setTheme(std::make_shared<BulmaTheme>("bulma", !embedded)); setTheme(std::make_shared<BulmaTheme>("bulma", !embedded));
if (!embedded) { if (!embedded) {
// setTheme(std::make_shared<Wt::WBootstrap2Theme>());
m_root = root(); m_root = root();
} else { } else {
std::unique_ptr<Wt::WContainerWidget> topPtr = std::make_unique<Wt::WContainerWidget>(); std::unique_ptr<Wt::WContainerWidget> topPtr = std::make_unique<Wt::WContainerWidget>();
@ -55,34 +52,11 @@ Application::Application(const Wt::WEnvironment &env, bool embedded) : Wt::WAppl
LOG(info) << p.first; LOG(info) << p.first;
} }
} }
}
LOG(info) << "url: " << url(); LOG(info) << "url: " << url();
LOG(info) << "relative resources url: " << relativeResourcesUrl(); LOG(info) << "relative resources url: " << relativeResourcesUrl();
LOG(info) << "resources url: " << resourcesUrl(); LOG(info) << "resources url: " << resourcesUrl();
}
if (!embedded) {
root()->addWidget(std::make_unique<Wt::WText>(
"Note: you can also run this application from within <a href=\"hello.html\">a web page</a>."));
}
LOG(info) << "internal path: " << internalPath(); LOG(info) << "internal path: " << internalPath();
m_root->addWidget(std::make_unique<Wt::WText>("Your name, please ? "));
m_nameEdit = m_root->addWidget(std::make_unique<Wt::WLineEdit>());
m_nameEdit->setFocus();
auto b = m_root->addWidget(std::make_unique<Wt::WPushButton>("点击我!"));
b->setMargin(5, Wt::Side::Left);
m_root->addWidget(std::make_unique<Wt::WBreak>());
m_greeting = m_root->addWidget(std::make_unique<Wt::WText>());
b->clicked().connect(this, &Application::greet);
m_nameEdit->enterPressed().connect(this, &Application::greet);
auto app = Amass::Singleton<Server>::instance();
m_root->addWidget(std::make_unique<Dialog>());
internalPathChanged().connect(this, &Application::handlePathChange); internalPathChanged().connect(this, &Application::handlePathChange);
handlePathChange(m_externalPath.empty() ? internalPath() : m_externalPath); handlePathChange(m_externalPath.empty() ? internalPath() : m_externalPath);
} }
@ -90,11 +64,6 @@ Application::Application(const Wt::WEnvironment &env, bool embedded) : Wt::WAppl
Application::~Application() { Application::~Application() {
} }
void Application::greet() {
m_greeting->setText("Hello there, " + m_nameEdit->text());
setInternalPath(m_externalPath);
}
void Application::authEvent() { void Application::authEvent() {
if (m_session->login().loggedIn()) { if (m_session->login().loggedIn()) {
const Wt::Auth::User &u = m_session->login().user(); const Wt::Auth::User &u = m_session->login().user();
@ -114,6 +83,9 @@ void Application::handlePathChange(const std::string &path) {
} else if (path.starts_with("/wt/visitor/analysis")) { } else if (path.starts_with("/wt/visitor/analysis")) {
m_root->clear(); m_root->clear();
m_root->addNew<VisitorRecordsPage>(*m_session); m_root->addNew<VisitorRecordsPage>(*m_session);
} else {
m_root->clear();
m_root->addNew<HomePage>();
} }
} }

View File

@ -27,13 +27,10 @@ public:
~Application(); ~Application();
protected: protected:
void greet();
void authEvent(); void authEvent();
void handlePathChange(const std::string &path); void handlePathChange(const std::string &path);
private: private:
Wt::WLineEdit *m_nameEdit = nullptr;
Wt::WText *m_greeting = nullptr;
std::unique_ptr<Session> m_session; std::unique_ptr<Session> m_session;
std::string m_externalPath; std::string m_externalPath;

View File

@ -1,6 +1,7 @@
#include "BulmaTheme.h" #include "BulmaTheme.h"
#include "BoostLog.h" #include "BoostLog.h"
#include <Wt/DomElement.h> #include <Wt/DomElement.h>
#include <Wt/WApplication.h>
#include <Wt/WDialog.h> #include <Wt/WDialog.h>
#include <Wt/WLinkedCssStyleSheet.h> #include <Wt/WLinkedCssStyleSheet.h>
#include <Wt/WPopupWidget.h> #include <Wt/WPopupWidget.h>
@ -11,6 +12,19 @@ namespace std {
std::ostream &operator<<(std::ostream &os, Wt::DomElementType type); std::ostream &operator<<(std::ostream &os, Wt::DomElementType type);
} }
void BulmaTheme::init(Wt::WApplication *app) const {
Wt::WString v = app->metaHeader(Wt::MetaHeaderType::Meta, "viewport");
if (v.empty()) {
// app->addMetaHeader("viewport", "width=device-width, initial-scale=1");
app->doJavaScript(R"(
var meta = document.createElement('meta');
meta.name = 'viewport';
meta.content = 'width=device-width, initial-scale=1';
document.getElementsByTagName('head')[0].appendChild(meta);
)");
}
}
std::string BulmaTheme::disabledClass() const { std::string BulmaTheme::disabledClass() const {
return ""; return "";
} }
@ -38,6 +52,40 @@ bool BulmaTheme::canStyleAnchorAsButton() const {
} }
void BulmaTheme::apply(Wt::WWidget *widget, Wt::WWidget *child, int widgetRole) const { void BulmaTheme::apply(Wt::WWidget *widget, Wt::WWidget *child, int widgetRole) const {
using namespace Wt;
if (!widget->isThemeStyleEnabled()) return;
switch (widgetRole) {
case DialogContent: {
child->addStyleClass("bulma-modal-content");
break;
}
case DialogCoverWidget: {
child->addStyleClass("bulma-modal-backdrop");
break;
}
case DialogTitleBar: {
child->addStyleClass("bulma-modal-card-head");
child->setAttributeValue("style", "justify-content: space-between");
break;
}
case DialogBody: {
child->addStyleClass("bulma-modal-card-body");
break;
}
case DialogFooter: {
child->addStyleClass("bulma-modal-card-foot bulma-buttons");
break;
}
case DialogCloseIcon: {
auto parent = dynamic_cast<WContainerWidget *>(child->parent());
auto self = parent->removeWidget(child);
parent->addWidget(std::move(self));
child->addStyleClass("bulma-delete");
break;
}
default:
break;
}
} }
void BulmaTheme::apply(Wt::WWidget *widget, Wt::DomElement &element, int elementRole) const { void BulmaTheme::apply(Wt::WWidget *widget, Wt::DomElement &element, int elementRole) const {
@ -55,9 +103,11 @@ void BulmaTheme::apply(Wt::WWidget *widget, Wt::DomElement &element, int element
break; break;
} }
case Wt::DomElementType::DIV: { case Wt::DomElementType::DIV: {
Wt::WDialog *dialog = dynamic_cast<Wt::WDialog *>(widget); if (Wt::WDialog *dialog = dynamic_cast<Wt::WDialog *>(widget); dialog != nullptr) {
if (dialog) { element.addPropertyWord(Wt::Property::Class, "bulma-modal bulma-is-active");
element.addPropertyWord(Wt::Property::Class, "modal-content"); return;
} else if (auto text = dynamic_cast<Wt::WText *>(widget); text != nullptr) {
element.addPropertyWord(Wt::Property::Class, "is-size-6");
return; return;
} }
break; break;

View File

@ -12,6 +12,7 @@ class BulmaTheme : public Wt::WTheme {
public: public:
BulmaTheme(const std::string &name, bool global = true); BulmaTheme(const std::string &name, bool global = true);
std::string name() const final; std::string name() const final;
void init(Wt::WApplication *app) const final;
std::string disabledClass() const final; std::string disabledClass() const final;
std::string activeClass() const final; std::string activeClass() const final;
std::string utilityCssClass(int utilityCssClassRole) const final; std::string utilityCssClass(int utilityCssClassRole) const final;

View File

@ -2,8 +2,9 @@ find_package(Wt REQUIRED Wt)
add_library(WebApplication add_library(WebApplication
Application.h Application.cpp Application.h Application.cpp
LoginPage.h LoginPage.cpp
BulmaTheme.h BulmaTheme.cpp BulmaTheme.h BulmaTheme.cpp
HomePage.h HomePage.cpp
LoginPage.h LoginPage.cpp
VisitorRecordsPage.h VisitorRecordsPage.cpp VisitorRecordsPage.h VisitorRecordsPage.cpp
VisitorRecordTableModel.h VisitorRecordTableModel.cpp VisitorRecordTableModel.h VisitorRecordTableModel.cpp
Restful.h Restful.cpp Restful.h Restful.cpp

View File

@ -9,7 +9,7 @@ Dialog::Dialog() {
textdiv->setStyleClass("text"); textdiv->setStyleClass("text");
Wt::WContainerWidget *buttons = addWidget(std::make_unique<Wt::WContainerWidget>()); Wt::WContainerWidget *buttons = addWidget(std::make_unique<Wt::WContainerWidget>());
buttons->setStyleClass("buttons"); buttons->setStyleClass("bulma-buttons");
Wt::WPushButton *button = buttons->addWidget(std::make_unique<Wt::WPushButton>("One liner")); Wt::WPushButton *button = buttons->addWidget(std::make_unique<Wt::WPushButton>("One liner"));
button->clicked().connect(this, &Dialog::messageBox1); button->clicked().connect(this, &Dialog::messageBox1);
@ -42,8 +42,7 @@ void Dialog::messageBox1() {
void Dialog::messageBox2() { void Dialog::messageBox2() {
m_messageBox = std::make_unique<Wt::WMessageBox>("Question", "Are you getting comfortable?", Wt::Icon::Question, m_messageBox = std::make_unique<Wt::WMessageBox>("Question", "Are you getting comfortable?", Wt::Icon::Question,
Wt::StandardButton::Yes | Wt::StandardButton::No | Wt::StandardButton::Yes | Wt::StandardButton::No | Wt::StandardButton::Cancel);
Wt::StandardButton::Cancel);
m_messageBox->buttonClicked().connect(this, &Dialog::messageBoxDone); m_messageBox->buttonClicked().connect(this, &Dialog::messageBoxDone);
@ -68,14 +67,13 @@ void Dialog::messageBox4() {
Wt::Icon::None, Wt::StandardButton::None); Wt::Icon::None, Wt::StandardButton::None);
m_messageBox->addButton("Discard Modifications", Wt::StandardButton::Ok); m_messageBox->addButton("Discard Modifications", Wt::StandardButton::Ok);
m_messageBox->setMovable(false);
m_messageBox->setClosable(true);
Wt::WPushButton *continueButton = m_messageBox->addButton("Cancel", Wt::StandardButton::Cancel); Wt::WPushButton *continueButton = m_messageBox->addButton("Cancel", Wt::StandardButton::Cancel);
m_messageBox->setDefaultButton(continueButton); m_messageBox->setDefaultButton(continueButton);
m_messageBox->buttonClicked().connect(this, &Dialog::messageBoxDone); m_messageBox->buttonClicked().connect(this, &Dialog::messageBoxDone);
m_messageBox->animateShow(Wt::WAnimation(Wt::AnimationEffect::SlideInFromBottom | Wt::AnimationEffect::Fade, Wt::TimingFunction::Linear, 250));
m_messageBox->setOffsets(0, Wt::Side::Bottom);
m_messageBox->animateShow(Wt::WAnimation(Wt::AnimationEffect::SlideInFromBottom | Wt::AnimationEffect::Fade,
Wt::TimingFunction::Linear, 250));
} }
void Dialog::custom() { void Dialog::custom() {

View File

@ -0,0 +1,39 @@
#include "HomePage.h"
#include "Dialog.h"
#include <Wt/WApplication.h>
#include <Wt/WLineEdit.h>
#include <Wt/WPushButton.h>
HomePage::HomePage() {
addStyleClass("bulma-content");
auto p = addWidget(std::make_unique<Wt::WText>("这是一个结合 C++ Web Toolkit 和 CSS Bulma 框架的前后端一体应用程序。"));
p->setInline(false);
auto ul = addWidget(std::make_unique<Wt::WContainerWidget>());
ul->setList(true);
auto li = ul->addWidget(std::make_unique<Wt::WText>(R"(<a href="/wt/login">登录页面</a>)"));
li->setHtmlTagName("li");
li = ul->addWidget(std::make_unique<Wt::WText>(R"(<a href="/wt/visitor/analysis">访客数据</a>)"));
li->setHtmlTagName("li");
addWidget(std::make_unique<Wt::WText>("Your name, please ? "));
m_nameEdit = addWidget(std::make_unique<Wt::WLineEdit>());
m_nameEdit->setFocus();
auto b = addWidget(std::make_unique<Wt::WPushButton>("点击我!"));
b->setMargin(5, Wt::Side::Left);
addWidget(std::make_unique<Wt::WBreak>());
m_greeting = addWidget(std::make_unique<Wt::WText>());
b->clicked().connect(this, &HomePage::greet);
m_nameEdit->enterPressed().connect(this, &HomePage::greet);
addWidget(std::make_unique<Dialog>());
}
void HomePage::greet() {
m_greeting->setText("Hello there, " + m_nameEdit->text());
Wt::WApplication::instance()->setInternalPath("/hello");
}

18
WebApplication/HomePage.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef __HOMEPAGE_H__
#define __HOMEPAGE_H__
#include <Wt/WContainerWidget.h>
class HomePage : public Wt::WContainerWidget {
public:
HomePage();
protected:
void greet();
private:
Wt::WLineEdit *m_nameEdit = nullptr;
Wt::WText *m_greeting = nullptr;
};
#endif // __HOMEPAGE_H__

View File

@ -273,6 +273,6 @@
</message> </message>
<message id="Wt.WDialog.titlebar"> <message id="Wt.WDialog.titlebar">
<h4>${title}</h4> <h4 class="bulma-modal-card-title">${title}</h4>
</message> </message>
</messages> </messages>