├── .gitignore ├── LICENSE ├── README.md ├── betternavi ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── vaadin │ │ └── example │ │ ├── AboutView.java │ │ ├── AboutViewDesign.java │ │ ├── DashboardView.java │ │ ├── DashboardViewDesign.java │ │ ├── MainLayout.java │ │ ├── MainLayoutDesign.java │ │ ├── MyUI.java │ │ ├── OrderView.java │ │ └── OrderViewDesign.java │ ├── resources │ └── org │ │ └── vaadin │ │ └── example │ │ ├── AboutViewDesign.html │ │ ├── DashboardViewDesign.html │ │ ├── MainLayoutDesign.html │ │ └── OrderViewDesign.html │ └── webapp │ └── VAADIN │ └── themes │ └── mytheme │ ├── addons.scss │ ├── designs.scss │ ├── favicon.ico │ ├── mytheme.scss │ └── styles.scss ├── emailclient-tutorial-data ├── README.adoc ├── pom.xml ├── src │ └── main │ │ ├── java │ │ └── org │ │ │ └── vaadin │ │ │ └── example │ │ │ ├── backend │ │ │ ├── AbstractEntity.java │ │ │ ├── CdiConfig.java │ │ │ ├── DatabaseInitialization.java │ │ │ ├── Message.java │ │ │ ├── MessageFacade.java │ │ │ └── MessageRepository.java │ │ │ └── ui │ │ │ ├── FolderView.java │ │ │ ├── MainLayout.java │ │ │ ├── MainLayoutDesign.java │ │ │ ├── MessageComponent.java │ │ │ ├── MessageDesign.java │ │ │ ├── MessageModifiedEvent.java │ │ │ ├── MyUI.java │ │ │ └── themes │ │ │ └── mytheme │ │ │ └── MyTheme.java │ │ ├── resources │ │ ├── META-INF │ │ │ ├── apache-deltaspike.properties │ │ │ └── persistence.xml │ │ └── org │ │ │ └── vaadin │ │ │ └── example │ │ │ └── ui │ │ │ ├── MainLayoutDesign.html │ │ │ └── MessageDesign.html │ │ └── webapp │ │ ├── VAADIN │ │ └── themes │ │ │ └── mytheme │ │ │ ├── addons.scss │ │ │ ├── designs.scss │ │ │ ├── favicon.ico │ │ │ ├── mytheme.scss │ │ │ └── styles.scss │ │ └── WEB-INF │ │ └── beans.xml └── tutorial-images │ └── email-client-with-data.png ├── emailclient-tutorial ├── README.md ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── vaadin │ │ └── example │ │ ├── ApplicationDesign.java │ │ ├── Message.java │ │ ├── MessageDesign.java │ │ └── MyUI.java │ ├── resources │ └── org │ │ └── vaadin │ │ └── example │ │ ├── ApplicationDesign.html │ │ └── MessageDesign.html │ └── webapp │ └── VAADIN │ └── themes │ └── mytheme │ ├── addons.scss │ ├── designs.scss │ ├── favicon.ico │ ├── mytheme.scss │ └── styles.scss └── simplenavi ├── README.md ├── pom.xml └── src └── main ├── java └── org │ └── vaadin │ └── example │ ├── MainLayout.java │ ├── MainLayoutDesign.java │ ├── MyUI.java │ ├── PermissionsView.java │ ├── PermissionsViewDesign.java │ ├── PluginsView.java │ ├── PluginsViewDesign.java │ ├── StatsView.java │ └── StatsViewDesign.java ├── resources └── org │ └── vaadin │ └── example │ ├── MainLayoutDesign.html │ ├── PermissionsViewDesign.html │ ├── PluginsViewDesign.html │ └── StatsViewDesign.html └── webapp └── VAADIN └── themes └── mytheme ├── addons.scss ├── favicon.ico ├── mytheme.scss └── styles.scss /.gitignore: -------------------------------------------------------------------------------- 1 | .settings 2 | .project 3 | .classpath 4 | *.class 5 | rebel.xml 6 | target 7 | .designer 8 | styles.scss.cache 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vaadin Designer tutorials 2 | This repository contains sample codes of various tutorials related to Vaadin application development using Vaadin Designer. 3 | * simplenavi and betternavi are sample codes of a tutorial found here: https://vaadin.com/wiki/-/wiki/Main/View+navigation+with+Vaadin+Designer 4 | * emailclient-tutorial is about using Vaadin Designer to build a bit more complex application design. The tutorial is written in the readme file (nicely formatted of course) and contains a link to a nice video. 5 | * emailclient-tutorial-data shows you how to connect an existing datasource to your complex application design. The basis for the UI is the same as in emailclient-tutorial and the datasource is implemented as an EJB facade and Apache DeltaSpike repository. 6 | -------------------------------------------------------------------------------- /betternavi/README.md: -------------------------------------------------------------------------------- 1 | `This tutorial is written using Java 8` 2 | 3 | betternavi 4 | ============== 5 | 6 | Template for a simple Vaadin application that only requires a Servlet 3.0 container to run. 7 | 8 | 9 | Workflow 10 | ======== 11 | 12 | To compile the entire project, run "mvn install". 13 | To run the application, run "mvn jetty:run" and open http://localhost:8080/ . 14 | 15 | To develop the theme, simply update the relevant theme files and reload the application. 16 | Pre-compiling a theme eliminates automatic theme updates at runtime - see below for more information. 17 | 18 | Debugging client side code 19 | - run "mvn vaadin:run-codeserver" on a separate console while the application is running 20 | - activate Super Dev Mode in the debug window of the application 21 | 22 | To produce a deployable production mode WAR: 23 | - change productionMode to true in the servlet class configuration (nested in the UI class) 24 | - run "mvn clean vaadin:compile-theme package" 25 | - See below for more information. Running "mvn clean" removes the pre-compiled theme. 26 | - test with "mvn jetty:run-war 27 | 28 | Using a precompiled theme 29 | ------------------------- 30 | 31 | When developing the application, Vaadin can compile the theme on the fly when needed, 32 | or the theme can be precompiled to speed up page loads. 33 | 34 | To precompile the theme run "mvn vaadin:compile-theme". Note, though, that once 35 | the theme has been precompiled, any theme changes will not be visible until the 36 | next theme compilation or running the "mvn clean" target. 37 | 38 | When developing the theme, running the application in the "run" mode (rather than 39 | in "debug") in the IDE can speed up consecutive on-the-fly theme compilations 40 | significantly. 41 | -------------------------------------------------------------------------------- /betternavi/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.vaadin.example 6 | betternavi 7 | war 8 | 1.0-SNAPSHOT 9 | betternavi 10 | 11 | 12 | 3 13 | 14 | 15 | 16 | 7.7.3 17 | ${vaadin.version} 18 | 9.2.3.v20140905 19 | 1.8 20 | 1.8 21 | UTF-8 22 | 23 | local 24 | 25 | 26 | 27 | 28 | vaadin-addons 29 | https://maven.vaadin.com/vaadin-addons 30 | 31 | 32 | 33 | 34 | 35 | 36 | com.vaadin 37 | vaadin-bom 38 | ${vaadin.version} 39 | pom 40 | import 41 | 42 | 43 | 44 | 45 | 46 | 47 | javax.servlet 48 | javax.servlet-api 49 | 3.0.1 50 | provided 51 | 52 | 53 | com.vaadin 54 | vaadin-server 55 | 56 | 57 | com.vaadin 58 | vaadin-push 59 | 60 | 61 | com.vaadin 62 | vaadin-client-compiled 63 | 64 | 65 | com.vaadin 66 | vaadin-themes 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-compiler-plugin 75 | 3.0 76 | 77 | ${project.encoding} 78 | ${project.source.version} 79 | ${project.target.version} 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-resources-plugin 85 | 2.6 86 | 87 | ${project.encoding} 88 | 89 | 90 | 91 | org.apache.maven.plugins 92 | maven-war-plugin 93 | 2.3 94 | 95 | false 96 | 97 | WEB-INF/classes/VAADIN/gwt-unitCache/**, 98 | WEB-INF/classes/VAADIN/widgetsets/WEB-INF/** 99 | 100 | 101 | 102 | com.vaadin 103 | vaadin-maven-plugin 104 | ${vaadin.plugin.version} 105 | 106 | -Xmx512M -Xss1024k 107 | ${basedir}/target/classes/VAADIN/widgetsets 108 | false 109 | false 110 | 111 | true 112 | 113 | 114 | 115 | 116 | update-theme 117 | update-widgetset 118 | compile 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | org.apache.maven.plugins 127 | maven-source-plugin 128 | 2.4 129 | 130 | 131 | org.apache.maven.plugins 132 | maven-clean-plugin 133 | 2.6.1 134 | 135 | 136 | 137 | 138 | src/main/webapp/VAADIN/themes 139 | 140 | **/styles.css 141 | **/styles.scss.cache 142 | 143 | 144 | 145 | 146 | 147 | 148 | 150 | 151 | org.eclipse.jetty 152 | jetty-maven-plugin 153 | ${jetty.plugin.version} 154 | 155 | 2 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | vaadin-prerelease 165 | 166 | false 167 | 168 | 169 | 170 | 171 | vaadin-prereleases 172 | https://maven.vaadin.com/vaadin-prereleases 173 | 174 | 175 | vaadin-snapshots 176 | https://oss.sonatype.org/content/repositories/vaadin-snapshots/ 177 | 178 | false 179 | 180 | 181 | true 182 | 183 | 184 | 185 | 186 | 187 | vaadin-prereleases 188 | https://maven.vaadin.com/vaadin-prereleases 189 | 190 | 191 | vaadin-snapshots 192 | https://oss.sonatype.org/content/repositories/vaadin-snapshots/ 193 | 194 | false 195 | 196 | 197 | true 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /betternavi/src/main/java/org/vaadin/example/AboutView.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.navigator.View; 4 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; 5 | 6 | public class AboutView extends AboutViewDesign implements View { 7 | 8 | public static final String VIEW_NAME = "about"; 9 | 10 | @Override 11 | public void enter(ViewChangeEvent event) { 12 | // TODO Auto-generated method stub 13 | 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /betternavi/src/main/java/org/vaadin/example/AboutViewDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.VerticalLayout; 6 | import com.vaadin.ui.declarative.Design; 7 | 8 | /** 9 | * !! DO NOT EDIT THIS FILE !! 10 | * 11 | * This class is generated by Vaadin Designer and will be overwritten. 12 | * 13 | * Please make a subclass with logic and additional interfaces as needed, 14 | * e.g class LoginView extends LoginDesign implements View { … } 15 | */ 16 | @DesignRoot 17 | @AutoGenerated 18 | @SuppressWarnings("serial") 19 | public class AboutViewDesign extends VerticalLayout { 20 | public AboutViewDesign() { 21 | Design.read(this); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /betternavi/src/main/java/org/vaadin/example/DashboardView.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.navigator.View; 4 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; 5 | 6 | public class DashboardView extends DashboardViewDesign implements View { 7 | 8 | public static final String VIEW_NAME = "dashboard"; 9 | 10 | @Override 11 | public void enter(ViewChangeEvent event) { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /betternavi/src/main/java/org/vaadin/example/DashboardViewDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.CssLayout; 6 | import com.vaadin.ui.Label; 7 | import com.vaadin.ui.declarative.Design; 8 | 9 | /** 10 | * !! DO NOT EDIT THIS FILE !! 11 | * 12 | * This class is generated by Vaadin Designer and will be overwritten. 13 | * 14 | * Please make a subclass with logic and additional interfaces as needed, 15 | * e.g class LoginView extends LoginDesign implements View { … } 16 | */ 17 | @DesignRoot 18 | @AutoGenerated 19 | @SuppressWarnings("serial") 20 | public class DashboardViewDesign extends CssLayout { 21 | protected Label billing_header_label; 22 | protected CssLayout dashboard_item5; 23 | protected Label dashboard_item_header; 24 | protected Label statistics_label; 25 | protected Label statistics_label2; 26 | protected Label statistics_label4; 27 | protected Label statistics_label3; 28 | protected Label statistics_label5; 29 | protected CssLayout dashboard_item26; 30 | protected Label dashboard_item_header2; 31 | protected Label statistics_label6; 32 | protected Label statistics_label7; 33 | protected Label statistics_label8; 34 | protected Label statistics_label9; 35 | protected Label statistics_label10; 36 | protected CssLayout dashboard_item27; 37 | protected Label dashboard_item_header3; 38 | protected Label statistics_label18; 39 | protected Label statistics_label12; 40 | protected Label statistics_label16; 41 | protected Label statistics_label17; 42 | protected Label statistics_label19; 43 | 44 | public DashboardViewDesign() { 45 | Design.read(this); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /betternavi/src/main/java/org/vaadin/example/MainLayout.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import java.util.Iterator; 4 | 5 | import com.vaadin.navigator.Navigator; 6 | import com.vaadin.navigator.View; 7 | import com.vaadin.navigator.ViewDisplay; 8 | import com.vaadin.ui.Button; 9 | import com.vaadin.ui.Component; 10 | import com.vaadin.ui.UI; 11 | 12 | public class MainLayout extends MainLayoutDesign implements ViewDisplay { 13 | 14 | private static final String STYLE_SELECTED = "selected"; 15 | private Navigator navigator; 16 | 17 | public MainLayout() { 18 | navigator = new Navigator(UI.getCurrent(), (ViewDisplay) this); 19 | addNavigatorView(DashboardView.VIEW_NAME, DashboardView.class, 20 | menuButton1); 21 | addNavigatorView(OrderView.VIEW_NAME, OrderView.class, menuButton2); 22 | addNavigatorView(AboutView.VIEW_NAME, AboutView.class, menuButton3); 23 | if (navigator.getState().isEmpty()) { 24 | navigator.navigateTo(DashboardView.VIEW_NAME); 25 | } 26 | } 27 | 28 | private void doNavigate(String viewName) { 29 | getUI().getNavigator().navigateTo(viewName); 30 | } 31 | 32 | private void addNavigatorView(String viewName, 33 | Class viewClass, Button menuButton) { 34 | navigator.addView(viewName, viewClass); 35 | menuButton.addClickListener(event -> doNavigate(viewName)); 36 | menuButton.setData(viewClass.getName()); 37 | } 38 | 39 | private void adjustStyleByData(Component component, Object data) { 40 | if (component instanceof Button) { 41 | if (data != null && data.equals(((Button) component).getData())) { 42 | component.addStyleName(STYLE_SELECTED); 43 | } else { 44 | component.removeStyleName(STYLE_SELECTED); 45 | } 46 | } 47 | } 48 | 49 | @Override 50 | public void showView(View view) { 51 | if (view instanceof Component) { 52 | scroll_panel.setContent((Component) view); 53 | Iterator it = side_bar.iterator(); 54 | while (it.hasNext()) { 55 | adjustStyleByData(it.next(), view.getClass().getName()); 56 | } 57 | } else { 58 | throw new IllegalArgumentException("View is not a Component"); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /betternavi/src/main/java/org/vaadin/example/MainLayoutDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.CssLayout; 6 | import com.vaadin.ui.HorizontalLayout; 7 | import com.vaadin.ui.Label; 8 | import com.vaadin.ui.NativeButton; 9 | import com.vaadin.ui.Panel; 10 | import com.vaadin.ui.TextField; 11 | import com.vaadin.ui.VerticalLayout; 12 | import com.vaadin.ui.declarative.Design; 13 | 14 | /** 15 | * !! DO NOT EDIT THIS FILE !! 16 | * 17 | * This class is generated by Vaadin Designer and will be overwritten. 18 | * 19 | * Please make a subclass with logic and additional interfaces as needed, 20 | * e.g class LoginView extends LoginDesign implements View { … } 21 | */ 22 | @DesignRoot 23 | @AutoGenerated 24 | @SuppressWarnings("serial") 25 | public class MainLayoutDesign extends VerticalLayout { 26 | protected CssLayout header_bar; 27 | protected NativeButton user_menu; 28 | protected Label user_name_label; 29 | protected TextField search_field; 30 | protected HorizontalLayout main_area; 31 | protected CssLayout side_bar; 32 | protected NativeButton menuButton1; 33 | protected NativeButton menuButton2; 34 | protected NativeButton menuButton3; 35 | protected Panel scroll_panel; 36 | 37 | public MainLayoutDesign() { 38 | Design.read(this); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /betternavi/src/main/java/org/vaadin/example/MyUI.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import javax.servlet.annotation.WebServlet; 4 | 5 | import com.vaadin.annotations.Theme; 6 | import com.vaadin.annotations.VaadinServletConfiguration; 7 | import com.vaadin.server.VaadinRequest; 8 | import com.vaadin.server.VaadinServlet; 9 | import com.vaadin.ui.UI; 10 | 11 | /** 12 | * 13 | */ 14 | @Theme("mytheme") 15 | public class MyUI extends UI { 16 | 17 | @Override 18 | protected void init(VaadinRequest vaadinRequest) { 19 | setContent(new MainLayout()); 20 | } 21 | 22 | @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true) 23 | @VaadinServletConfiguration(ui = MyUI.class, productionMode = false) 24 | public static class MyUIServlet extends VaadinServlet { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /betternavi/src/main/java/org/vaadin/example/OrderView.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.navigator.View; 4 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; 5 | 6 | public class OrderView extends OrderViewDesign implements View { 7 | 8 | public static final String VIEW_NAME = "order"; 9 | 10 | @Override 11 | public void enter(ViewChangeEvent event) { 12 | // TODO Auto-generated method stub 13 | 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /betternavi/src/main/java/org/vaadin/example/OrderViewDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.CssLayout; 6 | import com.vaadin.ui.FormLayout; 7 | import com.vaadin.ui.HorizontalLayout; 8 | import com.vaadin.ui.Label; 9 | import com.vaadin.ui.NativeButton; 10 | import com.vaadin.ui.TextField; 11 | import com.vaadin.ui.declarative.Design; 12 | 13 | /** 14 | * !! DO NOT EDIT THIS FILE !! 15 | * 16 | * This class is generated by Vaadin Designer and will be overwritten. 17 | * 18 | * Please make a subclass with logic and additional interfaces as needed, 19 | * e.g class LoginView extends LoginDesign implements View { … } 20 | */ 21 | @DesignRoot 22 | @AutoGenerated 23 | @SuppressWarnings("serial") 24 | public class OrderViewDesign extends CssLayout { 25 | protected Label billing_header_label; 26 | protected CssLayout main_content_wrapper; 27 | protected FormLayout billing_form; 28 | protected Label email_header_label; 29 | protected TextField email_field; 30 | protected Label address_label; 31 | protected HorizontalLayout name_wrapper; 32 | protected TextField firstname_field; 33 | protected TextField lastname_field; 34 | protected TextField address_field; 35 | protected TextField company_field; 36 | protected TextField city_field; 37 | protected HorizontalLayout name_wrapper2; 38 | protected TextField state_field; 39 | protected TextField zip_field; 40 | protected TextField country_field; 41 | protected TextField phone_field; 42 | protected FormLayout order_summary_layout; 43 | protected Label order_heading; 44 | protected CssLayout order_item; 45 | protected Label order_label; 46 | protected NativeButton cancel_order_button; 47 | protected Label tax_sum; 48 | protected Label total_sum; 49 | 50 | public OrderViewDesign() { 51 | Design.read(this); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /betternavi/src/main/resources/org/vaadin/example/AboutViewDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | About view 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /betternavi/src/main/resources/org/vaadin/example/DashboardViewDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 85 | 86 | 87 | 88 | 89 | 90 | General Vaadin Statistics 91 | 92 | 93 | 94 | Monthly Vaadin Statistics 95 | 96 | 97 | Vaadin Addon Downloads 98 | 232,392 99 | 100 | 101 | Vaadin Designer Downloads 102 | 114,036 103 | 104 | 105 | Vaadin Charts Downloads 106 | 151,663 107 | 108 | 109 | Vaadin TestBench Downloads 110 | 96,691 111 | 112 | 113 | Vaadin Homepage Visits 114 | 471,484 115 | 116 | 117 | 118 | 119 | Vaadin Release Info 120 | 121 | 122 | Current Vaadin Version 123 | 7.5.4 124 | 125 | 126 | Open Framework Tickets 127 | 36 128 | 129 | 130 | Open Designer Tickets 131 | 12 132 | 133 | 134 | Open Vaadin Charts Tickets 135 | 23 136 | 137 | 138 | Next Vaadin Framework release 139 | 10.10.2010 140 | 141 | 142 | 143 | 144 | Upcoming Vaadin Trainings 145 | 146 | 147 | Turku, Finland 148 | Sep 9, 2015 149 | 150 | 151 | Berlin, Germany 152 | Sep 14, 2015 153 | 154 | 155 | San Jose, U.S 156 | Sep 21, 2015 157 | 158 | 159 | München, Germany 160 | Oct 5, 2015 161 | 162 | 163 | Rome, Italy 164 | Oct 19, 2015 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /betternavi/src/main/resources/org/vaadin/example/MainLayoutDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | John Smith 195 | 196 | 197 | 198 | 199 | 200 | 201 | Dashboard 202 | 203 | 204 | Order 205 | 206 | 207 | About 208 | 209 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /betternavi/src/main/resources/org/vaadin/example/OrderViewDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 145 | 146 | 147 | 148 | 149 | 150 | Billing Information 151 | 152 | 153 | 154 | 155 | Please enter your email address 156 | 157 | 158 | 159 | Please enter your billing address 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | Order Summary 178 | 179 | 180 | 181 | Vaadin Designer License 182 |
$ 389.00 183 |
184 | 185 |
186 | 187 | 188 | Tax : 189 | $0.00 190 | 191 | 192 | Total : 193 | $ 389.00 194 | 195 | 196 |
197 |
198 |
199 | 200 | -------------------------------------------------------------------------------- /betternavi/src/main/webapp/VAADIN/themes/mytheme/addons.scss: -------------------------------------------------------------------------------- 1 | /* This file is automatically managed and will be overwritten from time to time. */ 2 | /* Do not manually edit this file. */ 3 | 4 | /* Import and include this mixin into your project theme to include the addon themes */ 5 | @mixin addons { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /betternavi/src/main/webapp/VAADIN/themes/mytheme/designs.scss: -------------------------------------------------------------------------------- 1 | // Styles imported from MainLayoutDesign.html 2 | $v-font-size: 16px; 3 | $v-font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 4 | $v-border-radius: 0; 5 | $v-textfield-bevel: false; 6 | $v-textfield-shadow: false; 7 | $v-shadow: false; 8 | $v-bevel: false; 9 | $v-gradient: false; 10 | $v-textfield-border: 0; 11 | .root-layout.navigation-template-vaadin { 12 | $root-background-color: #ffffff; 13 | $main-color: #5AAAFA; 14 | $menu-color: #5AAAFA; 15 | $header-label-font-size: 1.618em; 16 | background-color: $root-background-color; 17 | 18 | .v-nativebutton{ 19 | background: none; 20 | border: none; 21 | 22 | &:hover{ 23 | cursor: pointer; 24 | } 25 | } 26 | 27 | .scroll-panel{ 28 | background-color: $root-background-color; 29 | border: none; 30 | border-radius: 0; 31 | } 32 | 33 | .header-bar{ 34 | background-color: $menu-color; 35 | padding: 0px 15px 0 15px; 36 | vertical-align: middle; 37 | height: 65px; 38 | 39 | > * { 40 | color: #FFFFFF; 41 | float: right; 42 | padding: 0; 43 | line-height: 20px; 44 | margin-left: 15px; 45 | 46 | /** Vertically center everything **/ 47 | position: relative; 48 | top: 50%; 49 | -webkit-transform: translateY(-50%); 50 | -ms-transform: translateY(-50%); 51 | transform: translateY(-50%); 52 | } 53 | 54 | > .search-field{ 55 | background: none; 56 | border-bottom: solid 2px #fff; 57 | padding-left: 5px; 58 | 59 | &.v-textfield-prompt{ 60 | color: #ffffff; 61 | font-style: italic; 62 | } 63 | } 64 | 65 | } 66 | 67 | .side-bar { 68 | 69 | background-color: #000; 70 | width: 100px; 71 | 72 | > .menu-button{ 73 | position: relative; 74 | color: $main-color; 75 | height: 90px; 76 | 77 | &.selected{ 78 | background-color: $root-background-color; 79 | 80 | .v-nativebutton-caption { 81 | color: #1A1314; 82 | } 83 | } 84 | 85 | .v-nativebutton-caption{ 86 | font-size: .7em; 87 | color: #E9E0E0; 88 | text-transform: uppercase; 89 | position: absolute; 90 | bottom: 8px; 91 | text-align: center; 92 | left: 0; 93 | right: 0; 94 | margin-left: auto; 95 | margin-right: auto; 96 | } 97 | 98 | .v-icon{ 99 | position: absolute; 100 | font-size: 35px; 101 | margin-left: auto; 102 | margin-right: auto; 103 | top: 10px; 104 | left: 0; 105 | right: 0; 106 | } 107 | } 108 | } 109 | 110 | .header-label{ 111 | font-size: $header-label-font-size; 112 | width: 100%; 113 | margin-bottom: 20px; 114 | color: #000000; 115 | border-bottom: 3px solid #D0C7C7; 116 | } 117 | 118 | .header-label-small{ 119 | width: 100%; 120 | color: $main-color; 121 | text-transform: uppercase; 122 | border-bottom: 2px solid #D0C7C7; 123 | } 124 | 125 | .dashboard-layout{ 126 | padding: 60px 60px 0 60px; 127 | } 128 | 129 | .dashboard-item{ 130 | background-color: #f6f3f3; 131 | border: 1px solid white; 132 | margin: 0 30px 30px 0px; 133 | padding: 15px; 134 | 135 | > .statistics-label{ 136 | margin-top: 15px; 137 | 138 | .statistics-value{ 139 | float: right; 140 | font-weight: bold; 141 | } 142 | } 143 | } 144 | 145 | &[width-range~="321px-768px"]{ 146 | .dashboard-layout{ 147 | padding: 10px; 148 | } 149 | 150 | .dashboard-item{ 151 | width: 100% !important; 152 | min-width: 321px; 153 | margin: 0; 154 | } 155 | 156 | .side-bar{ 157 | width: 60px; 158 | 159 | > .menu-button{ 160 | 161 | height: 50px; 162 | 163 | > .v-nativebutton-caption{ 164 | visibility: hidden; 165 | } 166 | 167 | > .v-icon{ 168 | top: 0; 169 | } 170 | } 171 | } 172 | 173 | .header-bar{ 174 | height: 45px; 175 | padding: 2px; 176 | } 177 | } 178 | } 179 | 180 | .navigation-template-vaadin[width-range~="321px-768px"]{ 181 | visibility: visible; 182 | } 183 | 184 | // Styles imported from DashboardViewDesign.html 185 | $v-font-size: 16px; 186 | $v-font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 187 | $v-border-radius: 0; 188 | $v-textfield-bevel: false; 189 | $v-textfield-shadow: false; 190 | $v-shadow: false; 191 | $v-bevel: false; 192 | $v-gradient: false; 193 | $v-textfield-border: 0; 194 | .root-layout.dashboard-view-template-vaadin { 195 | $root-background-color: #ffffff; 196 | $main-color: #5AAAFA; 197 | $menu-color: #5AAAFA; 198 | $header-label-font-size: 1.618em; 199 | background-color: $root-background-color; 200 | padding: 60px; 201 | 202 | .v-nativebutton{ 203 | background: none; 204 | border: none; 205 | 206 | &:hover{ 207 | cursor: pointer; 208 | } 209 | } 210 | 211 | .header-label{ 212 | font-size: $header-label-font-size; 213 | width: 100%; 214 | margin-bottom: 20px; 215 | color: #000000; 216 | border-bottom: 3px solid #D0C7C7; 217 | } 218 | 219 | .header-label-small{ 220 | width: 100%; 221 | color: $main-color; 222 | text-transform: uppercase; 223 | border-bottom: 2px solid #D0C7C7; 224 | } 225 | 226 | .dashboard-layout{ 227 | padding: 60px 60px 0 60px; 228 | } 229 | 230 | .dashboard-item{ 231 | background-color: #f6f3f3; 232 | border: 1px solid white; 233 | margin: 0 30px 30px 0px; 234 | padding: 15px; 235 | 236 | > .statistics-label{ 237 | margin-top: 15px; 238 | 239 | .statistics-value{ 240 | float: right; 241 | font-weight: bold; 242 | } 243 | } 244 | } 245 | 246 | &[width-range~="321px-768px"]{ 247 | padding: 10px; 248 | 249 | .dashboard-layout{ 250 | padding: 10px; 251 | } 252 | 253 | .dashboard-item{ 254 | width: 100% !important; 255 | min-width: 321px; 256 | margin: 0; 257 | } 258 | } 259 | } 260 | 261 | .dashboard-view-template-vaadin[width-range~="321px-768px"]{ 262 | visibility: visible; 263 | } 264 | 265 | // Styles imported from OrderViewDesign.html 266 | $v-font-size: 16px; 267 | $v-font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 268 | $v-border-radius: 0; 269 | $v-textfield-bevel: false; 270 | $v-textfield-shadow: false; 271 | $v-shadow: false; 272 | $v-bevel: false; 273 | $v-gradient: false; 274 | $v-textfield-border: 0; 275 | .root-layout.form-template-vaadin { 276 | $root-background-color: #ffffff; 277 | $header-bar-height: 100px; 278 | $main-color: #5AAAFA; 279 | $menu-color: #5AAAFA; 280 | $header-label-font-size: 1.618em; 281 | background-color: $root-background-color; 282 | padding: 60px; 283 | 284 | .v-nativebutton{ 285 | background: none; 286 | border: none; 287 | 288 | &:hover{ 289 | cursor: pointer; 290 | } 291 | } 292 | 293 | .header-label{ 294 | font-size: $header-label-font-size; 295 | width: 100%; 296 | margin-bottom: 20px; 297 | color: #000000; 298 | border-bottom: 3px solid #D0C7C7; 299 | } 300 | 301 | .header-label-small{ 302 | width: 100%; 303 | color: $main-color; 304 | text-transform: uppercase; 305 | border-bottom: 2px solid #D0C7C7; 306 | } 307 | 308 | .billing-formlayout { 309 | 310 | background: #f6f3f3; 311 | border: solid 1px #ffffff; 312 | margin: 0 30px 0 0px; 313 | float: left; 314 | padding: 20px; 315 | width: 100%; 316 | max-width: 722px; 317 | 318 | .form-textfield{ 319 | background: none; 320 | border-bottom: 2px solid #D0C7C7; 321 | } 322 | 323 | .email-field{ 324 | min-width: 250px; 325 | } 326 | } 327 | 328 | .order-summary-layout{ 329 | background: #8CD211; 330 | border: #ffffff; 331 | float: right; 332 | padding: 20px; 333 | 334 | .header-label-small { 335 | color: #ffffff; 336 | border-bottom-color: #C8F08F; 337 | } 338 | 339 | .v-label{ 340 | color: #ffffff; 341 | } 342 | 343 | .cancel-order-button{ 344 | background: none; 345 | border: none; 346 | position: relative; 347 | margin-left: 15px; 348 | margin-top: 10px; 349 | padding: 0; 350 | float: right; 351 | 352 | .v-icon{ 353 | font-size: 25px; 354 | width: 25px; 355 | height: 25px; 356 | line-height: 25px; 357 | color: #4B8400; 358 | } 359 | } 360 | 361 | .order-sum{ 362 | position: absolute; 363 | left: 170px; 364 | text-align: right; 365 | width: 150px; 366 | } 367 | 368 | .total-sum{ 369 | border-top: solid 2px #C8F08F; 370 | color: #C8F08F !important; 371 | font-size: 2em; 372 | &:first-letter { 373 | font-weight: 400; 374 | } 375 | } 376 | } 377 | 378 | &[width-range~="321px-768px"]{ 379 | padding: 10px; 380 | 381 | .billing-formlayout{ 382 | margin: 15px 0 0 0; 383 | width: 100% !important; 384 | } 385 | 386 | .order-summary-layout{ 387 | margin: 15px 0 0 0; 388 | } 389 | } 390 | 391 | &[width-range~="769px-1426px"]{ 392 | .billing-formlayout{ 393 | margin-bottom: 30px; 394 | } 395 | 396 | .order-summary-layout{ 397 | float: left; 398 | } 399 | } 400 | } 401 | 402 | .form-template-vaadin[width-range~="321px-768px"], 403 | .form-template-vaadin[width-range~="769px-1426px"]{ 404 | visibility: visible; 405 | } 406 | 407 | -------------------------------------------------------------------------------- /betternavi/src/main/webapp/VAADIN/themes/mytheme/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaadin/designer-tutorials/5a810e6e5c3cb78f4396405c909491dcd8d84533/betternavi/src/main/webapp/VAADIN/themes/mytheme/favicon.ico -------------------------------------------------------------------------------- /betternavi/src/main/webapp/VAADIN/themes/mytheme/mytheme.scss: -------------------------------------------------------------------------------- 1 | // Global variable overrides. Must be declared before importing Valo. 2 | 3 | // Defines the plaintext font size, weight and family. Font size affects general component sizing. 4 | //$v-font-size: 16px; 5 | //$v-font-weight: 300; 6 | //$v-font-family: "Open Sans", sans-serif; 7 | 8 | // Defines the border used by all components. 9 | //$v-border: 1px solid (v-shade 0.7); 10 | //$v-border-radius: 4px; 11 | 12 | // Affects the color of some component elements, e.g Button, Panel title, etc 13 | //$v-background-color: hsl(210, 0%, 98%); 14 | // Affects the color of content areas, e.g Panel and Window content, TextField input etc 15 | //$v-app-background-color: $v-background-color; 16 | 17 | // Affects the visual appearance of all components 18 | //$v-gradient: v-linear 8%; 19 | //$v-bevel-depth: 30%; 20 | //$v-shadow-opacity: 5%; 21 | 22 | // Defines colors for indicating status (focus, success, failure) 23 | //$v-focus-color: valo-focus-color(); // Calculates a suitable color automatically 24 | //$v-friendly-color: #2c9720; 25 | //$v-error-indicator-color: #ed473b; 26 | 27 | // For more information, see: https://vaadin.com/book/-/page/themes.valo.html 28 | // Example variants can be copy/pasted from https://vaadin.com/wiki/-/wiki/Main/Valo+Examples 29 | 30 | @import "../valo/valo.scss"; 31 | 32 | @mixin mytheme { 33 | @include valo; 34 | 35 | } 36 | -------------------------------------------------------------------------------- /betternavi/src/main/webapp/VAADIN/themes/mytheme/styles.scss: -------------------------------------------------------------------------------- 1 | @import "designs.scss"; 2 | @import "mytheme.scss"; 3 | @import "addons.scss"; 4 | 5 | // This file prefixes all rules with the theme name to avoid causing conflicts with other themes. 6 | // The actual styles should be defined in mytheme.scss 7 | 8 | .mytheme { 9 | @include addons; 10 | @include mytheme; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/README.adoc: -------------------------------------------------------------------------------- 1 | `This tutorial is written using Java 8, Vaadin 7.7.3 and Designer 1.2` 2 | 3 | = Connecting your designs to data 4 | 5 | In the following tutorial I’ll show you how you can connect your Vaadin Designer based views to a real database backend 6 | with only a few steps. The sample code in this tutorial is based on a previous link:https://github.com/vaadin/designer-tutorials/tree/master/emailclient-tutorial[one] where I demonstrated building a design 7 | of an email client. Now we’ll add fetching message entities from a real database and writing some modifications 8 | back to the database. The data access is done through a stateless EJB accessing a JPA repository. 9 | The repository is implemented using Apache link:https://deltaspike.apache.org/documentation/[DeltaSpike]. 10 | 11 | image::https://raw.githubusercontent.com/vaadin/designer-tutorials/develop/emailclient-tutorial-data/tutorial-images/email-client-with-data.png[Screenshot] 12 | 13 | 14 | I assume you have installed link:https://vaadin.com/designer[Vaadin Designer] and you are using Eclipse. In this tutorial I used 15 | 16 | - Java 8 and Java EE 7 Web Specification APIs 17 | - Eclipse Neon 18 | - Vaadin 7.7.3 19 | - Designer 1.2.0 20 | - Java EE 7 container e.g. Wildfly 9. 21 | 22 | == For the impatient one 23 | If you just want to see the end result and the completed code and don’t feel like doing it yourself, you can get the end result from link:https://github.com/vaadin/designer-tutorials/tree/master/emailclient-tutorial-data[here]. However, I would recommend going through all the steps yourself. 24 | 25 | `git clone --depth 1 \https://github.com/vaadin/designer-tutorials.git` 26 | 27 | == Quick start 28 | The key point in this tutorial is to show you how to connect your designs to data, and as I want to keep this tutorial as short as possible, I’ve implemented the data part and the UI designs for you. Just fork or clone link:https://github.com/vaadin/designer-tutorials/tree/emailclient-tutorial-data-start/emailclient-tutorial-data[this] repository and you are almost good to go. 29 | 30 | `git clone --depth 1 --no-single-branch \https://github.com/vaadin/designer-tutorials.git --branch emailclient-tutorial-data-start` 31 | 32 | What you need, in addition to the code, is: *Eclipse (Luna or newer)*, *Vaadin Designer*, and *Java EE 7* compatible container (e.g. Wildfly 9). The project is a Maven project and has been created using `vaadin-archetype-application`. The project pom has all the necessary dependencies like `deltaspike-data-module-api`, `javaee-web-api`, etc. The project also uses a Vaadin CDI add-on to allow using our UI components as CDI managed beans and to easily inject the data source. 33 | 34 | Import the project into Eclipse using `File > Import... > Existing Maven Projects`. Select the emailclient-tutorial-data directory as the root directory of your project. 35 | 36 | If you get stuck with the tutorial or you have some other questions, you can post them in this forum thread https://vaadin.com/forum#!/thread/11628010. 37 | 38 | == The backend 39 | *The backend is already done in the project, so you don’t have to do the following steps. This is here just for your information.* 40 | 41 | A simple and safe way to do the data access is through a stateless EJB facade accessing repositories. With the stateless bean you get the thread-safety and instance pooling by the container. To the Facade you can inject your repository. Using an EJB means that the transaction boundary should be in the EJB level and not in the JPA level. For that reason you need to put `apache-deltaspike.properties` file in `src/main/resources/META-INF` and define the transcation strategy to be container managed JTA transactions. 42 | 43 | `globalAlternatives.org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy=org.apache.deltaspike.jpa.impl.transaction.ContainerManagedTransactionStrategy` 44 | 45 | Another necessary step is to expose the EntityManager to the DeltaSpike Data module. This is done via CDI producer. 46 | 47 | [source, java] 48 | ---- 49 | public class CdiConfig { 50 | 51 | @Produces 52 | @Dependent 53 | @PersistenceContext(unitName = "tutorialdb") 54 | public EntityManager entityManager; 55 | } 56 | ---- 57 | 58 | === Entity 59 | In this simple example you only need a single JPA entity, which represents the listed message. An AbstractEntity here is a base class containing version and id fields. 60 | 61 | [source, java] 62 | ---- 63 | @Entity 64 | public class Message extends AbstractEntity { 65 | 66 | private boolean read; 67 | private boolean trashed; 68 | private String sender; 69 | @Enumerated(EnumType.STRING) 70 | private Flag flag; 71 | 72 | public enum Flag { 73 | FLAG_STAR 74 | } 75 | 76 | @Temporal(TemporalType.TIMESTAMP) 77 | private Date sent; 78 | private String subject; 79 | 80 | @Lob 81 | private String body; 82 | 83 | // … 84 | // getters and setters skipped for brevity 85 | } 86 | ---- 87 | 88 | === Repository 89 | With DeltaSpike, defining a repository is very simple. In this sample I just extended EntityRepository and added the needed methods. The EntityRepository has already the basic CRUD methods, and I only needed to add my custom methods there. The methods use DeltaSpike’s automatically generated query implementations by naming conventions. 90 | 91 | [source, java] 92 | ---- 93 | @Repository 94 | public interface MessageRepository extends EntityRepository { 95 | QueryResult findByRead(boolean read); 96 | 97 | QueryResult findByFlagIsNotNullAndRead(boolean read); 98 | 99 | List findByFlagIsNotNullAndTrashed(boolean trashed); 100 | } 101 | ---- 102 | 103 | === Facade 104 | A simple stateless EJB facade accessing repositories. Inject your repository to the facade. 105 | 106 | [source, java] 107 | ---- 108 | @Stateless 109 | public class MessageFacade { 110 | 111 | @Inject 112 | private MessageRepository repository; 113 | 114 | // … 115 | // business logic and data operations go here 116 | } 117 | ---- 118 | 119 | == UI views and navigation 120 | The starting point project already contains a bunch of UI logic and a couple of Vaadin Designer design files e.g. the folder navigation works both by clicking from the UI and navigating using a URL. There is also a logic to updating the unread messages count in the menu item badges on the left side. This implementation is out of scope of the tutorial and we can focus on the list of messages in the FolderView, but I still want to describe a bit what is happening in the UI. 121 | 122 | MyUI is annotated with `@CDIUI` coming from Vaadin CDI. It sets up a Navigator and uses CDIViewProvider with navigator. CDViewProvider understands `@CDIView` annotated views. MyUI also defines a ServletContextListener to initialize test data. 123 | 124 | MainLayout is extending MainLayoutDesign which is the content of our UI, having a menu on the left side and a toolbar on the top. The lower right area is the view content area for Navigator. MainLayout has a bunch of boiler-plate code to manage the button selected style, click events, formatting Valo themed menu items etc. You should take a look at it just maybe out of curiosity, but it’s not necessary for this tutorial. 125 | 126 | FolderView is simply extending VerticalLayout and implements com.vaadin.navigator.View. It is annotated with `@CDIView` and uses view parameters to communicate which folder is the currently selected one and based on that parameter we can fetch the appropriate messages from the backend and display them. For each of the folders, we are using the same view class just because the content of the views is the same apart from the dynamic list of messages. 127 | 128 | MessageModifiedEvent is a CDI event we use later on in the tutorial. 129 | 130 | It’s worth mentioning that the application uses a custom theme. There’s not much style definitions in the `mytheme.scss`, but some sizing, alignment, colors, and such. The style names needed for this tutorial are available in link:https://github.com/vaadin/designer-tutorials/blob/master/emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/themes/mytheme/MyTheme.java[`MyTheme.java`]. 131 | 132 | MessageDesign is the still a bit static message UI component you should use in message listing. 133 | 134 | == Let’s get coding! 135 | Let’s add some functionality to this currently a somewhat dumb application. When the user selects a message folder, the list of messages should be shown. Also, when the user clicks a message that is marked as unread it should be marked as read. The message should display the unread status by showing a colored indicator. 136 | 137 | === Show list of messages 138 | Message facade has methods to provide list messages when a folder is selected. You should fetch the list of messages in FolderView#enter() and then replace the static content of MessageDesign with real data and finally populate the FolderView UI with the fetched messages. 139 | 140 | - Start by extending MessageDesign and name it MessageComponent. 141 | - Add a constructor to create it based on Message entity 142 | - Set the values of appropriate UI components from message properties 143 | 144 | [source, java] 145 | ---- 146 | public class MessageComponent extends MessageDesign { 147 | public MessageComponent(Message message) { 148 | senderLabel.setValue(message.getSender()); 149 | messageLabel.setCaption(message.getSubject()); 150 | messageLabel.setValue(message.getBody()); 151 | } 152 | } 153 | ---- 154 | 155 | - In FolderView there is a method named refreshFolders, which is called in FolderView#enter. Fetch messages from MessageFacade and populate the FolderView VerticalLayout. 156 | 157 | [source, java] 158 | ---- 159 | @Override 160 | public void enter(ViewChangeEvent event) { 161 | String folder = event.getParameters(); 162 | refreshFolder(folder); 163 | } 164 | 165 | private void refreshFolder(String folder) { 166 | removeAllComponents(); 167 | messageFacade.getFolderMessages(folder).stream() 168 | .map(MessageComponent::new).forEach(this::addComponent); 169 | } 170 | ---- 171 | 172 | Ok, so now the message listing is working, but the message unread indicator is not colored for the unread messages 173 | and all the messages have the same indicator icon. Let’s fix that. 174 | 175 | - Flagged messages get a star indicator and unread messages get a circle indicator. 176 | - Indicators of unread messages get a color. 177 | - Read non-flagged messages don’t have an indicator at all. 178 | 179 | [source, java] 180 | ---- 181 | public void setIndicator(boolean read, Flag flag) { 182 | MyTheme.MESSAGE_STYLES.forEach(indicatorButton::removeStyleName); 183 | indicatorButton.setIcon(null); 184 | if (flag == Flag.FLAG_STAR) { 185 | indicatorButton.setIcon(FontAwesome.STAR); 186 | if (!read) { 187 | indicatorButton.addStyleName(MyTheme.INDICATOR_STAR_RED); 188 | } 189 | } else if (!read) { 190 | indicatorButton.setIcon(FontAwesome.CIRCLE); 191 | indicatorButton.addStyleName(MyTheme.INDICATOR_CIRCLE); 192 | } 193 | } 194 | ---- 195 | 196 | - Call setIndicator in MessageComponent constructor + 197 | `setIndicator(message.isRead(), message.getFlag())`; 198 | 199 | === Marking messages as read 200 | .Let’s add a support for marking messages as read. This requires you to: 201 | - Handle mouse click events in the MessageComponent 202 | - Propagate the click event from the message to the FolderView. 203 | - In the FolderView set the message as read and save the modifications to the database through MessageFacade. 204 | - After the modification transaction is complete, propagate the change to the menu component to refresh 205 | the folder badges (now the custom CDI event MessageModifiedEvent comes into play). 206 | 207 | .Let’s go through this step-by-step: 208 | - To handle a click event in MessageComponent you can use LayoutClickListener. 209 | - From there the click event can be propagated in many ways, but I like Java 8 so let’s 210 | define a functional interface MessageClickListener. 211 | 212 | [source, java] 213 | ---- 214 | @FunctionalInterface 215 | interface MessageClickListener { 216 | public void messageClick(MessageComponent source, Message message); 217 | } 218 | ---- 219 | 220 | Add MessageClickListener parameter to the constructor and call the listener in LayoutClickListener. 221 | 222 | [source, java] 223 | ---- 224 | public MessageComponent(Message message, 225 | MessageClickListener clickListener) { 226 | // … 227 | addLayoutClickListener( 228 | event -> clickListener.messageClick(this, message)); 229 | } 230 | ---- 231 | 232 | - Fix the FolderView message population to include this new MessageClickListener. So instead of 233 | `MessageComponent::new` call `this::createFromEntity`. 234 | 235 | [source, java] 236 | ---- 237 | private void refreshFolder(String folder) { 238 | removeAllComponents(); 239 | messageFacade.getFolderMessages(folder).stream() 240 | .map(this::createFromEntity).forEach(this::addComponent); 241 | } 242 | 243 | private MessageComponent createFromEntity(Message entity) { 244 | MessageComponent msg = new MessageComponent(entity, 245 | this::onMessageClicked); 246 | return msg; 247 | } 248 | 249 | private void onMessageClicked(MessageComponent source, Message message) { 250 | } 251 | ---- 252 | 253 | .Now the FolderView consumes the click event and you can modify the message. 254 | - Set the message as read and save it through MessageFacade. 255 | - Update the message indicator 256 | 257 | [source, java] 258 | ---- 259 | private void onMessageClicked(MessageComponent source, Message message) { 260 | if (!message.isRead()) { 261 | message.setRead(true); 262 | messageFacade.save(message); 263 | source.setIndicator(true, message.getFlag()); 264 | } 265 | } 266 | ---- 267 | 268 | As an added bonus the message folder badge on the left side menu should update right away so fire a CDI event called 269 | MessageModifiedEvent. MainLayout is already observing that message and waiting eagerly for some updates. 270 | To achieve this I just added @Observes annotated event listener to the MainLayout class. 271 | The event handler then calls MessageFacade and asks for a message count for each of the folders and 272 | maps the results to the menu buttons. 273 | Check it out from link:https://github.com/vaadin/designer-tutorials/blob/master/emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/MainLayout.java[MainLayout.java] if you are interested. 274 | 275 | The event is already injected into FolderView so just call: + 276 | `messageSelectEvent.fire(new MessageModifiedEvent(message));` 277 | 278 | == What next? 279 | If you got this far and everything is working just the way you wanted, great job! We used DeltaSpike repositories 280 | and Java EE container features here, but these same principles can be applied to Spring Data, plain JPA 281 | or basically to any data source. 282 | 283 | I need to mention one important thing: If you were to use this same approach in any larger data set, 284 | you would have to implement data paging. Here we loaded all items to a layout, but you can imagine what 285 | happens to the server’s memory usage and the browser’s capability to display the items if the data set gets large. 286 | With DeltaSpike paging can be implemented easily using `QueryResult`. After your data source implements paging, 287 | you only need to add UI controls for getting the next/previous page of data. 288 | 289 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.vaadin.example 6 | emailclient-tutorial-data 7 | war 8 | 1.0-SNAPSHOT 9 | emailclient-tutorial-data 10 | 11 | 12 | 3 13 | 14 | 15 | 16 | 7.7.3 17 | ${vaadin.version} 18 | 9.2.3.v20140905 19 | 1.8 20 | 1.8 21 | UTF-8 22 | 1.5.1 23 | 24 | local 25 | 26 | 27 | 28 | 29 | vaadin-addons 30 | https://maven.vaadin.com/vaadin-addons 31 | 32 | 33 | 34 | 35 | 36 | 37 | com.vaadin 38 | vaadin-bom 39 | ${vaadin.version} 40 | pom 41 | import 42 | 43 | 44 | 45 | 46 | 47 | 48 | javax.servlet 49 | javax.servlet-api 50 | 3.0.1 51 | provided 52 | 53 | 54 | javax 55 | javaee-web-api 56 | 7.0 57 | provided 58 | 59 | 60 | org.apache.deltaspike.modules 61 | deltaspike-data-module-api 62 | ${deltaspike.version} 63 | compile 64 | 65 | 66 | org.apache.deltaspike.modules 67 | deltaspike-data-module-impl 68 | ${deltaspike.version} 69 | runtime 70 | 71 | 72 | com.vaadin 73 | vaadin-server 74 | 75 | 76 | com.vaadin 77 | vaadin-push 78 | 79 | 80 | com.vaadin 81 | vaadin-client-compiled 82 | 83 | 84 | com.vaadin 85 | vaadin-themes 86 | 87 | 88 | com.vaadin 89 | vaadin-cdi 90 | 1.0.3 91 | 92 | 93 | 94 | 95 | 96 | 97 | org.apache.maven.plugins 98 | maven-compiler-plugin 99 | 3.0 100 | 101 | ${project.encoding} 102 | ${project.source.version} 103 | ${project.target.version} 104 | 105 | 106 | 107 | org.apache.maven.plugins 108 | maven-resources-plugin 109 | 2.6 110 | 111 | ${project.encoding} 112 | 113 | 114 | 115 | org.apache.maven.plugins 116 | maven-war-plugin 117 | 2.3 118 | 119 | false 120 | 121 | WEB-INF/classes/VAADIN/gwt-unitCache/**, 122 | WEB-INF/classes/VAADIN/widgetsets/WEB-INF/** 123 | 124 | 125 | 126 | com.vaadin 127 | vaadin-maven-plugin 128 | ${vaadin.plugin.version} 129 | 130 | -Xmx512M -Xss1024k 131 | ${basedir}/target/classes/VAADIN/widgetsets 132 | false 133 | false 134 | 135 | true 136 | 137 | 138 | 139 | 140 | update-theme 141 | update-widgetset 142 | compile 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | org.apache.maven.plugins 151 | maven-source-plugin 152 | 2.4 153 | 154 | 155 | org.apache.maven.plugins 156 | maven-clean-plugin 157 | 2.6.1 158 | 159 | 160 | 161 | 162 | src/main/webapp/VAADIN/themes 163 | 164 | **/styles.css 165 | **/styles.scss.cache 166 | 167 | 168 | 169 | 170 | 171 | 172 | 174 | 175 | org.eclipse.jetty 176 | jetty-maven-plugin 177 | ${jetty.plugin.version} 178 | 179 | 2 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | vaadin-prerelease 189 | 190 | false 191 | 192 | 193 | 194 | 195 | vaadin-prereleases 196 | https://maven.vaadin.com/vaadin-prereleases 197 | 198 | 199 | vaadin-snapshots 200 | https://oss.sonatype.org/content/repositories/vaadin-snapshots/ 201 | 202 | false 203 | 204 | 205 | true 206 | 207 | 208 | 209 | 210 | 211 | vaadin-prereleases 212 | https://maven.vaadin.com/vaadin-prereleases 213 | 214 | 215 | vaadin-snapshots 216 | https://oss.sonatype.org/content/repositories/vaadin-snapshots/ 217 | 218 | false 219 | 220 | 221 | true 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/backend/AbstractEntity.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.backend; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.GenerationType; 7 | import javax.persistence.Id; 8 | import javax.persistence.MappedSuperclass; 9 | import javax.persistence.Version; 10 | 11 | @MappedSuperclass 12 | public abstract class AbstractEntity implements Serializable { 13 | 14 | @Id 15 | @GeneratedValue(strategy = GenerationType.AUTO) 16 | private Long id; 17 | 18 | @Version 19 | private int version; 20 | 21 | public Long getId() { 22 | return id; 23 | } 24 | 25 | protected void setId(Long id) { 26 | this.id = id; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/backend/CdiConfig.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.backend; 2 | 3 | import javax.enterprise.context.Dependent; 4 | import javax.enterprise.inject.Produces; 5 | import javax.persistence.EntityManager; 6 | import javax.persistence.PersistenceContext; 7 | 8 | public class CdiConfig { 9 | 10 | @Produces 11 | @Dependent 12 | @PersistenceContext(unitName = "tutorialdb") 13 | public EntityManager entityManager; 14 | } 15 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/backend/DatabaseInitialization.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.backend; 2 | 3 | import java.time.LocalDateTime; 4 | import java.time.ZoneOffset; 5 | import java.util.Date; 6 | 7 | import javax.ejb.Stateless; 8 | import javax.inject.Inject; 9 | 10 | import org.vaadin.example.backend.Message.Flag; 11 | 12 | @Stateless 13 | public class DatabaseInitialization { 14 | 15 | @Inject 16 | private MessageRepository msgRepo; 17 | 18 | public void initDatabaseIfEmpty() { 19 | 20 | if (!msgRepo.findAll().isEmpty()) { 21 | return; 22 | } 23 | 24 | createMessage("Marc Englund", "Vaadin Designer 1.0 has arrived", 25 | LocalDateTime.of(2015, 10, 24, 21, 0), 26 | "We are thrilled to announce the release of Vaadin Designer 1.0 after 6 months of intensive beta testing. " 27 | + "Vaadin Designer is available for all developers, to be installed from Eclipse Marketplace today.", 28 | false, null); 29 | createMessage("Jurka Rahikkala", 30 | "10+1 things to know about Vaadin for job seekers", 31 | LocalDateTime.of(2015, 10, 22, 12, 34), 32 | "We are constantly seeking highly skilled software experts to join the team. The Vaadin team is constantly working on several projects, " 33 | + "ranging from our own products (such as Vaadin Framework, Designer and Elements) to several customer projects around the world " 34 | + "(examples at https://vaadin.com/success-stories). Needless to say, these projects do not get done without the right people.", 35 | true, null); 36 | createMessage("Teemu Pöntelin", 37 | "Building a mobile-first app with Polymer and Vaadin Elements", 38 | LocalDateTime.of(2015, 10, 19, 18, 20), 39 | "As you might have noticed, we at Vaadin have been experimenting with bringing our Grid and Charts components to a new audience by wrapping " 40 | + "them into Polymer elements. Polymer is Google’s project to bring Web Components into developers’ hands and into production.", 41 | true, Flag.FLAG_STAR); 42 | createMessage("Tanja Repo", "Come and meet us at JavaOne 2015", 43 | LocalDateTime.of(2015, 10, 13, 17, 50), 44 | "Once again Vaadin packs up for the upcoming JavaOne 2015 and heads to San Francisco, US. JavaOne is ‘the event’ for Java enthusiasts, " 45 | + "where one can hear the best speakers, get insights into the future of Java, and connect with other members of the Java community.", 46 | false, Flag.FLAG_STAR); 47 | } 48 | 49 | private Message createMessage(String sender, String subject, 50 | LocalDateTime dateTime, String body, boolean isRead, Flag flag) { 51 | Message msg = new Message(); 52 | msg.setSender(sender); 53 | msg.setSubject(subject); 54 | msg.setSent(Date.from(dateTime.toInstant(ZoneOffset.UTC))); 55 | msg.setBody(body); 56 | msg.setRead(isRead); 57 | msg.setFlag(flag); 58 | msg.setTrashed(false); 59 | msgRepo.saveAndFlush(msg); 60 | return msg; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/backend/Message.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.backend; 2 | 3 | import java.util.Date; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.EnumType; 7 | import javax.persistence.Enumerated; 8 | import javax.persistence.Lob; 9 | import javax.persistence.Temporal; 10 | import javax.persistence.TemporalType; 11 | 12 | @Entity 13 | public class Message extends AbstractEntity { 14 | 15 | private boolean read; 16 | private boolean trashed; 17 | private String sender; 18 | @Enumerated(EnumType.STRING) 19 | private Flag flag; 20 | 21 | public enum Flag { 22 | FLAG_STAR 23 | } 24 | 25 | @Temporal(TemporalType.TIMESTAMP) 26 | private Date sent; 27 | private String subject; 28 | 29 | @Lob 30 | private String body; 31 | 32 | public boolean isRead() { 33 | return read; 34 | } 35 | 36 | public void setRead(boolean read) { 37 | this.read = read; 38 | } 39 | 40 | public boolean isTrashed() { 41 | return trashed; 42 | } 43 | 44 | public void setTrashed(boolean trashed) { 45 | this.trashed = trashed; 46 | } 47 | 48 | public Flag getFlag() { 49 | return flag; 50 | } 51 | 52 | public void setFlag(Flag flag) { 53 | this.flag = flag; 54 | } 55 | 56 | public String getSender() { 57 | return sender; 58 | } 59 | 60 | public void setSender(String sender) { 61 | this.sender = sender; 62 | } 63 | 64 | public Date getSent() { 65 | return sent; 66 | } 67 | 68 | public void setSent(Date sent) { 69 | this.sent = sent; 70 | } 71 | 72 | public String getSubject() { 73 | return subject; 74 | } 75 | 76 | public void setSubject(String subject) { 77 | this.subject = subject; 78 | } 79 | 80 | public String getBody() { 81 | return body; 82 | } 83 | 84 | public void setBody(String body) { 85 | this.body = body; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/backend/MessageFacade.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.backend; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import javax.ejb.Stateless; 8 | import javax.inject.Inject; 9 | 10 | @Stateless 11 | public class MessageFacade { 12 | 13 | public static final String FOLDER_INBOX = "inbox"; 14 | public static final String FOLDER_DRAFTS = "drafts"; 15 | public static final String FOLDER_SENT = "sent"; 16 | public static final String FOLDER_JUNK = "junk"; 17 | public static final String FOLDER_TRASH = "trash"; 18 | public static final String FOLDER_FLAGGED = "flagged"; 19 | public static final List FOLDERS = Arrays.asList(FOLDER_INBOX, 20 | FOLDER_DRAFTS, FOLDER_SENT, FOLDER_JUNK, FOLDER_TRASH, 21 | FOLDER_FLAGGED); 22 | 23 | @Inject 24 | private MessageRepository repository; 25 | 26 | public List getFolderMessages(String folder) { 27 | if (FOLDERS.contains(folder)) { 28 | if (folder.equals(FOLDER_INBOX)) { 29 | return repository.findAll(); 30 | } else if (folder.equals(FOLDER_FLAGGED)) { 31 | return repository.findByFlagIsNotNullAndTrashed(false); 32 | } 33 | } 34 | return new ArrayList<>(); 35 | } 36 | 37 | public long countAllUnread() { 38 | return repository.findByRead(false).count(); 39 | 40 | } 41 | 42 | public long countFlaggedUnread() { 43 | return repository.findByFlagIsNotNullAndRead(false).count(); 44 | } 45 | 46 | public void save(Message message) { 47 | repository.saveAndFlush(message); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/backend/MessageRepository.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.backend; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.deltaspike.data.api.EntityRepository; 6 | import org.apache.deltaspike.data.api.QueryResult; 7 | import org.apache.deltaspike.data.api.Repository; 8 | 9 | @Repository 10 | public interface MessageRepository extends EntityRepository { 11 | QueryResult findByRead(boolean read); 12 | 13 | QueryResult findByFlagIsNotNullAndRead(boolean read); 14 | 15 | List findByFlagIsNotNullAndTrashed(boolean trashed); 16 | } 17 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/FolderView.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.ui; 2 | 3 | import javax.inject.Inject; 4 | 5 | import org.vaadin.example.backend.Message; 6 | import org.vaadin.example.backend.MessageFacade; 7 | 8 | import com.vaadin.cdi.CDIView; 9 | import com.vaadin.navigator.View; 10 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; 11 | import com.vaadin.ui.VerticalLayout; 12 | 13 | /** 14 | * View listing messages fetched through MessageFacade. Also handles message 15 | * clicks to mark them as read. 16 | * 17 | */ 18 | @CDIView(supportsParameters = true, value = FolderView.VIEW_NAME) 19 | public class FolderView extends VerticalLayout implements View { 20 | 21 | public static final String VIEW_NAME = "folder"; 22 | 23 | @Inject 24 | private MessageFacade messageFacade; 25 | 26 | @Inject 27 | javax.enterprise.event.Event messageSelectEvent; 28 | 29 | @Override 30 | public void enter(ViewChangeEvent event) { 31 | String folder = event.getParameters(); 32 | refreshFolder(folder); 33 | } 34 | 35 | private void refreshFolder(String folder) { 36 | removeAllComponents(); 37 | messageFacade.getFolderMessages(folder).stream() 38 | .map(this::createFromEntity).forEach(this::addComponent); 39 | } 40 | 41 | private MessageComponent createFromEntity(Message entity) { 42 | MessageComponent msg = new MessageComponent(entity, 43 | this::onMessageClicked); 44 | return msg; 45 | } 46 | 47 | private void onMessageClicked(MessageComponent source, Message message) { 48 | if (!message.isRead()) { 49 | message.setRead(true); 50 | messageFacade.save(message); 51 | source.setIndicator(true, message.getFlag()); 52 | } 53 | messageSelectEvent.fire(new MessageModifiedEvent(message)); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/MainLayout.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.ui; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Optional; 6 | import java.util.function.Supplier; 7 | 8 | import javax.annotation.PostConstruct; 9 | import javax.enterprise.event.Observes; 10 | import javax.inject.Inject; 11 | 12 | import org.vaadin.example.backend.MessageFacade; 13 | import org.vaadin.example.ui.themes.mytheme.MyTheme; 14 | 15 | import com.vaadin.cdi.UIScoped; 16 | import com.vaadin.ui.Button; 17 | import com.vaadin.ui.Component; 18 | import com.vaadin.ui.UI; 19 | 20 | /** 21 | * 22 | * Handles the left-side menu and the top toolbar 23 | */ 24 | @UIScoped 25 | public class MainLayout extends MainLayoutDesign { 26 | 27 | @Inject 28 | private MessageFacade messageFacade; 29 | 30 | private Map> badgeSuppliers = new HashMap<>(); 31 | 32 | @PostConstruct 33 | protected void init() { 34 | setupMenuButtons(); 35 | } 36 | 37 | public void setSelectedFolder(String folder) { 38 | menuItems.forEach(component -> adjustStyleByData(component, folder)); 39 | } 40 | 41 | // Adjust all menu badges when a message is modified (marked as read) 42 | public void messageModified(@Observes MessageModifiedEvent event) { 43 | menuItems.forEach(this::setMenuBadge); 44 | } 45 | 46 | void navigateToFolder(String folder) { 47 | UI.getCurrent().getNavigator() 48 | .navigateTo(FolderView.VIEW_NAME + "/" + folder); 49 | } 50 | 51 | private void setupMenuButtons() { 52 | mapButton(inboxButton, MessageFacade.FOLDER_INBOX, 53 | Optional.of(() -> messageFacade.countAllUnread())); 54 | mapButton(draftsButton, MessageFacade.FOLDER_DRAFTS); 55 | mapButton(sentButton, MessageFacade.FOLDER_SENT); 56 | mapButton(junkButton, MessageFacade.FOLDER_JUNK); 57 | mapButton(trashButton, MessageFacade.FOLDER_TRASH); 58 | mapButton(flaggedButton, MessageFacade.FOLDER_FLAGGED, 59 | Optional.of(() -> messageFacade.countFlaggedUnread())); 60 | 61 | menuItems.forEach(this::setMenuBadge); 62 | } 63 | 64 | // Formats a given Button component's caption to contain HTML in a 65 | // particular format required by Valo themed menu item component 66 | private void setMenuBadge(Component component) { 67 | if (component instanceof Button) { 68 | Button button = (Button) component; 69 | if (button.getData() != null 70 | && button.getData() instanceof String) { 71 | String folder = (String) button.getData(); 72 | Long count = badgeSuppliers.containsKey(folder) 73 | ? badgeSuppliers.get(folder).get() : 0L; 74 | String badgeText = (count != null && count > 0) 75 | ? (count > 99) ? "99+" : count.toString() : ""; 76 | String captionFormat = badgeText.isEmpty() ? "" 77 | : "%s %s"; 78 | if (captionFormat.isEmpty()) { 79 | component.setCaption(folder); 80 | } else { 81 | component.setCaption( 82 | String.format(captionFormat, folder, badgeText)); 83 | } 84 | } 85 | } 86 | } 87 | 88 | // Map button click to a navigation method. 89 | // Map button to a folder name to allow setting selected style when folder 90 | // is navigated without clicking the button. 91 | // Map button to a Supplier method, that provides count for unread items 92 | private void mapButton(Button button, String folderName, 93 | Optional> badgeSupplier) { 94 | button.addClickListener(event -> navigateToFolder(folderName)); 95 | button.setData(folderName); 96 | if (badgeSupplier.isPresent()) { 97 | badgeSuppliers.put(folderName, badgeSupplier.get()); 98 | } 99 | } 100 | 101 | private void mapButton(Button button, String folderName) { 102 | mapButton(button, folderName, Optional.empty()); 103 | } 104 | 105 | // Checks if a given Component has a given folder name as data, and adds or 106 | // removes selected style appropriately 107 | private void adjustStyleByData(Component component, Object data) { 108 | if (component instanceof Button) { 109 | if (data != null && data.equals(((Button) component).getData())) { 110 | component.addStyleName(MyTheme.SELECTED); 111 | } else { 112 | component.removeStyleName(MyTheme.SELECTED); 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/MainLayoutDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.ui; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.Button; 6 | import com.vaadin.ui.ComboBox; 7 | import com.vaadin.ui.CssLayout; 8 | import com.vaadin.ui.HorizontalLayout; 9 | import com.vaadin.ui.Panel; 10 | import com.vaadin.ui.VerticalLayout; 11 | import com.vaadin.ui.declarative.Design; 12 | 13 | /** 14 | * !! DO NOT EDIT THIS FILE !! 15 | * 16 | * This class is generated by Vaadin Designer and will be overwritten. 17 | * 18 | * Please make a subclass with logic and additional interfaces as needed, 19 | * e.g class LoginView extends LoginDesign implements View { … } 20 | */ 21 | @DesignRoot 22 | @AutoGenerated 23 | @SuppressWarnings("serial") 24 | public class MainLayoutDesign extends HorizontalLayout { 25 | protected Button menuToggle; 26 | protected CssLayout menuItems; 27 | protected Button composeButton; 28 | protected Button inboxButton; 29 | protected Button draftsButton; 30 | protected Button sentButton; 31 | protected Button junkButton; 32 | protected Button trashButton; 33 | protected Button flaggedButton; 34 | protected VerticalLayout content; 35 | protected ComboBox sortCombo; 36 | protected Button deleteButton; 37 | protected Button replyButton; 38 | protected Button replyAllButton; 39 | protected Button forwardButton; 40 | protected ComboBox flagCombo; 41 | protected Panel messagePanel; 42 | protected VerticalLayout messageList; 43 | 44 | public MainLayoutDesign() { 45 | Design.read(this); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/MessageComponent.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.ui; 2 | 3 | import org.vaadin.example.backend.Message; 4 | import org.vaadin.example.backend.Message.Flag; 5 | import org.vaadin.example.ui.themes.mytheme.MyTheme; 6 | 7 | import com.vaadin.server.FontAwesome; 8 | 9 | /** 10 | * This is the place to implement component logic for MessageDesign. The super 11 | * class should not be edited, because Vaadin Designer overwrites it. 12 | * 13 | */ 14 | public class MessageComponent extends MessageDesign { 15 | 16 | public MessageComponent(Message message, 17 | MessageClickListener clickListener) { 18 | senderLabel.setValue(message.getSender()); 19 | messageLabel.setCaption(message.getSubject()); 20 | messageLabel.setValue(message.getBody()); 21 | 22 | addLayoutClickListener( 23 | event -> clickListener.messageClick(this, message)); 24 | setIndicator(message.isRead(), message.getFlag()); 25 | } 26 | 27 | public void setIndicator(boolean read, Flag flag) { 28 | MyTheme.MESSAGE_STYLES.forEach(indicatorButton::removeStyleName); 29 | indicatorButton.setIcon(null); 30 | if (flag == Flag.FLAG_STAR) { 31 | indicatorButton.setIcon(FontAwesome.STAR); 32 | if (!read) { 33 | indicatorButton.addStyleName(MyTheme.INDICATOR_STAR_RED); 34 | } 35 | } else if (!read) { 36 | indicatorButton.setIcon(FontAwesome.CIRCLE); 37 | indicatorButton.addStyleName(MyTheme.INDICATOR_CIRCLE); 38 | } 39 | } 40 | 41 | @FunctionalInterface 42 | interface MessageClickListener { 43 | public void messageClick(MessageComponent source, Message message); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/MessageDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.ui; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.Button; 6 | import com.vaadin.ui.HorizontalLayout; 7 | import com.vaadin.ui.Label; 8 | import com.vaadin.ui.declarative.Design; 9 | 10 | /** 11 | * !! DO NOT EDIT THIS FILE !! 12 | * 13 | * This class is generated by Vaadin Designer and will be overwritten. 14 | * 15 | * Please make a subclass with logic and additional interfaces as needed, e.g 16 | * class LoginView extends LoginDesign implements View { … } 17 | */ 18 | @DesignRoot 19 | @AutoGenerated 20 | @SuppressWarnings("serial") 21 | public class MessageDesign extends HorizontalLayout { 22 | protected Button indicatorButton; 23 | protected Label senderLabel; 24 | protected Label messageLabel; 25 | 26 | public MessageDesign() { 27 | Design.read(this); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/MessageModifiedEvent.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.ui; 2 | 3 | import org.vaadin.example.backend.Message; 4 | 5 | /** 6 | * Event is fired by {@link FolderView} and observed by {@link MyUI}. 7 | * 8 | */ 9 | public class MessageModifiedEvent { 10 | private final Message message; 11 | 12 | public MessageModifiedEvent(Message message) { 13 | this.message = message; 14 | } 15 | 16 | public Message getMessage() { 17 | return message; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/MyUI.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.ui; 2 | 3 | import javax.inject.Inject; 4 | import javax.servlet.ServletContextEvent; 5 | import javax.servlet.ServletContextListener; 6 | import javax.servlet.annotation.WebListener; 7 | 8 | import org.vaadin.example.backend.DatabaseInitialization; 9 | import org.vaadin.example.backend.MessageFacade; 10 | 11 | import com.vaadin.annotations.Theme; 12 | import com.vaadin.cdi.CDIUI; 13 | import com.vaadin.cdi.CDIViewProvider; 14 | import com.vaadin.navigator.Navigator; 15 | import com.vaadin.navigator.ViewChangeListener; 16 | import com.vaadin.server.VaadinRequest; 17 | import com.vaadin.ui.UI; 18 | 19 | /** 20 | * UI class using Vaadin CDI addon annotation CDIUI, which makes it a managed 21 | * bean and allows to inject dependencies to it. 22 | */ 23 | @Theme("mytheme") 24 | @CDIUI("") 25 | public class MyUI extends UI { 26 | 27 | // CDIViewProvider implements com.vaadin.navigator.ViewProvider and 28 | // understands container managed views. 29 | @Inject 30 | private CDIViewProvider viewProvider; 31 | 32 | @Inject 33 | private MainLayout mainLayout; 34 | 35 | @Override 36 | protected void init(VaadinRequest vaadinRequest) { 37 | setContent(mainLayout); 38 | 39 | Navigator navigator = new Navigator(this, mainLayout.messagePanel); 40 | navigator.addProvider(viewProvider); 41 | setNavigator(navigator); 42 | 43 | navigator.addViewChangeListener(new ViewChangeListener() { 44 | 45 | @Override 46 | public boolean beforeViewChange(ViewChangeEvent event) { 47 | return true; 48 | } 49 | 50 | @Override 51 | public void afterViewChange(ViewChangeEvent event) { 52 | String folder = event.getParameters(); 53 | mainLayout.setSelectedFolder(folder); 54 | } 55 | }); 56 | 57 | if (navigator.getState().isEmpty()) { 58 | mainLayout.navigateToFolder(MessageFacade.FOLDER_INBOX); 59 | } 60 | 61 | } 62 | 63 | // Test data initialization is done in contextInitialized Servlet life-cycle 64 | // event 65 | @WebListener 66 | private static class MyUIServlectContextListener 67 | implements ServletContextListener { 68 | 69 | @Inject 70 | private DatabaseInitialization init; 71 | 72 | @Override 73 | public void contextDestroyed(ServletContextEvent arg0) { 74 | // do nothing 75 | } 76 | 77 | @Override 78 | public void contextInitialized(ServletContextEvent arg0) { 79 | init.initDatabaseIfEmpty(); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/java/org/vaadin/example/ui/themes/mytheme/MyTheme.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example.ui.themes.mytheme; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collections; 5 | import java.util.List; 6 | 7 | public class MyTheme { 8 | public static final String INDICATOR_STAR_RED = "indicator-star-red"; 9 | public static final String INDICATOR_CIRCLE = "indicator-circle"; 10 | public static final String SELECTED = "selected"; 11 | 12 | public static final List MESSAGE_STYLES = Collections 13 | .unmodifiableList(Arrays.asList(MyTheme.INDICATOR_CIRCLE, 14 | MyTheme.INDICATOR_STAR_RED)); 15 | } 16 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/resources/META-INF/apache-deltaspike.properties: -------------------------------------------------------------------------------- 1 | globalAlternatives.org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy=org.apache.deltaspike.jpa.impl.transaction.ContainerManagedTransactionStrategy 2 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/resources/META-INF/persistence.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/resources/org/vaadin/example/ui/MainLayoutDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Menu 12 | 13 | 14 | 15 | Compose 16 | 17 | 18 | Inbox 19 | 7 20 | 21 | 22 | Drafts 23 | 24 | 25 | Sent 26 | 27 | 28 | Junk 29 | 30 | 31 | Trash 32 | 99+ 33 | 34 | 35 | Flagged 36 | 2 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Sort by: 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/resources/org/vaadin/example/ui/MessageDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | This is the sender 12 | 13 | 14 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed posuere interdum sem. Quisque ligula eros ullamcorper quis, lacinia quis facilisis sed sapien. Mauris varius diam vitae arcu. Sed arcu lectus auctor vitae, consectetuer et venenatis eget velit. Sed augue orci, lacinia eu tincidunt et eleifend nec lacus. Donec ultricies nisl ut felis, suspendisse potenti. 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/webapp/VAADIN/themes/mytheme/addons.scss: -------------------------------------------------------------------------------- 1 | /* This file is automatically managed and will be overwritten from time to time. */ 2 | /* Do not manually edit this file. */ 3 | 4 | /* Import and include this mixin into your project theme to include the addon themes */ 5 | @mixin addons { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/webapp/VAADIN/themes/mytheme/designs.scss: -------------------------------------------------------------------------------- 1 | // Styles imported from ApplicationDesign.html 2 | // Workaround for a https://dev.vaadin.com/ticket/19170 to get hidden icons in some environments to show 3 | #responsive-application-template.valo-menu-responsive .valo-menu-part .valo-menu-item span.v-icon { 4 | opacity: 1.0; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/webapp/VAADIN/themes/mytheme/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaadin/designer-tutorials/5a810e6e5c3cb78f4396405c909491dcd8d84533/emailclient-tutorial-data/src/main/webapp/VAADIN/themes/mytheme/favicon.ico -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/webapp/VAADIN/themes/mytheme/mytheme.scss: -------------------------------------------------------------------------------- 1 | // Valo parameters to make the menu look as desired 2 | $valo-menu-background-color: #433; 3 | $v-focus-color: #433; 4 | $v-border-radius: 10px; 5 | 6 | @import "../valo/valo.scss"; 7 | 8 | @mixin mytheme { 9 | @include valo; 10 | 11 | // More spacing around the menu items (and re-align badge after that change) 12 | .valo-menu-item { 13 | line-height: 45px; 14 | .valo-menu-badge { 15 | top: 12px; 16 | } 17 | } 18 | 19 | // Only for the "desktop" (wide) version: make menu wider 20 | .valo-menu-responsive[width-range~="1101px-"] { 21 | .valo-menu-item-caption { 22 | min-width: 150px; 23 | } 24 | } 25 | 26 | // Make the compose button bigger and add some spacing 27 | .compose { 28 | padding-top: 50px; 29 | .v-icon { 30 | font-size: 50px; 31 | color: #ccc; 32 | padding-bottom: 15px; 33 | } 34 | 35 | // Make the compose button react when mousing over 36 | &:hover { 37 | color: white; 38 | .v-icon { 39 | color: white; 40 | } 41 | } 42 | 43 | // Workaround for always visible scroll bar 44 | &:after { 45 | right: 0px; 46 | } 47 | } 48 | 49 | // Just a barely noticeable gradient to make the background a little bit nicer 50 | .valo-menu { 51 | @include linear-gradient(230deg, #433 0%, #382a2a 100%); 52 | } 53 | 54 | // Horizontal lines below the header and message content 55 | .header, .content { 56 | border-bottom: 1px solid #ccc; 57 | } 58 | 59 | .message-layout { 60 | .message-sender { 61 | white-space: nowrap; 62 | overflow: hidden; 63 | } 64 | 65 | .message { 66 | overflow: hidden; 67 | } 68 | 69 | .v-caption-message { 70 | padding-left: 0; 71 | } 72 | 73 | &:hover { 74 | cursor: pointer; 75 | } 76 | } 77 | 78 | .indicator-star-red { 79 | .v-icon { 80 | color: #ff3301; 81 | } 82 | } 83 | 84 | .indicator-circle { 85 | .v-icon { 86 | color: #0398ff; 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/webapp/VAADIN/themes/mytheme/styles.scss: -------------------------------------------------------------------------------- 1 | @import "designs.scss"; 2 | @import "mytheme.scss"; 3 | @import "addons.scss"; 4 | 5 | // This file prefixes all rules with the theme name to avoid causing conflicts with other themes. 6 | // The actual styles should be defined in mytheme.scss 7 | 8 | .mytheme { 9 | @include addons; 10 | @include mytheme; 11 | } 12 | -------------------------------------------------------------------------------- /emailclient-tutorial-data/src/main/webapp/WEB-INF/beans.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaadin/designer-tutorials/5a810e6e5c3cb78f4396405c909491dcd8d84533/emailclient-tutorial-data/src/main/webapp/WEB-INF/beans.xml -------------------------------------------------------------------------------- /emailclient-tutorial-data/tutorial-images/email-client-with-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaadin/designer-tutorials/5a810e6e5c3cb78f4396405c909491dcd8d84533/emailclient-tutorial-data/tutorial-images/email-client-with-data.png -------------------------------------------------------------------------------- /emailclient-tutorial/README.md: -------------------------------------------------------------------------------- 1 | `This tutorial is written using Java 8, Vaadin 7.7.3 and Designer 1.2` 2 | 3 | Building a comprehensive UI from scratch with Vaadin Designer 4 | ================================== 5 | If you just want to see the end result, can fork this project and run the code yourself. However, I recommend starting from scratch and going through all the steps yourself. 6 | 7 | In the following tutorial you will build a bit more extensive application UI than in some of the earlier tutorials. This tutorial familiarizes you with the different features of [Vaadin Designer](https://vaadin.com/designer) and gives you ideas of how the tool can be used more effectively. The tutorial is based on a video, where Marc and Ville from Vaadin demonstrate how Vaadin Designer can be used to create a substantial application from an existing design. 8 | 9 | [![Vaadin Designer demonstration](https://cloud.githubusercontent.com/assets/1398470/10881298/3b1b49ba-816a-11e5-812f-873f4ae5e953.png)](https://www.youtube.com/watch?v=-6Ix8WHgD6g "Vaadin Designer demonstration") 10 | 11 | In the video they use a design from a site called www.100daysui.com where Paul Flavius Nechita made a UI design per day. The design for day [#38](https://dribbble.com/shots/2181203-Day-038-Email-Client/attachments/402034) was a mockup of an email client. This tutorial breaks down the steps in the video to help you follow the same workflow. Let’s see how close we can get to the design with only a little effort. 12 | 13 | Start by creating a project 14 | --------------------------- 15 | Create a new Vaadin 7 project either by using the Vaadin Eclipse plugin or Maven. You should use version 7.7.3 or newer of Vaadin. If you are using Maven, just use vaadin-archetype-application. 16 | ``` 17 | mvn archetype:generate -DarchetypeGroupId=com.vaadin -DarchetypeArtifactId=vaadin-archetype-application -DarchetypeVersion=7.7.3 18 | ``` 19 | Getting a head start 20 | -------------------- 21 | The application UI is divided into three areas: the menu layout on the left side, the action toolbar on the top right, and the list of email messages in the content area on the right. To get a good head start you can use a template called Responsive Application. The template has a menu for the left side and a content area. 22 | 23 | The application layout created with the template is also responsive, meaning that menu items are displayed in a more compact way when the width of the browser window gets smaller, e.g. in a mobile browser. The responsiveness is done using Vaadin Framework’s responsive extension and specific style names in Valo theme. The responsive part is out of the scope of this tutorial. 24 | 25 | * Create a new design in your project by right clicking your project and selecting __New › Other… › Vaadin Design.__ 26 | * In the dialog, select the __Responsive Application template__ and give the design the name ApplicationDesign. 27 | 28 | __Your design from the template should look like this__ 29 | ![Starting point from responsive template](https://cloud.githubusercontent.com/assets/1398470/10730425/86d938de-7bf8-11e5-8650-7a841071718d.png) 30 | 31 | Beautiful buttons 32 | ----------------- 33 | * Remove the blue menuTitle HorizontalLayout that has the text ‘The Application’. 34 | * Select the top most button userButton and change its style from the properties panel. 35 | * Clear the value of PrimaryStyleName property and set the StyleName property value with opening the style editor ![property editor button](https://cloud.githubusercontent.com/assets/1398470/10730428/8b182eaa-7bf8-11e5-9735-859c9d878d1d.png). 36 | * From ValoTheme, add styles `BUTTON_BORDERLESS` and `BUTTON_ICON_ALIGN_TOP`. 37 | * Click OK to close the style editor. 38 | 39 | As you can see, the button style changed and the button StyleName property has the value ‘borderless icon-align-top’. Sometimes it’s faster just to write the style name instead of using the style editor, if you remember the style name, that is. 40 | 41 | * Modify the userButton 42 | * Set the height to 150px. 43 | * Change its caption to Compose. 44 | * Change its name to composeButton. 45 | * Give a new icon with the icon editor. Select the Font Icons tab and select the icon called `EDIT`. 46 | 47 | The inbox button is ok and can be moved below the composeButton. The rest of the buttons you need to change: name, caption, and icon properties. The template doesn’t contain enough buttons, so you need to add a couple. The easiest way is to copy one of the buttons and paste it a couple of times. To get the little number badge by the button caption, you need to set the HtmlContentAllowed checkbox and set the button caption to contain an Html snippet e.g. `99+`. 48 | 49 | ![Icon FILES_O](https://cloud.githubusercontent.com/assets/1398470/10730429/8ea45c56-7bf8-11e5-81a2-2a975f14fef2.png) FILES_O, ![Icon PAPER_PLANE](https://cloud.githubusercontent.com/assets/1398470/10730431/911a5b52-7bf8-11e5-824a-f3d58cd72e9d.png) PAPER_PLANE, ![Icon EXCLAMATION](https://cloud.githubusercontent.com/assets/1398470/10730434/92742bcc-7bf8-11e5-9506-09ac57da1d29.png) EXCLAMATION, ![Icon TRASH_O](https://cloud.githubusercontent.com/assets/1398470/10730438/95749ac8-7bf8-11e5-9583-cbc404beca5c.png) TRASH_O, ![Icon FLAG](https://cloud.githubusercontent.com/assets/1398470/10730439/976f3a86-7bf8-11e5-82ee-1dd179ffaefa.png) FLAG. 50 | 51 | __At this point your application should look like this__ 52 | ![Buttons made a bit better](https://cloud.githubusercontent.com/assets/1398470/10730445/9fc418dc-7bf8-11e5-9127-9d325c71a149.png) 53 | 54 | The left side menu looks quite nice already, but you need to style it up a bit to get it to look more like the UI mockup. You need to add the styles to your theme scss file. Remember that any Valo variables need to be set before the valo.scss is imported. All the other style definitions go inside your theme mixin. 55 | 56 | * Change the color of the menu background: `$valo-menu-background-color: #433;` 57 | * Change the menu badge roundness: `$v-border-radius: 10px;` 58 | 59 | Make the menu wider when the layout is in the “desktop” mode. Add a responsive extension CSS “breakpoint”. The topic of responsive layouts is out of our scope, but if you are interested, check out the Book of Vaadin chapter about it: https://vaadin.com/book/-/page/themes.responsive.html. 60 | ```css 61 | .valo-menu-responsive[width-range~="1101px-"] { 62 | .valo-menu-item-caption { 63 | min-width: 150px; 64 | } 65 | } 66 | ``` 67 | Add some space around the menu items by making the menu item line height higher and then realign the badge. 68 | ```css 69 | .valo-menu-item { 70 | line-height: 45px; 71 | .valo-menu-badge { 72 | top: 12px; 73 | } 74 | } 75 | ``` 76 | And finally make the compose button more dominant. Add another StyleName called compose to composeButton. With these Sass (and CSS) directives, your buttons should look correct. 77 | 78 | ```css 79 | .compose { 80 | padding-top: 50px; 81 | .v-icon { 82 | font-size: 50px; 83 | color: #ccc; 84 | padding-bottom: 15px; 85 | } 86 | 87 | // Make the compose button react when mousing over 88 | &:hover { 89 | color: white; 90 | .v-icon { 91 | color: white; 92 | } 93 | } 94 | 95 | // Workaround for always visible scroll bar 96 | &:after { 97 | right: 0px; 98 | } 99 | } 100 | ``` 101 | __With correctly styled buttons your application should look like this__ 102 | ![Beautiful buttons](https://cloud.githubusercontent.com/assets/1398470/10730446/a2f026f4-7bf8-11e5-9484-789606745fbd.png) 103 | 104 | Toolbar 105 | ------- 106 | Now that the left side navigation is looking good, let’s implement the toolbar above the message list. 107 | * First make the content called VerticalLayout full size and then drag a HorizontalLayout and a Panel into the content layout. 108 | * Make sure the Panel is full size and has ExpandRatio 1.0, and the HorizontalLayout has 100% width and an undefined height. 109 | * The expand is set automatically when you click the quick actions for the layout sizes in the Designer. 110 | * Add spacing and margins to the HorizontalLayout and remove margins and spacing from the content layout. 111 | * Set the `PANEL_BORDERLESS` style for the Panel. 112 | 113 | Build the toolbar component structure 114 | * Drag a Label into the toolbar HorizontalLayout 115 | * Value: Sort by 116 | * Align it middle-left with the quick actions 117 | * Drag a ComboBox into the toolbar layout 118 | * Set a width of 150px 119 | * Drag buttons, give them a name, remove their captions, and add their icons: 120 | * Delete button icon: `TIMES` 121 | * Reply button icon: `MAIL_REPLY` 122 | * Reply all button icon: `MAIL_REPLY_ALL` 123 | * Forward button icon: `MAIL_FORWARD.` 124 | * Wrap reply button with a CssLayout by right clicking the button in the Outline and select Wrap with… 125 | * Move ‘reply all’ and ‘forward’ buttons to the CssLayout and change the layout StyleName to `LAYOUT_COMPONENT_GROUP` from Valo Theme. 126 | 127 | Message list 128 | ------------ 129 | The scrollable Panel will contain the list of messages in each of the selected folders. There’s a slight challenge to design the message look-and-feel, because the content in the Panel is dynamic and the 1.0 version of Vaadin Designer doesn’t support nested designs nor component compositions. This is likely to be changed in the future, but in the meanwhile, what you want to do in case of dynamic content is to first design the composition in the place it’s going to appear and then detach it to a separate design file. This way you can benefit both from having the visual tools for designing and still keep the composition accessible from Java. Drag a VerticalLayout into the content Panel. Set its width to 100% and put the spacing on. Now you can start with the message itself. 130 | 131 | Build the message component structure 132 | * Drag a HorizontalLayout into the VerticalLayout inside content Panel. 133 | * Width 100%, and height 125px. 134 | * StyleName: message-layout 135 | * Drag a Button into the HorizontalLayout 136 | * Caption: n/a 137 | * Name: indicatorButton 138 | * Icon: Font icon `STAR` 139 | * StyleName: borderless 140 | * Drag a VerticalLayout into the HorizontalLayout 141 | * Expand the width and height to 100% 142 | * StyleName: content 143 | * Drag a Label into the VerticalLayout 144 | * Name: senderLabel 145 | * Expand it to 100% width 146 | * Set the label value to “This is the subject” 147 | * StyleName: bold and message-sender 148 | * Drag another Label into the VerticalLayout below the senderLabel 149 | * Name: messageLabel 150 | * Expand the label to 100% width and height 151 | * Label caption: This is the title 152 | * Label value: Put something e.g. lorem ipsum 153 | * StyleName: message 154 | 155 | Provided you added the style names to the components as instructed, you can use these style definitions. 156 | 157 | To get the horizontal line under each message: 158 | ```css 159 | .header, .content { 160 | border-bottom: 1px solid #ccc; 161 | } 162 | ``` 163 | To get the message title and content to behave even if they don’t fit in the given space: 164 | ```css 165 | .message-layout { 166 | .message-sender { 167 | white-space: nowrap; 168 | overflow: hidden; 169 | } 170 | 171 | .message { 172 | overflow: hidden; 173 | } 174 | } 175 | ``` 176 | Finally enable the right side margin of the message content VerticalLayout from the properties. Individual margins can be enabled using the margin editor, just click ![property editor button](https://cloud.githubusercontent.com/assets/1398470/10730428/8b182eaa-7bf8-11e5-9735-859c9d878d1d.png). 177 | 178 | __Completed message item design__ 179 | ![Message design ready](https://cloud.githubusercontent.com/assets/1398470/10730449/aa87145e-7bf8-11e5-9b53-b128a4615c8f.png) 180 | 181 | As the final step in implementing the message component you need to create a new design. Name it MessageDesign and use the blank template. Then copy-paste the whole message layout to your new design. At the time of writing this, there is a limitation in Designer, which prevents you pasting to a blank design in the visual view. You need to switch to the source mode and paste your content in between the body elements. 182 | 183 | Create a new Java class called Message as a subclass of MessageDesign. This Message class is the place where you would implement the component logic, but for now, you can leave it empty. Create a bunch of Message instances in a loop to demonstrate how the dynamic content works in your application design 184 | ```java 185 | @Override 186 | protected void init(VaadinRequest vaadinRequest) { 187 | final ApplicationDesign design = new ApplicationDesign(); 188 | setContent(design); 189 | 190 | for (int i = 0; i < 10; i++) { 191 | design.messageList.addComponent(new Message()); 192 | } 193 | } 194 | ``` 195 | 196 | Final result 197 | ------------ 198 | The final result looks quite nice. You started from a basic responsive application template and took some simple steps to modify the design to look like the design mockup. First you modified the left side menu to have the correct buttons and styled the compose button to be more dominant. Then you implemented the rest of the application layout to contain a toolbar and a scrollable message list. Finally you created a message component to be used dynamically in your Java code. After these steps your design should look more or less like in the image below. Great job! 199 | 200 | __Finished application__
201 | ![Final result](https://cloud.githubusercontent.com/assets/1398470/10730450/ad4dae46-7bf8-11e5-9dd2-a00dda94b1cd.png) 202 | 203 | What now? 204 | --------- 205 | As you probably noticed, the end result isn't completely identical with the original mockup. The email dates are not there and the menu has some more info at the bottom. These are left for you to work on and now you can try out your new Vaadin Designer skills for real! 206 | -------------------------------------------------------------------------------- /emailclient-tutorial/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.vaadin.example 6 | emailclient-tutorial 7 | war 8 | 1.0-SNAPSHOT 9 | emailclient-tutorial 10 | 11 | 12 | 3 13 | 14 | 15 | 16 | 7.7.3 17 | ${vaadin.version} 18 | 9.2.3.v20140905 19 | 1.8 20 | 1.8 21 | UTF-8 22 | 23 | local 24 | 25 | 26 | 27 | 28 | vaadin-addons 29 | https://maven.vaadin.com/vaadin-addons 30 | 31 | 32 | 33 | 34 | 35 | 36 | com.vaadin 37 | vaadin-bom 38 | ${vaadin.version} 39 | pom 40 | import 41 | 42 | 43 | 44 | 45 | 46 | 47 | javax.servlet 48 | javax.servlet-api 49 | 3.0.1 50 | provided 51 | 52 | 53 | com.vaadin 54 | vaadin-server 55 | 56 | 57 | com.vaadin 58 | vaadin-push 59 | 60 | 61 | com.vaadin 62 | vaadin-client-compiled 63 | 64 | 65 | com.vaadin 66 | vaadin-themes 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-compiler-plugin 75 | 3.0 76 | 77 | ${project.encoding} 78 | ${project.source.version} 79 | ${project.target.version} 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-resources-plugin 85 | 2.6 86 | 87 | ${project.encoding} 88 | 89 | 90 | 91 | org.apache.maven.plugins 92 | maven-war-plugin 93 | 2.3 94 | 95 | false 96 | 97 | WEB-INF/classes/VAADIN/gwt-unitCache/**, 98 | WEB-INF/classes/VAADIN/widgetsets/WEB-INF/** 99 | 100 | 101 | 102 | com.vaadin 103 | vaadin-maven-plugin 104 | ${vaadin.plugin.version} 105 | 106 | -Xmx512M -Xss1024k 107 | ${basedir}/target/classes/VAADIN/widgetsets 108 | false 109 | false 110 | 111 | true 112 | 113 | 114 | 115 | 116 | update-theme 117 | update-widgetset 118 | compile 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | org.apache.maven.plugins 127 | maven-source-plugin 128 | 2.4 129 | 130 | 131 | org.apache.maven.plugins 132 | maven-clean-plugin 133 | 2.6.1 134 | 135 | 136 | 137 | 138 | src/main/webapp/VAADIN/themes 139 | 140 | **/styles.css 141 | **/styles.scss.cache 142 | 143 | 144 | 145 | 146 | 147 | 148 | 150 | 151 | org.eclipse.jetty 152 | jetty-maven-plugin 153 | ${jetty.plugin.version} 154 | 155 | 2 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | vaadin-prerelease 165 | 166 | false 167 | 168 | 169 | 170 | 171 | vaadin-prereleases 172 | https://maven.vaadin.com/vaadin-prereleases 173 | 174 | 175 | vaadin-snapshots 176 | https://oss.sonatype.org/content/repositories/vaadin-snapshots/ 177 | 178 | false 179 | 180 | 181 | true 182 | 183 | 184 | 185 | 186 | 187 | vaadin-prereleases 188 | https://maven.vaadin.com/vaadin-prereleases 189 | 190 | 191 | vaadin-snapshots 192 | https://oss.sonatype.org/content/repositories/vaadin-snapshots/ 193 | 194 | false 195 | 196 | 197 | true 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/java/org/vaadin/example/ApplicationDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.Button; 6 | import com.vaadin.ui.ComboBox; 7 | import com.vaadin.ui.CssLayout; 8 | import com.vaadin.ui.HorizontalLayout; 9 | import com.vaadin.ui.VerticalLayout; 10 | import com.vaadin.ui.declarative.Design; 11 | 12 | /** 13 | * !! DO NOT EDIT THIS FILE !! 14 | * 15 | * This class is generated by Vaadin Designer and will be overwritten. 16 | * 17 | * Please make a subclass with logic and additional interfaces as needed, 18 | * e.g class LoginView extends LoginDesign implements View { … } 19 | */ 20 | @DesignRoot 21 | @AutoGenerated 22 | @SuppressWarnings("serial") 23 | public class ApplicationDesign extends HorizontalLayout { 24 | protected Button menuToggle; 25 | protected CssLayout menuItems; 26 | protected Button composeButton; 27 | protected Button inboxButton; 28 | protected Button draftsButton; 29 | protected Button sentButton; 30 | protected Button junkButton; 31 | protected Button trashButton; 32 | protected Button flaggedButton; 33 | protected VerticalLayout content; 34 | protected ComboBox sortCombo; 35 | protected Button deleteButton; 36 | protected Button replyButton; 37 | protected Button replyAllButton; 38 | protected Button forwardButton; 39 | protected VerticalLayout messageList; 40 | 41 | public ApplicationDesign() { 42 | Design.read(this); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/java/org/vaadin/example/Message.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | /** 4 | * This is the place to implement component logic for MessageDesign. The super 5 | * class should not be edited, because Vaadin Designer overwrites it. 6 | */ 7 | public class Message extends MessageDesign { 8 | } 9 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/java/org/vaadin/example/MessageDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.Button; 6 | import com.vaadin.ui.HorizontalLayout; 7 | import com.vaadin.ui.Label; 8 | import com.vaadin.ui.declarative.Design; 9 | 10 | /** 11 | * !! DO NOT EDIT THIS FILE !! 12 | * 13 | * This class is generated by Vaadin Designer and will be overwritten. 14 | * 15 | * Please make a subclass with logic and additional interfaces as needed, 16 | * e.g class LoginView extends LoginDesign implements View { … } 17 | */ 18 | @DesignRoot 19 | @AutoGenerated 20 | @SuppressWarnings("serial") 21 | public class MessageDesign extends HorizontalLayout { 22 | protected Button indicatorButton; 23 | protected Label senderLabel; 24 | protected Label messageLabel; 25 | 26 | public MessageDesign() { 27 | Design.read(this); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/java/org/vaadin/example/MyUI.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import javax.servlet.annotation.WebServlet; 4 | 5 | import com.vaadin.annotations.Theme; 6 | import com.vaadin.annotations.VaadinServletConfiguration; 7 | import com.vaadin.server.VaadinRequest; 8 | import com.vaadin.server.VaadinServlet; 9 | import com.vaadin.ui.UI; 10 | 11 | /** 12 | * 13 | */ 14 | @Theme("mytheme") 15 | public class MyUI extends UI { 16 | 17 | @Override 18 | protected void init(VaadinRequest vaadinRequest) { 19 | final ApplicationDesign design = new ApplicationDesign(); 20 | setContent(design); 21 | 22 | // This replaces a proper backend just to simulate how the view behaves 23 | // with dynamic content 24 | for (int i = 0; i < 10; i++) { 25 | design.messageList.addComponent(new Message()); 26 | } 27 | } 28 | 29 | @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true) 30 | @VaadinServletConfiguration(ui = MyUI.class, productionMode = false) 31 | public static class MyUIServlet extends VaadinServlet { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/resources/org/vaadin/example/ApplicationDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Menu 12 | 13 | 14 | 15 | Compose 16 | 17 | 18 | Inbox 19 | 7 20 | 21 | 22 | Drafts 23 | 24 | 25 | Sent 26 | 27 | 28 | Junk 29 | 30 | 31 | Trash 32 | 99+ 33 | 34 | 35 | Flagged 36 | 2 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | Sort by: 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/resources/org/vaadin/example/MessageDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | This is the sender 12 | 13 | 14 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Sed posuere interdum sem. Quisque ligula eros ullamcorper quis, lacinia quis facilisis sed sapien. Mauris varius diam vitae arcu. Sed arcu lectus auctor vitae, consectetuer et venenatis eget velit. Sed augue orci, lacinia eu tincidunt et eleifend nec lacus. Donec ultricies nisl ut felis, suspendisse potenti. 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/webapp/VAADIN/themes/mytheme/addons.scss: -------------------------------------------------------------------------------- 1 | /* This file is automatically managed and will be overwritten from time to time. */ 2 | /* Do not manually edit this file. */ 3 | 4 | /* Import and include this mixin into your project theme to include the addon themes */ 5 | @mixin addons { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/webapp/VAADIN/themes/mytheme/designs.scss: -------------------------------------------------------------------------------- 1 | // Styles imported from ApplicationDesign.html 2 | // Workaround for a https://dev.vaadin.com/ticket/19170 to get hidden icons in some environments to show 3 | #responsive-application-template.valo-menu-responsive .valo-menu-part .valo-menu-item span.v-icon { 4 | opacity: 1.0; 5 | } 6 | 7 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/webapp/VAADIN/themes/mytheme/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaadin/designer-tutorials/5a810e6e5c3cb78f4396405c909491dcd8d84533/emailclient-tutorial/src/main/webapp/VAADIN/themes/mytheme/favicon.ico -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/webapp/VAADIN/themes/mytheme/mytheme.scss: -------------------------------------------------------------------------------- 1 | // Valo parameters to make the menu look as desired 2 | $valo-menu-background-color: #433; 3 | $v-focus-color: #433; 4 | $v-border-radius: 10px; 5 | 6 | @import "../valo/valo.scss"; 7 | 8 | @mixin mytheme { 9 | @include valo; 10 | 11 | // More spacing around the menu items (and re-align badge after that change) 12 | .valo-menu-item { 13 | line-height: 45px; 14 | .valo-menu-badge { 15 | top: 12px; 16 | } 17 | } 18 | 19 | // Only for the "desktop" (wide) version: make menu wider 20 | .valo-menu-responsive[width-range~="1101px-"] { 21 | .valo-menu-item-caption { 22 | min-width: 150px; 23 | } 24 | } 25 | 26 | // Make the compose button bigger and add some spacing 27 | .compose { 28 | padding-top: 50px; 29 | .v-icon { 30 | font-size: 50px; 31 | color: #ccc; 32 | padding-bottom: 15px; 33 | } 34 | 35 | // Make the compose button react when mousing over 36 | &:hover { 37 | color: white; 38 | .v-icon { 39 | color: white; 40 | } 41 | } 42 | 43 | // Workaround for always visible scroll bar 44 | &:after { 45 | right: 0px; 46 | } 47 | } 48 | 49 | // Just a barely noticeable gradient to make the background a little bit nicer 50 | .valo-menu { 51 | @include linear-gradient(230deg, #433 0%, #382a2a 100%); 52 | } 53 | 54 | // Horizontal lines below the header and message content 55 | .header, .content { 56 | border-bottom: 1px solid #ccc; 57 | } 58 | 59 | .message-layout { 60 | .message-sender { 61 | white-space: nowrap; 62 | overflow: hidden; 63 | } 64 | 65 | .message { 66 | overflow: hidden; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /emailclient-tutorial/src/main/webapp/VAADIN/themes/mytheme/styles.scss: -------------------------------------------------------------------------------- 1 | @import "designs.scss"; 2 | @import "mytheme.scss"; 3 | @import "addons.scss"; 4 | 5 | // This file prefixes all rules with the theme name to avoid causing conflicts with other themes. 6 | // The actual styles should be defined in mytheme.scss 7 | 8 | .mytheme { 9 | @include addons; 10 | @include mytheme; 11 | } 12 | -------------------------------------------------------------------------------- /simplenavi/README.md: -------------------------------------------------------------------------------- 1 | `This tutorial is written using Java 8` 2 | 3 | simplenavi 4 | ============== 5 | 6 | Template for a simple Vaadin application that only requires a Servlet 3.0 container to run. 7 | 8 | 9 | Workflow 10 | ======== 11 | 12 | To compile the entire project, run "mvn install". 13 | To run the application, run "mvn jetty:run" and open http://localhost:8080/ . 14 | 15 | To develop the theme, simply update the relevant theme files and reload the application. 16 | Pre-compiling a theme eliminates automatic theme updates at runtime - see below for more information. 17 | 18 | Debugging client side code 19 | - run "mvn vaadin:run-codeserver" on a separate console while the application is running 20 | - activate Super Dev Mode in the debug window of the application 21 | 22 | To produce a deployable production mode WAR: 23 | - change productionMode to true in the servlet class configuration (nested in the UI class) 24 | - run "mvn clean vaadin:compile-theme package" 25 | - See below for more information. Running "mvn clean" removes the pre-compiled theme. 26 | - test with "mvn jetty:run-war 27 | 28 | Using a precompiled theme 29 | ------------------------- 30 | 31 | When developing the application, Vaadin can compile the theme on the fly when needed, 32 | or the theme can be precompiled to speed up page loads. 33 | 34 | To precompile the theme run "mvn vaadin:compile-theme". Note, though, that once 35 | the theme has been precompiled, any theme changes will not be visible until the 36 | next theme compilation or running the "mvn clean" target. 37 | 38 | When developing the theme, running the application in the "run" mode (rather than 39 | in "debug") in the IDE can speed up consecutive on-the-fly theme compilations 40 | significantly. 41 | -------------------------------------------------------------------------------- /simplenavi/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | org.vaadin.example 6 | simplenavi 7 | war 8 | 1.0-SNAPSHOT 9 | simplenavi 10 | 11 | 12 | 3 13 | 14 | 15 | 16 | 7.7.3 17 | ${vaadin.version} 18 | 9.2.3.v20140905 19 | 1.8 20 | 1.8 21 | UTF-8 22 | 23 | local 24 | 25 | 26 | 27 | 28 | vaadin-addons 29 | https://maven.vaadin.com/vaadin-addons 30 | 31 | 32 | 33 | 34 | 35 | 36 | com.vaadin 37 | vaadin-bom 38 | ${vaadin.version} 39 | pom 40 | import 41 | 42 | 43 | 44 | 45 | 46 | 47 | javax.servlet 48 | javax.servlet-api 49 | 3.0.1 50 | provided 51 | 52 | 53 | com.vaadin 54 | vaadin-server 55 | 56 | 57 | com.vaadin 58 | vaadin-push 59 | 60 | 61 | com.vaadin 62 | vaadin-client-compiled 63 | 64 | 65 | com.vaadin 66 | vaadin-themes 67 | 68 | 69 | 70 | 71 | 72 | 73 | org.apache.maven.plugins 74 | maven-compiler-plugin 75 | 3.0 76 | 77 | ${project.encoding} 78 | ${project.source.version} 79 | ${project.target.version} 80 | 81 | 82 | 83 | org.apache.maven.plugins 84 | maven-resources-plugin 85 | 2.6 86 | 87 | ${project.encoding} 88 | 89 | 90 | 91 | org.apache.maven.plugins 92 | maven-war-plugin 93 | 2.3 94 | 95 | false 96 | 97 | WEB-INF/classes/VAADIN/gwt-unitCache/**, 98 | WEB-INF/classes/VAADIN/widgetsets/WEB-INF/** 99 | 100 | 101 | 102 | com.vaadin 103 | vaadin-maven-plugin 104 | ${vaadin.plugin.version} 105 | 106 | -Xmx512M -Xss1024k 107 | ${basedir}/target/classes/VAADIN/widgetsets 108 | false 109 | false 110 | 111 | true 112 | 113 | 114 | 115 | 116 | update-theme 117 | update-widgetset 118 | compile 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | org.apache.maven.plugins 127 | maven-source-plugin 128 | 2.4 129 | 130 | 131 | org.apache.maven.plugins 132 | maven-clean-plugin 133 | 2.6.1 134 | 135 | 136 | 137 | 138 | src/main/webapp/VAADIN/themes 139 | 140 | **/styles.css 141 | **/styles.scss.cache 142 | 143 | 144 | 145 | 146 | 147 | 148 | 150 | 151 | org.eclipse.jetty 152 | jetty-maven-plugin 153 | ${jetty.plugin.version} 154 | 155 | 2 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | vaadin-prerelease 165 | 166 | false 167 | 168 | 169 | 170 | 171 | vaadin-prereleases 172 | https://maven.vaadin.com/vaadin-prereleases 173 | 174 | 175 | vaadin-snapshots 176 | https://oss.sonatype.org/content/repositories/vaadin-snapshots/ 177 | 178 | false 179 | 180 | 181 | true 182 | 183 | 184 | 185 | 186 | 187 | vaadin-prereleases 188 | https://maven.vaadin.com/vaadin-prereleases 189 | 190 | 191 | vaadin-snapshots 192 | https://oss.sonatype.org/content/repositories/vaadin-snapshots/ 193 | 194 | false 195 | 196 | 197 | true 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /simplenavi/src/main/java/org/vaadin/example/MainLayout.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.navigator.Navigator; 4 | import com.vaadin.ui.UI; 5 | 6 | public class MainLayout extends MainLayoutDesign { 7 | 8 | public MainLayout() { 9 | Navigator navigator = new Navigator(UI.getCurrent(), contentPanel); 10 | navigator.addView(StatsView.VIEW_NAME, StatsView.class); 11 | navigator.addView(PluginsView.VIEW_NAME, PluginsView.class); 12 | navigator.addView(PermissionsView.VIEW_NAME, PermissionsView.class); 13 | 14 | menuButton1.addClickListener(event -> doNavigate(StatsView.VIEW_NAME)); 15 | menuButton2 16 | .addClickListener(event -> doNavigate(PluginsView.VIEW_NAME)); 17 | menuButton3.addClickListener( 18 | event -> doNavigate(PermissionsView.VIEW_NAME)); 19 | 20 | if (navigator.getState().isEmpty()) { 21 | navigator.navigateTo(StatsView.VIEW_NAME); 22 | } else { 23 | navigator.navigateTo(navigator.getState()); 24 | } 25 | } 26 | 27 | private void doNavigate(String viewName) { 28 | getUI().getNavigator().navigateTo(viewName); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /simplenavi/src/main/java/org/vaadin/example/MainLayoutDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.HorizontalLayout; 6 | import com.vaadin.ui.NativeButton; 7 | import com.vaadin.ui.Panel; 8 | import com.vaadin.ui.VerticalLayout; 9 | import com.vaadin.ui.declarative.Design; 10 | 11 | /** 12 | * !! DO NOT EDIT THIS FILE !! 13 | * 14 | * This class is generated by Vaadin Designer and will be overwritten. 15 | * 16 | * Please make a subclass with logic and additional interfaces as needed, 17 | * e.g class LoginView extends LoginDesign implements View { … } 18 | */ 19 | @DesignRoot 20 | @AutoGenerated 21 | @SuppressWarnings("serial") 22 | public class MainLayoutDesign extends HorizontalLayout { 23 | protected VerticalLayout menuLayout; 24 | protected NativeButton menuButton1; 25 | protected NativeButton menuButton2; 26 | protected NativeButton menuButton3; 27 | protected Panel contentPanel; 28 | 29 | public MainLayoutDesign() { 30 | Design.read(this); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /simplenavi/src/main/java/org/vaadin/example/MyUI.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import javax.servlet.annotation.WebServlet; 4 | 5 | import com.vaadin.annotations.Theme; 6 | import com.vaadin.annotations.VaadinServletConfiguration; 7 | import com.vaadin.server.VaadinRequest; 8 | import com.vaadin.server.VaadinServlet; 9 | import com.vaadin.ui.UI; 10 | 11 | /** 12 | * 13 | */ 14 | @Theme("mytheme") 15 | public class MyUI extends UI { 16 | 17 | @Override 18 | protected void init(VaadinRequest vaadinRequest) { 19 | setContent(new MainLayout()); 20 | 21 | } 22 | 23 | @WebServlet(urlPatterns = "/*", name = "MyUIServlet", asyncSupported = true) 24 | @VaadinServletConfiguration(ui = MyUI.class, productionMode = false) 25 | public static class MyUIServlet extends VaadinServlet { 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /simplenavi/src/main/java/org/vaadin/example/PermissionsView.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.navigator.View; 4 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; 5 | 6 | public class PermissionsView extends PermissionsViewDesign implements View { 7 | 8 | public static final String VIEW_NAME = "permissions"; 9 | 10 | @Override 11 | public void enter(ViewChangeEvent event) { 12 | // TODO Auto-generated method stub 13 | 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /simplenavi/src/main/java/org/vaadin/example/PermissionsViewDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.VerticalLayout; 6 | import com.vaadin.ui.declarative.Design; 7 | 8 | /** 9 | * !! DO NOT EDIT THIS FILE !! 10 | * 11 | * This class is generated by Vaadin Designer and will be overwritten. 12 | * 13 | * Please make a subclass with logic and additional interfaces as needed, e.g 14 | * class LoginView extends LoginDesign implements View { … } 15 | */ 16 | @DesignRoot 17 | @AutoGenerated 18 | @SuppressWarnings("serial") 19 | public class PermissionsViewDesign extends VerticalLayout { 20 | public PermissionsViewDesign() { 21 | Design.read(this); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /simplenavi/src/main/java/org/vaadin/example/PluginsView.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.navigator.View; 4 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; 5 | 6 | public class PluginsView extends PluginsViewDesign implements View { 7 | 8 | public static final String VIEW_NAME = "plugins"; 9 | 10 | @Override 11 | public void enter(ViewChangeEvent event) { 12 | // TODO Auto-generated method stub 13 | 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /simplenavi/src/main/java/org/vaadin/example/PluginsViewDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.VerticalLayout; 6 | import com.vaadin.ui.declarative.Design; 7 | 8 | /** 9 | * !! DO NOT EDIT THIS FILE !! 10 | * 11 | * This class is generated by Vaadin Designer and will be overwritten. 12 | * 13 | * Please make a subclass with logic and additional interfaces as needed, e.g 14 | * class LoginView extends LoginDesign implements View { … } 15 | */ 16 | @DesignRoot 17 | @AutoGenerated 18 | @SuppressWarnings("serial") 19 | public class PluginsViewDesign extends VerticalLayout { 20 | public PluginsViewDesign() { 21 | Design.read(this); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /simplenavi/src/main/java/org/vaadin/example/StatsView.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.navigator.View; 4 | import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; 5 | 6 | public class StatsView extends StatsViewDesign implements View { 7 | 8 | public static final String VIEW_NAME = "stats"; 9 | 10 | @Override 11 | public void enter(ViewChangeEvent event) { 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /simplenavi/src/main/java/org/vaadin/example/StatsViewDesign.java: -------------------------------------------------------------------------------- 1 | package org.vaadin.example; 2 | 3 | import com.vaadin.annotations.AutoGenerated; 4 | import com.vaadin.annotations.DesignRoot; 5 | import com.vaadin.ui.VerticalLayout; 6 | import com.vaadin.ui.declarative.Design; 7 | 8 | /** 9 | * !! DO NOT EDIT THIS FILE !! 10 | * 11 | * This class is generated by Vaadin Designer and will be overwritten. 12 | * 13 | * Please make a subclass with logic and additional interfaces as needed, e.g 14 | * class LoginView extends LoginDesign implements View { … } 15 | */ 16 | @DesignRoot 17 | @AutoGenerated 18 | @SuppressWarnings("serial") 19 | public class StatsViewDesign extends VerticalLayout { 20 | public StatsViewDesign() { 21 | Design.read(this); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /simplenavi/src/main/resources/org/vaadin/example/MainLayoutDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Statistics 11 | 12 | 13 | Plug-ins 14 | 15 | 16 | Permissions 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /simplenavi/src/main/resources/org/vaadin/example/PermissionsViewDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Permissions 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /simplenavi/src/main/resources/org/vaadin/example/PluginsViewDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Plug-ins 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /simplenavi/src/main/resources/org/vaadin/example/StatsViewDesign.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Statistics 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /simplenavi/src/main/webapp/VAADIN/themes/mytheme/addons.scss: -------------------------------------------------------------------------------- 1 | /* This file is automatically managed and will be overwritten from time to time. */ 2 | /* Do not manually edit this file. */ 3 | 4 | /* Import and include this mixin into your project theme to include the addon themes */ 5 | @mixin addons { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /simplenavi/src/main/webapp/VAADIN/themes/mytheme/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vaadin/designer-tutorials/5a810e6e5c3cb78f4396405c909491dcd8d84533/simplenavi/src/main/webapp/VAADIN/themes/mytheme/favicon.ico -------------------------------------------------------------------------------- /simplenavi/src/main/webapp/VAADIN/themes/mytheme/mytheme.scss: -------------------------------------------------------------------------------- 1 | // Global variable overrides. Must be declared before importing Valo. 2 | 3 | // Defines the plaintext font size, weight and family. Font size affects general component sizing. 4 | //$v-font-size: 16px; 5 | //$v-font-weight: 300; 6 | //$v-font-family: "Open Sans", sans-serif; 7 | 8 | // Defines the border used by all components. 9 | //$v-border: 1px solid (v-shade 0.7); 10 | //$v-border-radius: 4px; 11 | 12 | // Affects the color of some component elements, e.g Button, Panel title, etc 13 | //$v-background-color: hsl(210, 0%, 98%); 14 | // Affects the color of content areas, e.g Panel and Window content, TextField input etc 15 | //$v-app-background-color: $v-background-color; 16 | 17 | // Affects the visual appearance of all components 18 | //$v-gradient: v-linear 8%; 19 | //$v-bevel-depth: 30%; 20 | //$v-shadow-opacity: 5%; 21 | 22 | // Defines colors for indicating status (focus, success, failure) 23 | //$v-focus-color: valo-focus-color(); // Calculates a suitable color automatically 24 | //$v-friendly-color: #2c9720; 25 | //$v-error-indicator-color: #ed473b; 26 | 27 | // For more information, see: https://vaadin.com/book/-/page/themes.valo.html 28 | // Example variants can be copy/pasted from https://vaadin.com/wiki/-/wiki/Main/Valo+Examples 29 | $v-app-loading-text: "Loading navigation example..."; 30 | $v-background-color: #fafafa; 31 | $v-app-background-color: #fff; 32 | $v-panel-background-color: #fff; 33 | $v-font-family: "Source Sans Pro"; 34 | $v-font-size: 20px; 35 | $v-font-color: #37404E; 36 | $v-font-weight: 400; 37 | 38 | @import "../valo/valo.scss"; 39 | 40 | @mixin mytheme { 41 | @include valo; 42 | 43 | $menu-bg: #0072C6; 44 | $menu-item-color: valo-font-color($menu-bg, 0.8); 45 | 46 | .menu-layout { 47 | background-color: $menu-bg; 48 | } 49 | .menu-item { 50 | position: relative; 51 | padding: 0 40px 0 20px; 52 | text-align: left; 53 | height: 50px; 54 | border: none; 55 | background-color: $menu-bg; 56 | color: $menu-item-color; 57 | outline: none; 58 | 59 | .v-nativebutton-caption { 60 | position: absolute; 61 | bottom: 10px; 62 | left: 2.5em; 63 | } 64 | 65 | .v-icon { 66 | font-size: 30px; 67 | } 68 | 69 | &:active span { 70 | @include transition(color 0.2s linear); 71 | color: darken($menu-item-color, 30%); 72 | } 73 | 74 | &:active .v-icon, &:focus .v-icon { 75 | position: relative; 76 | top: 0; 77 | left: 0; 78 | } 79 | 80 | &:hover { 81 | color: tint($menu-item-color, 50%); 82 | cursor: pointer; 83 | } 84 | } 85 | 86 | 87 | } 88 | -------------------------------------------------------------------------------- /simplenavi/src/main/webapp/VAADIN/themes/mytheme/styles.scss: -------------------------------------------------------------------------------- 1 | @import "mytheme.scss"; 2 | @import "addons.scss"; 3 | 4 | // This file prefixes all rules with the theme name to avoid causing conflicts with other themes. 5 | // The actual styles should be defined in mytheme.scss 6 | 7 | .mytheme { 8 | @include addons; 9 | @include mytheme; 10 | 11 | } 12 | --------------------------------------------------------------------------------