From 343a3df6bde6fd3b3d8a262ba8294a9f9bc963d1 Mon Sep 17 00:00:00 2001 From: Liu Date: Mon, 30 Sep 2019 15:41:44 +0800 Subject: [PATCH] feat: add message --- demo/app/assets/views/documentation.xml | 10 +- demo/demo.vcxproj | 5 +- demo/demo.vcxproj.filters | 11 +- demo/include/ui.h | 25 ++-- demo/src/main.c | 1 + ...umentation_view.c => documentation-view.c} | 0 .../src/ui/views/{home_view.c => home-view.c} | 0 demo/src/ui/views/message-view.c | 77 ++++++++++ docs/components/message.md | 137 ++++++++++++++++++ docs/components/toasts.md | 81 ----------- include/LCDesign/ui/components.h | 1 + include/LCDesign/ui/components/message.h | 34 +++++ main.vcxproj | 2 + main.vcxproj.filters | 2 + src/scss/_message.scss | 69 +++++++++ src/scss/_toasts.scss | 63 -------- src/scss/_variables.scss | 36 ++--- src/scss/lc-design.scss | 2 +- src/ui/components/message.c | 132 +++++++++++++++++ 19 files changed, 498 insertions(+), 190 deletions(-) rename demo/src/ui/views/{documentation_view.c => documentation-view.c} (100%) rename demo/src/ui/views/{home_view.c => home-view.c} (100%) create mode 100644 demo/src/ui/views/message-view.c create mode 100644 docs/components/message.md delete mode 100644 docs/components/toasts.md create mode 100644 include/LCDesign/ui/components/message.h create mode 100644 src/scss/_message.scss delete mode 100644 src/scss/_toasts.scss create mode 100644 src/ui/components/message.c diff --git a/demo/app/assets/views/documentation.xml b/demo/app/assets/views/documentation.xml index e82eabf..3fc5c19 100644 --- a/demo/app/assets/views/documentation.xml +++ b/demo/app/assets/views/documentation.xml @@ -95,6 +95,11 @@ Radio + + + Message + + Modal @@ -105,11 +110,6 @@ Tooltips - - - Toasts - - Spinners diff --git a/demo/demo.vcxproj b/demo/demo.vcxproj index bde544c..3bbb944 100644 --- a/demo/demo.vcxproj +++ b/demo/demo.vcxproj @@ -188,8 +188,9 @@ xcopy "$(SolutionDir)dist\assets" "$(ProjectDir)app\assets" /S /Y - - + + + diff --git a/demo/demo.vcxproj.filters b/demo/demo.vcxproj.filters index 246f11d..a3f967a 100644 --- a/demo/demo.vcxproj.filters +++ b/demo/demo.vcxproj.filters @@ -21,16 +21,19 @@ 源文件 - + 源文件 - + 源文件 - + 源文件 - + + 源文件 + + 源文件 diff --git a/demo/include/ui.h b/demo/include/ui.h index d6f34df..6e1cd01 100644 --- a/demo/include/ui.h +++ b/demo/include/ui.h @@ -1,8 +1,8 @@ -#define ID_SIDEBAR_LINKS "demo-sidebar-links" -#define ID_NAVBAR_LINKS "demo-navbar-links" -#define ID_LINK_NAV_HOME "navbar-link-home" -#define ID_LINK_NAV_DOCS "navbar-link-docs" -#define ID_LINK_GETTING_STARTED "doc-link-getting-strted" +#define ID_SIDEBAR_LINKS "demo-sidebar-links" +#define ID_NAVBAR_LINKS "demo-navbar-links" +#define ID_LINK_NAV_HOME "navbar-link-home" +#define ID_LINK_NAV_DOCS "navbar-link-docs" +#define ID_LINK_GETTING_STARTED "doc-link-getting-strted" typedef enum NavigationPointId { NAV_NONE, @@ -11,13 +11,14 @@ typedef enum NavigationPointId { NAV_TOTAL_NUM } NavigationPointId; +void ActiveLink(LCUI_Widget parent, const char *link_id); -void ActiveLink( LCUI_Widget parent, const char *link_id ); +void Navbar_Init(void); +void Navigation_Init(void); -void Navbar_Init( void ); -void Navigation_Init( void ); +void DocumentationView_Init(void); +void DocumentationView_Free(void); +void HomeView_Init(void); +void HomeView_Free(void); -void DocumentationView_Init( void ); -void DocumentationView_Free( void ); -void HomeView_Init( void ); -void HomeView_Free( void ); +void UI_InitMessageView(void); diff --git a/demo/src/main.c b/demo/src/main.c index acae31f..7263a11 100644 --- a/demo/src/main.c +++ b/demo/src/main.c @@ -23,6 +23,7 @@ int main(int argc, char **argv) Widget_Unwrap(pack); Widget_SetTitleW(root, L"LC Design - A UI component framework for building LCUI application."); Navigation_Init(); + UI_InitMessageView(); Navbar_Init(); return LCUI_Main(); } diff --git a/demo/src/ui/views/documentation_view.c b/demo/src/ui/views/documentation-view.c similarity index 100% rename from demo/src/ui/views/documentation_view.c rename to demo/src/ui/views/documentation-view.c diff --git a/demo/src/ui/views/home_view.c b/demo/src/ui/views/home-view.c similarity index 100% rename from demo/src/ui/views/home_view.c rename to demo/src/ui/views/home-view.c diff --git a/demo/src/ui/views/message-view.c b/demo/src/ui/views/message-view.c new file mode 100644 index 0000000..87c3615 --- /dev/null +++ b/demo/src/ui/views/message-view.c @@ -0,0 +1,77 @@ +#include +#include +#include + +static LCUI_WidgetPrototype message_view_proto; + +static void OpenNormalMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenInfoMessage(L"This is a normal message", 3000); +} + +static void OpenSuccessMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenSuccessMessage(L"This is a success message", 3000); +} + +static void OpenWarningMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenWarningMessage(L"This is a warning message", 3000); +} + +static void OpenErrorMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenErrorMessage(L"This is a error message", 3000); +} + +static void OpenCustomDurationMessage(LCUI_Widget w, LCUI_WidgetEvent e, + void *arg) +{ + LCDesign_OpenSuccessMessage(L"This is a prompt message for success, " + L"and it will disappear in 10 seconds", + 10000); +} + +static void OpenLoadingMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenLoadingMessage(L"Action in progress..", 3000); +} + +static void MessageView_OnReady(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + Dict *dict; + LCUI_Widget btn; + + dict = Widget_CollectReferences(w); + btn = Dict_FetchValue(dict, "open-normal-message"); + Widget_BindEvent(btn, "click", OpenNormalMessage, NULL, NULL); + + btn = Dict_FetchValue(dict, "open-success-message"); + Widget_BindEvent(btn, "click", OpenSuccessMessage, NULL, NULL); + + btn = Dict_FetchValue(dict, "open-warning-message"); + Widget_BindEvent(btn, "click", OpenWarningMessage, NULL, NULL); + + btn = Dict_FetchValue(dict, "open-error-message"); + Widget_BindEvent(btn, "click", OpenErrorMessage, NULL, NULL); + + btn = Dict_FetchValue(dict, "open-custom-duration-message"); + Widget_BindEvent(btn, "click", OpenCustomDurationMessage, NULL, NULL); + + btn = Dict_FetchValue(dict, "open-loading-message"); + Widget_BindEvent(btn, "click", OpenLoadingMessage, NULL, NULL); + + Dict_Release(dict); + Widget_UnbindEvent(w, "ready", MessageView_OnReady); +} + +static void MessageView_OnInit(LCUI_Widget w) +{ + Widget_BindEvent(w, "ready", MessageView_OnReady, NULL, NULL); +} + +void UI_InitMessageView(void) +{ + message_view_proto = LCUIWidget_NewPrototype("message-view", NULL); + message_view_proto->init = MessageView_OnInit; +} diff --git a/docs/components/message.md b/docs/components/message.md new file mode 100644 index 0000000..e83d536 --- /dev/null +++ b/docs/components/message.md @@ -0,0 +1,137 @@ +# Message + +Display global messages as feedback in response to user operations. + +## Normal prompt + +Normal message for information. + +``` embedded-xml + + + +``` + +``` c +#include +#include +#include + +static void OpenMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenInfoMessage(L"This is a normal message", 3000); +} + +// ... other code + + LCUI_Widget btn = LCUIWidget_GetById("btn-open-message"); + Widget_BindEvent(btn, "click", OpenMessage, NULL, NULL); + +// ... other code +``` + +## Other types of message + +Messages of success, error and warning types. + +``` embedded-xml + + + + + +``` + +``` c +#include +#include +#include + +static void OpenSuccessMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenSuccessMessage(L"This is a success message", 3000); +} + +static void OpenWarningMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenWarningMessage(L"This is a warning message", 3000); +} + +static void OpenErrorMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenErrorMessage(L"This is a error message", 3000); +} + +// ... other code + + LCUI_Widget btn; + + btn = LCUIWidget_GetById("btn-open-success-message"); + Widget_BindEvent(btn, "click", OpenSuccessMessage, NULL, NULL); + + btn = LCUIWidget_GetById("btn-open-warning-message"); + Widget_BindEvent(btn, "click", OpenWarningMessage, NULL, NULL); + + btn = LCUIWidget_GetById("btn-open-error-message"); + Widget_BindEvent(btn, "click", OpenErrorMessage, NULL, NULL); + +// ... other code +``` + +## Customize duration + +Customize message display duration to `10s`. + +``` embedded-xml + + + +``` + +``` c +#include +#include +#include + +static void OpenMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenSuccessMessage(L"This is a prompt message for success, " + L"and it will disappear in 10 seconds", + 10000); +} + +// ... other code + + LCUI_Widget btn = LCUIWidget_GetById("btn-open-message"); + Widget_BindEvent(btn, "click", OpenMessage, NULL, NULL); + +// ... other code +``` + +## Message with loading indicator + +Display a global loading indicator, which is dismissed by itself asynchronously. + +``` embedded-xml + + + +``` + +``` c +#include +#include +#include + +static void OpenMessage(LCUI_Widget w, LCUI_WidgetEvent e, void *arg) +{ + LCDesign_OpenLoadingMessage(L"Action in progress..", 3000); +} + +// ... other code + + LCUI_Widget btn = LCUIWidget_GetById("btn-open-message"); + Widget_BindEvent(btn, "click", OpenMessage, NULL, NULL); + +// ... other code +``` diff --git a/docs/components/toasts.md b/docs/components/toasts.md deleted file mode 100644 index a5664a5..0000000 --- a/docs/components/toasts.md +++ /dev/null @@ -1,81 +0,0 @@ -# Toasts - -Push notifications to your visitors with a toast, a lightweight and easily customizable alert message. - -Toasts are lightweight notifications designed to mimic the push notifications that have been popularized by mobile and desktop operating systems. - -## Examples - -### Basic - -To encourage extensible and predictable toasts, we recommend a header and body. - -``` basic-toast-demo-xml - - - - LC Design - - 11 mins ago - - - - - Hello, world! This is a toast message. - - -``` - -### Translucent - -Toasts are slightly translucent, too, so they blend over whatever they might appear over. - -``` translucent-toast-demo-xml - - - - LC Design - - 11 mins ago - - - - - Hello, world! This is a toast message. - - -``` - -### Stacking - -When you have multiple toasts, we default to vertically stacking them in a readable manner. - -``` stacking-toast-demo-xml - - - - LC Design - - just now - - - - - See? Just like this. - - - - - - - LC Design - - 2 seconds ago - - - - - Heads up, toasts will stack automatically - - -``` diff --git a/include/LCDesign/ui/components.h b/include/LCDesign/ui/components.h index 7585912..e45d5c7 100644 --- a/include/LCDesign/ui/components.h +++ b/include/LCDesign/ui/components.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #endif diff --git a/include/LCDesign/ui/components/message.h b/include/LCDesign/ui/components/message.h new file mode 100644 index 0000000..df8ff1e --- /dev/null +++ b/include/LCDesign/ui/components/message.h @@ -0,0 +1,34 @@ +#ifndef LCDESIGN_MESSAGE_H +#define LCDESIGN_MESSAGE_H + +typedef struct LCDesign_MessageConfigRec_ { + /** Customized Icon */ + LCUI_Widget icon; + + /** content of the message */ + const wchar_t *content; + + /** time(milliseconds) before auto-dismiss, don't dismiss if set to 0 */ + long duration; +} LCDesign_MessageConfigRec, *LCDesign_MessageConfig; + +LCUI_API LCUI_Widget LCDesign_OpenMessage(LCDesign_MessageConfig config); + +LCUI_API void LCDesign_CloseMessage(LCUI_Widget message); + +LCUI_API LCUI_Widget LCDesign_OpenSuccessMessage(const wchar_t *content, + long duration); + +LCUI_API LCUI_Widget LCDesign_OpenInfoMessage(const wchar_t *content, + long duration); + +LCUI_API LCUI_Widget LCDesign_OpenWarningMessage(const wchar_t *content, + long duration); + +LCUI_API LCUI_Widget LCDesign_OpenErrorMessage(const wchar_t *content, + long duration); + +LCUI_API LCUI_Widget LCDesign_OpenLoadingMessage(const wchar_t *content, + long duration); + +#endif diff --git a/main.vcxproj b/main.vcxproj index 16caa23..441b658 100644 --- a/main.vcxproj +++ b/main.vcxproj @@ -167,6 +167,7 @@ + @@ -188,6 +189,7 @@ + diff --git a/main.vcxproj.filters b/main.vcxproj.filters index de66dd5..ed5e388 100644 --- a/main.vcxproj.filters +++ b/main.vcxproj.filters @@ -19,6 +19,7 @@ + @@ -40,5 +41,6 @@ + \ No newline at end of file diff --git a/src/scss/_message.scss b/src/scss/_message.scss new file mode 100644 index 0000000..4817e31 --- /dev/null +++ b/src/scss/_message.scss @@ -0,0 +1,69 @@ +.message-notice-container { + top: 0; + left: 0; + width: 100%; + padding: map-get($spacers, 2); + z-index: $zindex-message-notice; + position: absolute; + pointer-events: none; +} + +.message-notice-wrapper { + display: flex; + justify-content: center; + padding: map-get($spacers, 2) 0; + margin: 0 0 map-get($spacers, 2) 0; +} + +.message-notice { + display: inline-block; + padding: $message-notice-padding-y $message-notice-padding-x; + background-color: $message-notice-bg; + border: $message-notice-border; + border-radius: $border-radius; + pointer-events: auto; +} + +.message-notice-icon { + width: $message-notice-icon-size; + height: $message-notice-icon-size; + font-size: $message-notice-icon-size; + line-height: $message-notice-icon-size; + margin-right: map-get($spacers, 2); + display: inline-block; +} + +.message-notice-content { + text-align: center; + display: inline-block; +} + +.message-notice-success { + .message-notice-icon { + color: $green; + } +} + +.message-notice-info { + .message-notice-icon { + color: $blue; + } +} + +.message-notice-warning { + .message-notice-icon { + color: $orange; + } +} + +.message-notice-error { + .message-notice-icon { + color: $red; + } +} + +.message-notice-loading { + .message-notice-icon { + color: $primary; + } +} \ No newline at end of file diff --git a/src/scss/_toasts.scss b/src/scss/_toasts.scss deleted file mode 100644 index 7bacee4..0000000 --- a/src/scss/_toasts.scss +++ /dev/null @@ -1,63 +0,0 @@ -.toast { - max-width: $toast-max-width; - background-color: $toast-background-color; - background-clip: padding-box; - border: $toast-border-width solid $toast-border-color; - box-shadow: $toast-box-shadow; - margin-bottom: $toast-padding-x; - opacity: 0; - - @include text { - font-size: $toast-font-size; - } - - @include border-radius($toast-border-radius); - - small, small { - font-size: $toast-font-size * 0.8; - } - - &:last-child { - margin-bottom: 0; - } - - &.showing { - opacity: 1; - } - - &.show { - display: block; - opacity: 1; - } - - &.hide { - display: none; - } -} - -.toast-header { - @include text { - color: $toast-header-color; - } - - padding: $toast-padding-y $toast-padding-x; - background-color: $toast-header-background-color; - border-bottom: $toast-border-width solid $toast-header-border-color; -} - -.toast-header-right { - @include float-right; - - top: $toast-padding-y; - right: $toast-padding-x; - - .close { - top: -$toast-padding-y; - font-size: $close-font-size; - position: relative; - } -} - -.toast-body { - padding: $toast-padding-x; // apply to both vertical and horizontal -} diff --git a/src/scss/_variables.scss b/src/scss/_variables.scss index b67b34a..2e08d66 100644 --- a/src/scss/_variables.scss +++ b/src/scss/_variables.scss @@ -95,7 +95,7 @@ $yiq-text-light: $white !default; // Quickly modify global styling by enabling or disabling optional features. $enable-caret: true !default; -$enable-rounded: false !default; +$enable-rounded: true !default; $enable-shadows: true !default; $enable-gradients: false !default; $enable-transitions: false !default; @@ -184,9 +184,9 @@ $line-height-sm: 1.5 !default; $border-width: 1px !default; $border-color: $gray-200 !default; -$border-radius: 0; -$border-radius-lg: 0; -$border-radius-sm: 0; +$border-radius: 4px !default; +$border-radius-lg: 6px !default; +$border-radius-sm: 3px !default; $box-shadow-sm: 0 rem2px(.125) rem2px(.25) rgba($black, .075) !default; $box-shadow: 0 rem2px(.5) rem2px(1) rgba($black, .15) !default; @@ -405,23 +405,6 @@ $tooltip-arrow-height: rem2px(.4) !default; $tooltip-arrow-color: $tooltip-bg !default; -// Toasts - -$toast-max-width: 350px !default; -$toast-padding-x: rem2px(.75) !default; -$toast-padding-y: rem2px(.25) !default; -$toast-font-size: rem2px(.875) !default; -$toast-background-color: rgba($white, .85) !default; -$toast-border-width: 1px !default; -$toast-border-color: rgba(0, 0, 0, .1) !default; -$toast-border-radius: $border-radius !default; -$toast-box-shadow: $box-shadow !default; - -$toast-header-color: $gray-600 !default; -$toast-header-background-color: rgba($white, .85) !default; -$toast-header-border-color: rgba(0, 0, 0, .05) !default; - - // Z-index master list // // Warning: Avoid customizing these values. They're used for a bird's eye view @@ -430,9 +413,9 @@ $toast-header-border-color: rgba(0, 0, 0, .05) !default; $zindex-dropdown: 1000 !default; $zindex-modal-backdrop: 1040 !default; $zindex-modal: 1050 !default; +$zindex-message-notice: 1060 !default; $zindex-tooltip: 1070 !default; - // Navs $nav-link-padding-y: rem2px(.5) !default; @@ -599,3 +582,12 @@ $radio-inner-icon-size: $radio-size - $radio-border-width * 2 - $radio-inner-ico $radio-checked-color: $primary; $radio-disabled-bg: $gray-100; $radio-disabled-color: $gray-600; + + +// Message + +$message-notice-bg: $white; +$message-notice-icon-size: $font-size-base * 1.5; +$message-notice-padding-x: map-get($spacers, 3); +$message-notice-padding-y: map-get($spacers, 2); +$message-notice-border: $border-width solid $border-color; diff --git a/src/scss/lc-design.scss b/src/scss/lc-design.scss index fd295ec..ca59861 100644 --- a/src/scss/lc-design.scss +++ b/src/scss/lc-design.scss @@ -19,6 +19,6 @@ @import "switch"; @import "close"; @import "modal"; -@import "toasts"; +@import "message"; @import "tooltip"; @import "utilities"; diff --git a/src/ui/components/message.c b/src/ui/components/message.c new file mode 100644 index 0000000..d032165 --- /dev/null +++ b/src/ui/components/message.c @@ -0,0 +1,132 @@ + + +#include +#include +#include +#include +#include +#include + +static LCUI_Widget container; + +LCUI_Widget LCDesign_OpenMessage(LCDesign_MessageConfig config) +{ + LCUI_Widget wrapper; + LCUI_Widget message; + LCUI_Widget content; + + if (!container) { + container = LCUIWidget_New(NULL); + Widget_AddClass(container, "message-notice-container"); + Widget_Append(LCUIWidget_GetRoot(), container); + } + wrapper = LCUIWidget_New(NULL); + message = LCUIWidget_New(NULL); + content = LCUIWidget_New("text"); + if (config->icon) { + Widget_AddClass(config->icon, "message-notice-icon"); + Widget_Append(message, config->icon); + } + Widget_AddClass(wrapper, "message-notice-wrapper"); + Widget_AddClass(message, "message-notice"); + Widget_AddClass(content, "message-notice-content"); + TextView_SetTextW(content, config->content); + Widget_Append(message, content); + Widget_Append(wrapper, message); + Widget_Append(container, wrapper); + if (config->duration > 0) { + LCUI_SetTimeout(config->duration, + (TimerCallback)LCDesign_CloseMessage, wrapper); + } + return wrapper; +} + +void LCDesign_CloseMessage(LCUI_Widget message) +{ + Widget_Destroy(message); +} + +LCUI_Widget LCDesign_OpenSuccessMessage(const wchar_t *content, long duration) +{ + LCUI_Widget icon; + LCUI_Widget message; + LCDesign_MessageConfigRec config; + + icon = LCUIWidget_New("icon"); + Icon_SetName(icon, "check-circle"); + + config.icon = icon; + config.content = content; + config.duration = duration; + message = LCDesign_OpenMessage(&config); + Widget_AddClass(message, "message-notice-success"); + return message; +} + +LCUI_Widget LCDesign_OpenInfoMessage(const wchar_t *content, long duration) +{ + LCUI_Widget icon; + LCUI_Widget message; + LCDesign_MessageConfigRec config; + + icon = LCUIWidget_New("icon"); + Icon_SetName(icon, "information"); + + config.icon = icon; + config.content = content; + config.duration = duration; + message = LCDesign_OpenMessage(&config); + Widget_AddClass(message, "message-notice-info"); + return message; +} + +LCUI_Widget LCDesign_OpenWarningMessage(const wchar_t *content, long duration) +{ + LCUI_Widget icon; + LCUI_Widget message; + LCDesign_MessageConfigRec config; + + icon = LCUIWidget_New("icon"); + Icon_SetName(icon, "alert-circle"); + + config.icon = icon; + config.content = content; + config.duration = duration; + message = LCDesign_OpenMessage(&config); + Widget_AddClass(message, "message-notice-warning"); + return message; +} + +LCUI_Widget LCDesign_OpenErrorMessage(const wchar_t *content, long duration) +{ + LCUI_Widget icon; + LCUI_Widget message; + LCDesign_MessageConfigRec config; + + icon = LCUIWidget_New("icon"); + Icon_SetName(icon, "close-circle"); + + config.icon = icon; + config.content = content; + config.duration = duration; + message = LCDesign_OpenMessage(&config); + Widget_AddClass(message, "message-notice-error"); + return message; +} + +LCUI_Widget LCDesign_OpenLoadingMessage(const wchar_t *content, long duration) +{ + LCUI_Widget icon; + LCUI_Widget message; + LCDesign_MessageConfigRec config; + + icon = LCUIWidget_New("spinner"); + Widget_SetAttribute(icon, "type", "ring"); + + config.icon = icon; + config.content = content; + config.duration = duration; + message = LCDesign_OpenMessage(&config); + Widget_AddClass(message, "message-notice-loading"); + return message; +}