├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── baseplate.iml ├── example └── basic_example_page.dart ├── lib └── baseplate.dart ├── pubspec.lock ├── pubspec.yaml └── test └── baseplate_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | ios/.generated/ 9 | ios/Flutter/Generated.xcconfig 10 | ios/Runner/GeneratedPluginRegistrant.* 11 | 12 | \.idea/ 13 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 5391447fae6209bb21a89e6a5a6583cac1af9b4b 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.1.4] - 29/05/2019 2 | 3 | * Removed deprecated Baseplate class. Please now use bpRow and bpCol instead. 4 | * Support for max screen size added 5 | 6 | ## [0.1.3] - 13/05/2019 7 | 8 | * Added Support for `BoxConstraints` for when the widget will be less than the screen width on responsive layouts 9 | 10 | ## [0.1.2] - 06/02/2019 11 | 12 | * Added deprecation notice to Baseplate.row and Baseplate.col methods. Calling via bpRow and bpCol is preferred as these widgets _do_ appear in the inspector. 13 | * Updated example. 14 | 15 | ## [0.1.1] - 06/02/2019 16 | 17 | * Fixed logical error causing padding to display incorrectly when wrapping onto two rows. 18 | 19 | ## [0.1.0] - 06/02/2019 20 | 21 | * Switched to FractionallySizedBoxes to enable nesting of rows. Could break layouts on some devices hence the version increase. 22 | 23 | ## [0.0.3] - 06/02/2019 24 | 25 | * Removed unnecessary named parameters on the row constructor. 26 | * License added. 27 | 28 | ## [0.0.1] - 06/02/2019. 29 | 30 | * Initial Release. See readme.md 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # baseplate 2 | 3 | A responsive frontend material framework designed to emulate the behaviour of Bootstrap. 4 | 5 | ## Getting Started 6 | 7 | [Full documentation on the Wiki](https://github.com/HJBDev/flutter-baseplate/wiki) 8 | 9 | Import the Baseplate class. You can then use the widgets to build responsive layouts easily. 10 | 11 | I've included lots of breakpoints to give as much freedom as possible. You don't have to use all. Baseplate operates on a "up to" principle. If the screen width is less than or equal to your breakpoint (and there isn't one smaller) that's the one that will be used. 12 | 13 | It's a 12 column layout, similar to Bootstrap on the web. 14 | 15 | ![layout](https://i.imgur.com/GCAzjWj.png) 16 | 17 | ![code](https://i.imgur.com/yftC31h.png) 18 | -------------------------------------------------------------------------------- /baseplate.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /example/basic_example_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:baseplate/baseplate.dart'; 3 | 4 | class BasicExamplePage extends StatelessWidget { 5 | BasicExamplePage(); 6 | 7 | @override 8 | Widget build(BuildContext context) { 9 | return LayoutBuilder( 10 | builder: (_, constraints) => Scaffold( 11 | appBar: AppBar( 12 | title: Text('flutter-baseplate Example'), 13 | ), 14 | body: Container( 15 | child: bpRow( 16 | runSpacing: 8, 17 | padding: 8, 18 | gutter: 8, 19 | constraints: constraints, 20 | children: [ 21 | bpCol( 22 | w1200: 6, 23 | constraints: constraints, 24 | child: Container( 25 | color: Colors.red, 26 | height: 100, 27 | ), 28 | ), 29 | bpCol( 30 | w1200: 6, 31 | constraints: constraints, 32 | child: bpRow( 33 | children: [ 34 | bpCol( 35 | w1200: 6, 36 | constraints: constraints, 37 | child: Container( 38 | color: Colors.pink, 39 | height: 100, 40 | ), 41 | ), 42 | bpCol( 43 | w1200: 6, 44 | constraints: constraints, 45 | child: Container( 46 | color: Colors.blue, 47 | height: 100, 48 | ), 49 | ) 50 | ], 51 | )), 52 | bpCol( 53 | w1200: 6, 54 | constraints: constraints, 55 | child: Container( 56 | color: Colors.yellow, 57 | height: 100, 58 | )) 59 | ], 60 | )))); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/baseplate.dart: -------------------------------------------------------------------------------- 1 | library baseplate; 2 | 3 | import 'package:flutter/material.dart'; 4 | 5 | /// Senses Baseplate 6 | /// ---------------------------------------------------------- 7 | /// A responsive frontend framework for creating rich flutter 8 | /// user interfaces with a more web-oriented syntax. Influenced 9 | /// by the likes of Bootstrap and Materialize 10 | 11 | class bpCol extends StatelessWidget { 12 | int w360; 13 | int w540; 14 | int w720; 15 | int w1024; 16 | int w1200; 17 | int w1500; 18 | int w2000; 19 | int w2500; 20 | Widget child; 21 | int colCount; 22 | double gutter = 0.0; 23 | int colWidth = 0; 24 | double leftPadding = 0; 25 | double rightPadding = 0; 26 | final BoxConstraints constraints; 27 | 28 | bpCol({ 29 | this.w360, 30 | this.w540, 31 | this.w720, 32 | this.w1024, 33 | this.w1200, 34 | this.w1500, 35 | this.w2000, 36 | this.w2500, 37 | this.child, 38 | this.colCount, 39 | this.gutter, 40 | this.constraints, 41 | }); 42 | 43 | @override 44 | build(BuildContext context) { 45 | colWidth = Baseplate.calculateColWidth( 46 | context, w360, w540, w720, w1024, w1200, w1500, w2000, w2500, 47 | constraints: constraints); 48 | 49 | // calculate padding 50 | // int gutterCount = 2 + (colCount - 1); 51 | // double totalGutter = gutterCount * gutter; 52 | double width = Baseplate.calculateWidth(context, colWidth); 53 | 54 | return FractionallySizedBox( 55 | widthFactor: width, 56 | child: Container( 57 | child: Padding( 58 | padding: EdgeInsets.only(left: leftPadding, right: rightPadding), 59 | child: child), 60 | )); 61 | } 62 | 63 | setColCount(int count) { 64 | colCount = count; 65 | } 66 | 67 | getColWidth(context, BoxConstraints constraints) { 68 | return Baseplate.calculateColWidth( 69 | context, w360, w540, w720, w1024, w1200, w1500, w2000, w2500, 70 | constraints: constraints); 71 | } 72 | 73 | setRightPadding(double right) { 74 | rightPadding = right; 75 | } 76 | 77 | setLeftPadding(double left) { 78 | leftPadding = left; 79 | } 80 | 81 | setGutter(double theGutter) { 82 | gutter = theGutter; 83 | } 84 | } 85 | 86 | class bpRow extends StatelessWidget { 87 | final double gutter; 88 | final double padding; 89 | final double runSpacing; 90 | final List children; 91 | final BoxConstraints constraints; 92 | 93 | bpRow({ 94 | this.gutter = 0, 95 | this.runSpacing = 0, 96 | @required this.children, 97 | this.padding = 0, 98 | this.constraints, 99 | }); 100 | 101 | @override 102 | build(BuildContext context) { 103 | int colCount = 0; 104 | // what row am I on? 105 | // (tempColCount / 12).floor() 106 | Map rowColCounts = new Map(); 107 | 108 | int i = 0; 109 | children.forEach((col) { 110 | i++; 111 | // if the total count is a multiple of 12 (or 0) BEFORE the column width is added, it is at the start of the row 112 | // if there is only 1 child, the padding needs to be on both sides. 113 | 114 | if (children.length > 1) { 115 | if (colCount % 12 == 0 || colCount == 0) { 116 | col.setLeftPadding(padding); 117 | } else { 118 | col.setLeftPadding(gutter / 2); 119 | } 120 | } 121 | 122 | var initialColCount = colCount; 123 | colCount += col.getColWidth(context, constraints); 124 | 125 | // if the total count is a multiple of 12 AFTER the column width is added, it is at the END of the row. 126 | if (children.length > 1) { 127 | if (colCount % 12 == 0) { 128 | col.setRightPadding(padding); 129 | } else { 130 | col.setRightPadding(gutter / 2); 131 | } 132 | } 133 | 134 | if (children.length == 1) { 135 | col.setLeftPadding(padding); 136 | col.setRightPadding(padding); 137 | } 138 | 139 | if (children.length != 1 && 140 | colCount % 12 != 0 && 141 | initialColCount % 12 != 0 && 142 | initialColCount != 0) { 143 | col.setLeftPadding(gutter / 2); 144 | col.setRightPadding(gutter / 2); 145 | } 146 | 147 | // the row it's on 148 | int whatRow = (colCount / 12).floor(); 149 | 150 | // if it's a number with no remainder, then it's on the row below 151 | if (colCount % 12 == 0) { 152 | whatRow = whatRow - 1; 153 | } 154 | 155 | // build up the column counts per row 156 | if (rowColCounts[whatRow] == null) { 157 | rowColCounts[whatRow] = 1; 158 | } else { 159 | rowColCounts[whatRow]++; 160 | } 161 | 162 | // what do I need? 163 | // an array of the column counts per row 164 | // how am I getting it? 165 | // loop through all the children / 166 | // work out which row they are on / 167 | // count how many are on each row / 168 | }); 169 | 170 | colCount = 0; 171 | for (var i = 0; i < children.length; i++) { 172 | var col = children[i]; 173 | colCount += col.getColWidth(context, constraints); 174 | 175 | int whatRow = (colCount / 12).floor(); 176 | 177 | if (colCount % 12 == 0) { 178 | whatRow = whatRow - 1; 179 | } 180 | 181 | col.setColCount(rowColCounts[whatRow]); 182 | col.setGutter(gutter); 183 | } 184 | 185 | return Container( 186 | child: FractionallySizedBox( 187 | widthFactor: 1, 188 | child: Wrap( 189 | // spacing: gutter, 190 | runSpacing: runSpacing, 191 | children: children, 192 | ))); 193 | } 194 | } 195 | 196 | class Baseplate { 197 | static calculateColWidth(BuildContext context, int w360, int w540, int w720, 198 | int w1024, int w1200, int w1500, int w2000, int w2500, 199 | {BoxConstraints constraints}) { 200 | final _width = constraints?.maxWidth ?? MediaQuery.of(context).size.width; 201 | if (w360 != null && _width <= 360) { 202 | return w360; 203 | } else if (w540 != null && _width <= 540) { 204 | return w540; 205 | } else if (w720 != null && _width <= 720) { 206 | return w720; 207 | } else if (w1024 != null && _width <= 1024) { 208 | return w1024; 209 | } else if (w1200 != null && _width <= 1200) { 210 | return w1200; 211 | } else if (w1500 != null && _width <= 1500) { 212 | return w1500; 213 | } else if (w2000 != null && _width <= 2000) { 214 | return w2000; 215 | } else if (w2500 != null && _width > 2000) { 216 | return w2500; 217 | } else { 218 | return 12; 219 | } 220 | } 221 | 222 | static calculateWidth(BuildContext context, int colWidth, 223 | [BoxConstraints constraints, double padding = 0]) { 224 | final _width = constraints?.maxWidth ?? MediaQuery.of(context).size.width; 225 | var screenWidth = _width; 226 | var fraction = colWidth / 12; 227 | return fraction; 228 | // return (screenWidth - padding) * fraction; 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.2.0" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.0.4" 18 | charcode: 19 | dependency: transitive 20 | description: 21 | name: charcode 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.1.2" 25 | collection: 26 | dependency: transitive 27 | description: 28 | name: collection 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.14.11" 32 | flutter: 33 | dependency: "direct main" 34 | description: flutter 35 | source: sdk 36 | version: "0.0.0" 37 | flutter_test: 38 | dependency: "direct dev" 39 | description: flutter 40 | source: sdk 41 | version: "0.0.0" 42 | matcher: 43 | dependency: transitive 44 | description: 45 | name: matcher 46 | url: "https://pub.dartlang.org" 47 | source: hosted 48 | version: "0.12.5" 49 | meta: 50 | dependency: transitive 51 | description: 52 | name: meta 53 | url: "https://pub.dartlang.org" 54 | source: hosted 55 | version: "1.1.6" 56 | path: 57 | dependency: transitive 58 | description: 59 | name: path 60 | url: "https://pub.dartlang.org" 61 | source: hosted 62 | version: "1.6.2" 63 | pedantic: 64 | dependency: transitive 65 | description: 66 | name: pedantic 67 | url: "https://pub.dartlang.org" 68 | source: hosted 69 | version: "1.5.0" 70 | quiver: 71 | dependency: transitive 72 | description: 73 | name: quiver 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "2.0.3" 77 | sky_engine: 78 | dependency: transitive 79 | description: flutter 80 | source: sdk 81 | version: "0.0.99" 82 | source_span: 83 | dependency: transitive 84 | description: 85 | name: source_span 86 | url: "https://pub.dartlang.org" 87 | source: hosted 88 | version: "1.5.5" 89 | stack_trace: 90 | dependency: transitive 91 | description: 92 | name: stack_trace 93 | url: "https://pub.dartlang.org" 94 | source: hosted 95 | version: "1.9.3" 96 | stream_channel: 97 | dependency: transitive 98 | description: 99 | name: stream_channel 100 | url: "https://pub.dartlang.org" 101 | source: hosted 102 | version: "2.0.0" 103 | string_scanner: 104 | dependency: transitive 105 | description: 106 | name: string_scanner 107 | url: "https://pub.dartlang.org" 108 | source: hosted 109 | version: "1.0.4" 110 | term_glyph: 111 | dependency: transitive 112 | description: 113 | name: term_glyph 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "1.1.0" 117 | test_api: 118 | dependency: transitive 119 | description: 120 | name: test_api 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "0.2.5" 124 | typed_data: 125 | dependency: transitive 126 | description: 127 | name: typed_data 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "1.1.6" 131 | vector_math: 132 | dependency: transitive 133 | description: 134 | name: vector_math 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "2.0.8" 138 | sdks: 139 | dart: ">=2.2.0 <3.0.0" 140 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: baseplate 2 | description: A responsive frontend material framework designed to emulate the behaviour of Bootstrap on web. 3 | version: 0.1.4 4 | authors: 5 | - Harry 6 | - Rody Davis Jr 7 | homepage: https://github.com/HJBDev/flutter-baseplate 8 | 9 | environment: 10 | sdk: ">=2.0.0-dev.68.0 <3.0.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | 16 | dev_dependencies: 17 | flutter_test: 18 | sdk: flutter 19 | 20 | # For information on the generic Dart part of this file, see the 21 | # following page: https://www.dartlang.org/tools/pub/pubspec 22 | 23 | # The following section is specific to Flutter. 24 | flutter: 25 | 26 | # To add assets to your package, add an assets section, like this: 27 | # assets: 28 | # - images/a_dot_burr.jpeg 29 | # - images/a_dot_ham.jpeg 30 | # 31 | # For details regarding assets in packages, see 32 | # https://flutter.io/assets-and-images/#from-packages 33 | # 34 | # An image asset can refer to one or more resolution-specific "variants", see 35 | # https://flutter.io/assets-and-images/#resolution-aware. 36 | 37 | # To add custom fonts to your package, add a fonts section here, 38 | # in this "flutter" section. Each entry in this list should have a 39 | # "family" key with the font family name, and a "fonts" key with a 40 | # list giving the asset and other descriptors for the font. For 41 | # example: 42 | # fonts: 43 | # - family: Schyler 44 | # fonts: 45 | # - asset: fonts/Schyler-Regular.ttf 46 | # - asset: fonts/Schyler-Italic.ttf 47 | # style: italic 48 | # - family: Trajan Pro 49 | # fonts: 50 | # - asset: fonts/TrajanPro.ttf 51 | # - asset: fonts/TrajanPro_Bold.ttf 52 | # weight: 700 53 | # 54 | # For details regarding fonts in packages, see 55 | # https://flutter.io/custom-fonts/#from-packages 56 | -------------------------------------------------------------------------------- /test/baseplate_test.dart: -------------------------------------------------------------------------------- 1 | void main() { 2 | } 3 | --------------------------------------------------------------------------------