├── LICENSE ├── README.md ├── springboard ├── templates └── default │ ├── .sbconfig │ ├── deploy │ ├── css │ │ └── styles.min.css │ ├── index.html │ └── js │ │ ├── libs.js │ │ └── scripts.js │ └── source │ ├── css │ ├── normalize.css │ └── styles.css │ ├── index.html │ └── js │ ├── bootstrap.js │ ├── externs.js │ ├── libs │ ├── empty.js │ └── sbpath.js │ └── script.js └── tools ├── compiler.jar └── compressor.jar /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Justin Windle (justin@soulwire.co.uk) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Springboard 2 | 3 | Springboard helps you setup web projects in seconds and easily manage concatenation, minification and compilation of scripts and styles. 4 | 5 | The idea behind Springboard is to provide a universal build system for HTML/CSS/JS projects that works with your own project template library (whichever boilerplates you may use) and helps you get going with projects of any size quickly and easily. 6 | 7 | Here's how it works... 8 | 9 | # Blocks 10 | 11 | Blocks tell Springboard what to do with your scripts and styles when you build. Just tell it to **concat**, **minify** or **compile** and specify an output: 12 | 13 | 14 | [any number of linked styles] 15 | 16 | 17 | The output path serves as the block ID, so you can specify as many as you like and use the same blocks across multiple pages. 18 | 19 | You can also use the **show** and **hide** commands to rewrite code during the build process: 20 | 21 | // sb: hide 22 | var DEBUG = true; 23 | // sb end 24 | 25 | Or conversely: 26 | 27 | /* sb: show 28 | var DEBUG = false; 29 | sb: end */ 30 | 31 | # Installation 32 | 33 | $ git clone git@github.com:soulwire/Springboard.git Springboard 34 | $ cd Springboard 35 | $ python springboard install 36 | 37 | ### Setup a new project 38 | 39 | Once Springboard is installed, setting up a new project is easy 40 | 41 | $ cd /YourWorkspace/NewProject/ 42 | $ springboard init 43 | 44 | # Templates 45 | 46 | You can define any number of project templates by dropping them into Springboard's templates folder. To use them, simply specify their name when you **init** a project 47 | 48 | $ springboard init custom-template 49 | 50 | ### Build 51 | 52 | From within a project directory, invoke a build like so 53 | 54 | $ springboard build 55 | 56 | To see all available commands and options, just type 57 | 58 | $ springboard help 59 | 60 | And you can always use the **sb** alias for faster typing 61 | 62 | $ sb build 63 | 64 | ## Configuration 65 | 66 | The project template includes a small config file (.sbconfig), which allows you to specify default build settings for the project, such as the source and deploy directories and the Closure Compiler compilation level. 67 | 68 | ## Sublime Text Build System 69 | 70 | To use Springboard as a Sublime Text build system, create a file called **Springboard.sublime-build** containing the following 71 | 72 | { 73 | "cmd": ["python", "~/local/springboard/springboard", "build"], 74 | "working_dir": "${project_path:${folder}}" 75 | } 76 | 77 | and save it in the directory 78 | 79 | ~/Library/Application Support/Sublime Text 2/Packages/User/ 80 | 81 | 82 | -------------------------------------------------------------------------------- /springboard: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2011 Justin Windle 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 13 | # all 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 20 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | # DEALINGS IN THE SOFTWARE. 22 | 23 | import os 24 | import re 25 | import sys 26 | import getopt 27 | import fnmatch 28 | import logging 29 | import platform 30 | import fileinput 31 | import subprocess 32 | import webbrowser 33 | from shutil import copy, copyfileobj, copytree, ignore_patterns, rmtree 34 | 35 | # -------------------------------------------------- 36 | # 37 | # Config 38 | # 39 | # -------------------------------------------------- 40 | 41 | 42 | class Config: 43 | 44 | # Determine operating system 45 | sys = platform.system() 46 | 47 | # Set system alias 48 | if sys in ('Windows', 'Microsoft'): 49 | OS = 'win' 50 | elif sys in ('Darwin'): 51 | OS = 'mac' 52 | elif sys in ('Linux'): 53 | OS = 'linux' 54 | else: 55 | OS = 'other' 56 | 57 | # User directory 58 | USER_HOME = os.getenv('USERPROFILE') or os.getenv('HOME') 59 | 60 | # Springboard install directory 61 | SPRINGBOARD_HOME = os.path.join(USER_HOME, 'local', 'springboard') 62 | 63 | # Path to Closure compiler 64 | PATH_COMPILER = os.path.join(SPRINGBOARD_HOME, 'tools', 'compiler.jar') 65 | 66 | # Path to YUI compressor 67 | PATH_COMPRESSOR = os.path.join(SPRINGBOARD_HOME, 'tools', 'compressor.jar') 68 | 69 | # Default path to config file 70 | CONFIG_PATH = os.path.join(os.getcwd(), '.sbconfig') 71 | 72 | # Closure externs 73 | EXTERNS_FILES = None 74 | 75 | # Path to project source 76 | SOURCE_PATH = 'source' 77 | 78 | # Path to built project 79 | DEPLOY_PATH = 'deploy' 80 | 81 | # Path to project templates 82 | TEMPLATE_PATH = 'templates' 83 | 84 | # Prefix for tool commands 85 | COMMAND_PREFIX = 'sb' 86 | 87 | # Break lines at this column 88 | CSS_LINE_BREAK = 0 89 | 90 | # Project template to clone 91 | PROJECT_TEMPLATE = 'default' 92 | 93 | # Closure compiler compilation level 94 | COMPILATION_LEVEL = 'ADVANCED_OPTIMIZATIONS' 95 | 96 | # Closure / YUI Warning level 97 | WARNING_LEVEL = 'VERBOSE' 98 | 99 | # Additional Closure Compiler arguments 100 | COMPILER_ARGS = '' 101 | 102 | # Pattern for junk files to remove from deploy. 103 | REMOVE = '' 104 | 105 | # -------------------------------------------------- 106 | # 107 | # Sets arguments from config file (if found) and 108 | # extends them with any command line arguments 109 | # 110 | # -------------------------------------------------- 111 | 112 | def init(arguments): 113 | 114 | # Load custom config file if specified 115 | 116 | try: 117 | 118 | options, more = getopt.getopt(arguments, 'c:s:d:t:', ['config=', 'source=', 'deploy=', 'template=']) 119 | 120 | for option, value in options: 121 | 122 | if option in ('-c', '--config'): 123 | 124 | Config.CONFIG_PATH = os.path.join(os.getcwd(), value) 125 | 126 | except getopt.GetoptError, error: 127 | 128 | console.info(str(error)) 129 | 130 | # Override default options with loaded config 131 | 132 | if os.path.exists(Config.CONFIG_PATH): 133 | 134 | lines = open(Config.CONFIG_PATH, 'r') 135 | 136 | for line in lines: 137 | 138 | result = RegEx.CONFIG_OPTION.search(line) 139 | 140 | if result: 141 | 142 | setattr(Config, result.group(1), result.group(2)) 143 | 144 | # Override loaded options with command line arguments 145 | 146 | for option, value in options: 147 | 148 | if option in ('-s', '--source'): 149 | 150 | Config.SOURCE_PATH = value 151 | 152 | if option in ('-d', '--deploy'): 153 | 154 | Config.DEPLOY_PATH = value 155 | 156 | if option in ('-t', '--template'): 157 | 158 | Config.PROJECT_TEMPLATE = value 159 | 160 | # -------------------------------------------------- 161 | # 162 | # Define API 163 | # 164 | # -------------------------------------------------- 165 | 166 | init = staticmethod(init) 167 | 168 | 169 | # -------------------------------------------------- 170 | # 171 | # Regular Expressions 172 | # 173 | # -------------------------------------------------- 174 | 175 | class RegEx(): 176 | 177 | # -------------------------------------------------- 178 | # 179 | # Compiles all available regular expressions 180 | # 181 | # -------------------------------------------------- 182 | 183 | def compile(): 184 | 185 | # Files to parse for blocks during build 186 | RegEx.BUILD_TYPES = re.compile('\.(html|html|js|php)$') 187 | 188 | # Matches options in the config file 189 | RegEx.CONFIG_OPTION = re.compile('([^\=\s]+)\s+\=\s+(.+)') 190 | 191 | # Matches an embedded / linked file pattern 192 | RegEx.LINKED_FILE = re.compile('([\w\/\-\.]+\.\w{2,4})') 193 | 194 | # The start of a task block 195 | RegEx.BLOCK_START = re.compile('\W+%s:\s+(%s|show|hide)(\s+([\w\/\-\.]+\.\w{2,4}))?' % (Config.COMMAND_PREFIX, r'|'.join(Tools.API))) 196 | 197 | # The end of a task block 198 | RegEx.BLOCK_END = re.compile('^%s|\W+%s:\s+end' % (Config.COMMAND_PREFIX, Config.COMMAND_PREFIX)) 199 | 200 | # -------------------------------------------------- 201 | # 202 | # Define API 203 | # 204 | # -------------------------------------------------- 205 | 206 | compile = staticmethod(compile) 207 | 208 | 209 | # -------------------------------------------------- 210 | # 211 | # Utils 212 | # 213 | # -------------------------------------------------- 214 | 215 | class Utils(): 216 | 217 | # -------------------------------------------------- 218 | # 219 | # Formats and prints an action which operates on 220 | # input files to produce one output file 221 | # 222 | # -------------------------------------------------- 223 | 224 | def logAction(action, files, output): 225 | 226 | files = Utils.normalisePaths(files, Config.SOURCE_PATH) 227 | output = os.path.basename(output) 228 | console.info('%s:\t%s\n\t\t--> %s\n' % (action, files, output)) 229 | 230 | # -------------------------------------------------- 231 | # 232 | # Calls a method on a class using a string 233 | # representation of the method and returns whether 234 | # or not the call was successful 235 | # 236 | # -------------------------------------------------- 237 | 238 | def callMethod(owner, name, *args): 239 | 240 | method = None 241 | 242 | try: 243 | 244 | method = getattr(owner, name) 245 | 246 | except AttributeError: 247 | 248 | console.error('%s has no method "%s"' % (owner, name)) 249 | return False 250 | 251 | # If method exists and is a function 252 | if method and hasattr(method, '__call__'): 253 | 254 | method(*args) 255 | 256 | return True 257 | 258 | # -------------------------------------------------- 259 | # 260 | # Generator to recursively finds files whose 261 | # extension matches a certain pattern regex 262 | # 263 | # -------------------------------------------------- 264 | 265 | def findFiles(directory, pattern): 266 | 267 | for root, dirs, files in os.walk(directory): 268 | 269 | for basename in files: 270 | 271 | if pattern.search(basename): 272 | 273 | filename = os.path.join(root, basename) 274 | 275 | yield filename 276 | 277 | # -------------------------------------------------- 278 | # 279 | # Returns a list of paths, normalised to their own 280 | # directory or a specified base path 281 | # 282 | # -------------------------------------------------- 283 | 284 | def normalisePaths(paths, base=None): 285 | 286 | result = [] 287 | 288 | for path in paths: 289 | 290 | if base: 291 | 292 | result.append(re.sub('^/|/$', '', path.replace(base, ''))) 293 | 294 | else: 295 | 296 | result.append(os.path.basename(path)) 297 | 298 | return r', '.join(result) 299 | 300 | # -------------------------------------------------- 301 | # 302 | # Recursively copies files from one location to 303 | # another with optional include or exclude patterns 304 | # 305 | # -------------------------------------------------- 306 | 307 | def copyTree(source, target, includes=[], excludes=[]): 308 | 309 | # Always exclude these file types 310 | excludes.append('.DS_Store') 311 | 312 | # transform glob patterns to regular expressions 313 | includes = r'|'.join([fnmatch.translate(x) for x in includes]) 314 | excludes = r'|'.join([fnmatch.translate(x) for x in excludes]) or r'$.' 315 | 316 | for root, dirs, files in os.walk(source): 317 | 318 | # exclude directories matching exclude patterns 319 | dirs[:] = [os.path.join(root, d) for d in dirs] 320 | dirs[:] = [d for d in dirs if not re.match(excludes, os.path.basename(d))] 321 | 322 | # exclude / include files 323 | files = [os.path.join(root, f) for f in files] 324 | files = [f for f in files if not re.match(excludes, os.path.basename(f))] 325 | files = [f for f in files if re.match(includes, os.path.basename(f))] 326 | 327 | # Merge paths and copy 328 | for fname in files: 329 | 330 | # Find relative paths in target 331 | fpath = os.path.join(target, os.path.relpath(fname, source)) 332 | dpath = os.path.dirname(fpath) 333 | 334 | # Create directory structure if required 335 | if not os.path.exists(dpath): 336 | os.makedirs(dpath) 337 | 338 | # Copy the file 339 | copy(fname, fpath) 340 | 341 | # -------------------------------------------------- 342 | # 343 | # Define API 344 | # 345 | # -------------------------------------------------- 346 | 347 | normalisePaths = staticmethod(normalisePaths) 348 | callMethod = staticmethod(callMethod) 349 | findFiles = staticmethod(findFiles) 350 | logAction = staticmethod(logAction) 351 | copyTree = staticmethod(copyTree) 352 | 353 | 354 | # -------------------------------------------------- 355 | # 356 | # Tools 357 | # 358 | # -------------------------------------------------- 359 | 360 | class Tools(): 361 | 362 | # List of available method names 363 | API = ['concat', 'minify', 'compile'] 364 | 365 | # -------------------------------------------------- 366 | # 367 | # Concatenates a list of files into a single output 368 | # 369 | # -------------------------------------------------- 370 | 371 | def concat(paths, output): 372 | 373 | Utils.logAction('Concatenating', paths, output) 374 | 375 | # Open the destination file 376 | merged = open(output, 'wb') 377 | 378 | # Loop through all target files 379 | for path in paths: 380 | 381 | # Write the file contents into destination 382 | copyfileobj(open(path, 'rb'), merged) 383 | merged.write('\n') 384 | 385 | # Close the merged file 386 | merged.close() 387 | 388 | # -------------------------------------------------- 389 | # 390 | # Minifies a list of files into a single output 391 | # using YUI Compressor 392 | # 393 | # -------------------------------------------------- 394 | 395 | def minify(paths, output): 396 | 397 | Utils.logAction('Minifying', paths, output) 398 | 399 | # Loop through all target files 400 | for path in paths: 401 | 402 | # Pipe file into output and minify 403 | process = subprocess.Popen('java -jar %s --type css --line-break %s %s >> %s' % ( 404 | Config.PATH_COMPRESSOR, 405 | Config.CSS_LINE_BREAK, 406 | path, 407 | output 408 | ), shell=True) 409 | 410 | # Show output 411 | process.communicate() 412 | 413 | # -------------------------------------------------- 414 | # 415 | # Compiles a list of files into a single output 416 | # using Google Closure Compiler 417 | # 418 | # -------------------------------------------------- 419 | 420 | def compile(paths, output): 421 | 422 | Utils.logAction('Compiling', paths, output) 423 | 424 | # Formatted list 425 | scripts = ' --js '.join(paths) 426 | 427 | # Construct arguments 428 | options = [ 429 | 'java', 430 | '-jar', Config.PATH_COMPILER, 431 | '--js', scripts, 432 | '--js_output_file', output, 433 | '--compilation_level', Config.COMPILATION_LEVEL, 434 | '--warning_level', Config.WARNING_LEVEL, 435 | Config.COMPILER_ARGS 436 | ] 437 | 438 | # Add externs if specified 439 | if Config.EXTERNS_FILES: 440 | 441 | for extern in Config.EXTERNS_FILES.split(','): 442 | 443 | options += ['--externs', os.path.join(Config.SOURCE_PATH, extern)] 444 | 445 | # Tell Closure Compiler to process all scripts 446 | process = subprocess.Popen(' '.join(options), shell=True) 447 | 448 | # Show output 449 | process.communicate() 450 | 451 | # -------------------------------------------------- 452 | # 453 | # Define API 454 | # 455 | # -------------------------------------------------- 456 | 457 | concat = staticmethod(concat) 458 | minify = staticmethod(minify) 459 | compile = staticmethod(compile) 460 | 461 | 462 | # -------------------------------------------------- 463 | # 464 | # Springboard 465 | # 466 | # -------------------------------------------------- 467 | 468 | class Springboard(): 469 | 470 | LOGO = ''' 471 | ___ _ _ _ 472 | / __|_ __ _ _(_)_ _ __ _| |__ ___ __ _ _ _ __| | 473 | \__ \ '_ \ '_| | ' \/ _` | '_ \/ _ \/ _` | '_/ _` | 474 | |___/ .__/_| |_|_||_\__, |_.__/\___/\__,_|_| \__,_| 475 | |_| |___/ 476 | ''' 477 | 478 | HELP = LOGO + ''' 479 | Usage: 480 | 481 | $ sb command [options] 482 | 483 | Commands: 484 | 485 | install Installs Springboard and command line aliases 486 | config Opens the project templates directory for customising 487 | init Initialises a project in the current directory (copies in template files) 488 | -t, --template The name of the template to use (optional) (Defaults to 'default') 489 | build Builds the current project 490 | -c, --config Springboard config path (optional) (Defaults to '.sbconfig') 491 | -s, --source Project source location (optional) (Defaults to 'source') 492 | -d, --deploy Project output location (optional) (Defaults to 'deploy') 493 | help Displays help 494 | ''' 495 | 496 | # -------------------------------------------------- 497 | # 498 | # Outputs the help documentation for Springboard 499 | # 500 | # -------------------------------------------------- 501 | 502 | def help(): 503 | 504 | console.info(Springboard.HELP) 505 | 506 | # -------------------------------------------------- 507 | # 508 | # Installs Springboard & create command line aliases 509 | # 510 | # -------------------------------------------------- 511 | 512 | def install(): 513 | 514 | console.info(Springboard.LOGO) 515 | console.info('Installing Springboard to "%s"...' % Config.SPRINGBOARD_HOME) 516 | 517 | # Try to detect subsequent installs 518 | firstInstall = True 519 | 520 | # Output messages 521 | messages = [] 522 | 523 | # Install from here 524 | source = os.getcwd() 525 | 526 | # Path to installed script (assumes same name as current script) 527 | script = os.path.join(Config.SPRINGBOARD_HOME, os.path.basename(__file__)) 528 | 529 | # Copy Springboard files 530 | if os.path.exists(os.path.join(Config.SPRINGBOARD_HOME, Config.TEMPLATE_PATH)): 531 | 532 | # Copy files but ignore existing templates 533 | Utils.copyTree(source, Config.SPRINGBOARD_HOME, [], [Config.TEMPLATE_PATH, '.git']) 534 | 535 | # Not the first install if templates exist 536 | firstInstall = False 537 | 538 | else: 539 | 540 | # Copy all files and templates 541 | Utils.copyTree(source, Config.SPRINGBOARD_HOME, [], ['.git']) 542 | 543 | # For Mac, add alias to BASH profile 544 | if Config.OS == 'mac': 545 | 546 | # Make script executable 547 | subprocess.call(['chmod', 'a+x', script]) 548 | 549 | # Path top bash_profile 550 | bash = os.path.join(Config.USER_HOME, '.bash_profile') 551 | 552 | if not os.path.exists(bash): 553 | doc = open(bash, 'w+') 554 | doc.close() 555 | 556 | if os.path.exists(bash): 557 | 558 | # Read the current contents 559 | doc = open(bash, 'r') 560 | txt = doc.read() 561 | doc.close() 562 | 563 | # Check for existing aliases 564 | if not re.compile(r'alias (sb|springboard)').search(txt): 565 | 566 | console.info('Adding aliases (%s, %s) to "%s"' % ('springboard', 'sb', bash)) 567 | 568 | # Create bash session aliases 569 | subprocess.call(['alias', 'springboard=%s' % script]) 570 | subprocess.call(['alias', 'sb=%s' % script]) 571 | 572 | # Add Springboard aliases 573 | doc = open(bash, 'a') 574 | doc.write('\n# Springboard') 575 | doc.write('\nalias springboard="%s"' % script) 576 | doc.write('\nalias sb="%s"' % script) 577 | doc.write('\nexport SPRINGBOARD_HOME="%s"' % Config.SPRINGBOARD_HOME) 578 | doc.write('\nexport PATH=$PATH:$SPRINGBOARD_HOME') 579 | doc.close() 580 | 581 | # Aliases availbale in new BASH session 582 | messages.append('Start a new BASH session to start using Springboard :)') 583 | 584 | elif Config.OS == 'win': 585 | 586 | console.info('Install for windows') 587 | # subprocess.call(['setx', 'sb', script]) 588 | # Write a bat file to run Springboard 589 | # Add to PATH variable 590 | 591 | # Print status 592 | for message in ['', 'Springboard successful installed!'] + messages + ['']: 593 | console.info('\t%s' % message) 594 | 595 | # Open the default template in a browser. 596 | if firstInstall: 597 | target = os.path.join(Config.SPRINGBOARD_HOME, Config.TEMPLATE_PATH, 'default', 'source', 'index.html') 598 | webbrowser.open('file://' + target) 599 | 600 | # -------------------------------------------------- 601 | # 602 | # 603 | # 604 | # 605 | # -------------------------------------------------- 606 | 607 | def config(): 608 | target = os.path.join(Config.SPRINGBOARD_HOME, Config.TEMPLATE_PATH) 609 | subprocess.call(["open", "-R", target]) 610 | 611 | # -------------------------------------------------- 612 | # 613 | # Initialises a Springboard project in the current 614 | # directory using a given template if specified 615 | # 616 | # -------------------------------------------------- 617 | 618 | def init(): 619 | 620 | console.info('\nSpringboard >> init\n') 621 | 622 | # Determine paths 623 | root = os.path.join(Config.SPRINGBOARD_HOME, Config.TEMPLATE_PATH) 624 | path = os.path.join(root, Config.PROJECT_TEMPLATE) 625 | dest = os.getcwd() 626 | 627 | # If the template exists 628 | if os.path.exists(path): 629 | 630 | # Clone template into the current working directory 631 | console.info('Cloning template "%s" into "%s"' % (Config.PROJECT_TEMPLATE, dest)) 632 | Utils.copyTree(path, dest) 633 | console.info('Ok, start coding! :)') 634 | 635 | else: 636 | 637 | # If there's no tempate matching the specified name 638 | console.info('Cannot find template "%s" in "%s"' % (Config.PROJECT_TEMPLATE, root)) 639 | 640 | # -------------------------------------------------- 641 | # 642 | # Builds the current project 643 | # 644 | # -------------------------------------------------- 645 | 646 | def build(): 647 | 648 | console.info('\nSpringboard >> build\n') 649 | 650 | # Return if source path doesn't exist 651 | if not os.path.exists(Config.SOURCE_PATH): 652 | 653 | console.info('Source directory "%s" not found in "%s"' % (Config.SOURCE_PATH, os.getcwd())) 654 | return 655 | 656 | # Create / empty deploy directory 657 | if not os.path.exists(Config.DEPLOY_PATH): 658 | 659 | os.makedirs(Config.DEPLOY_PATH) 660 | 661 | # Files for processing 662 | stack = {} 663 | 664 | # Process queue 665 | queue = [] 666 | 667 | # Current output path 668 | output = None 669 | 670 | # Current task 671 | process = None 672 | 673 | # If we're stacking files 674 | stacking = False 675 | 676 | # Processed files 677 | processed = [] 678 | 679 | # Redundant files 680 | redundancies = [] 681 | 682 | # Format to embed resources 683 | embed_format = None 684 | 685 | # Remove current output 686 | rmtree(Config.DEPLOY_PATH) 687 | 688 | # Copy all files to deploy 689 | copytree(Config.SOURCE_PATH, Config.DEPLOY_PATH, ignore=ignore_patterns('*.svn', '.DS_Store')) 690 | 691 | # Parse each target marked for building 692 | for target in Utils.findFiles(Config.DEPLOY_PATH, RegEx.BUILD_TYPES): 693 | 694 | # Current line number 695 | line_num = 0 696 | 697 | # Current block start line 698 | open_line_num = 0 699 | 700 | # Step through the file 701 | for line in fileinput.input(target, inplace=1): 702 | 703 | line_num += 1 704 | 705 | # Are we collecting files? 706 | if stacking: 707 | 708 | # Check for an ending block 709 | if RegEx.BLOCK_END.match(line): 710 | 711 | stacking = False 712 | 713 | # Create process if output is specified 714 | if output: 715 | 716 | # Use the last embed code as a template to link the output 717 | embed = re.sub(RegEx.LINKED_FILE, output, embed_format) 718 | 719 | # Get the list of inputs 720 | files = stack[output] 721 | 722 | # Map output to the deploy directory 723 | output = Config.DEPLOY_PATH + '/' + output 724 | 725 | # If the block isn't empty 726 | if files: 727 | 728 | # Write in the embed tag after any indentation 729 | sys.stdout.write(embed) 730 | 731 | # For targets that haven't been processed 732 | if not output in processed: 733 | 734 | if files: 735 | 736 | if process in Tools.API: 737 | 738 | # Queue this block for processing 739 | queue.append({ 740 | 'process': process, 741 | 'output': output, 742 | 'files': files 743 | }) 744 | 745 | # Mark this target processed 746 | processed.append(output) 747 | else: 748 | 749 | # Warn about empty blocks 750 | console.info('Empty %s block found in "%s" on line %s' % (process, target, open_line_num)) 751 | 752 | else: 753 | 754 | if process == 'show': 755 | 756 | # Write the line back in 757 | sys.stdout.write(line) 758 | 759 | elif output: 760 | 761 | # Extract path from linked resource 762 | path = RegEx.LINKED_FILE.search(line) 763 | 764 | if path: 765 | 766 | # This line is now the embed template 767 | embed_format = line 768 | 769 | if path: 770 | 771 | # Remap the path to deploy directory 772 | path_deploy = Config.DEPLOY_PATH + '/' + path.group(1) 773 | 774 | # Store the path in this blocks list 775 | stack[output].append(path_deploy) 776 | 777 | # Remove processed files after build 778 | if not path_deploy in redundancies: 779 | 780 | redundancies.append(path_deploy) 781 | 782 | else: 783 | 784 | # Does a block start on this line 785 | block_open = RegEx.BLOCK_START.match(line) 786 | 787 | if block_open: 788 | 789 | # Store the current line number 790 | open_line_num = line_num 791 | 792 | # The process to perform in this file list 793 | process = block_open.group(1) 794 | 795 | if block_open.group(3): 796 | 797 | # The path of the output 798 | output = block_open.group(3) 799 | 800 | # Trim whitespace 801 | output = output.strip() 802 | 803 | else: 804 | 805 | output = None 806 | 807 | # We haven't processed this file yet, so collect it's contents 808 | stacking = True 809 | 810 | # Create a new list of collected files 811 | stack[output] = [] 812 | 813 | else: 814 | 815 | # Keep line content unmodified 816 | sys.stdout.write(line) 817 | 818 | fileinput.close() 819 | 820 | # Execute all queued tasks 821 | for item in queue: 822 | 823 | Utils.callMethod(Tools, item['process'], item['files'], item['output']) 824 | 825 | # Delete redundant files 826 | for path in redundancies: 827 | 828 | if not path in processed: 829 | 830 | if os.path.exists(path): 831 | 832 | os.remove(path) 833 | 834 | # Remove files matching a certain pattern 835 | for target in Utils.findFiles(Config.DEPLOY_PATH, re.compile(Config.REMOVE)): 836 | 837 | os.remove(target) 838 | 839 | # Delete externs 840 | if Config.EXTERNS_FILES: 841 | 842 | for extern in Config.EXTERNS_FILES.split(','): 843 | 844 | extern = os.path.join(Config.DEPLOY_PATH, extern) 845 | 846 | if os.path.exists(extern): 847 | 848 | os.remove(extern) 849 | 850 | # Remove empty directories, deepest first 851 | for path, dirs, files in os.walk(Config.DEPLOY_PATH, topdown=False): 852 | 853 | # If there are no files or directories 854 | if len(dirs) < 1 and len(files) < 1: 855 | 856 | # Remove it 857 | os.rmdir(path) 858 | 859 | console.info('\nBuild complete!\n') 860 | 861 | # -------------------------------------------------- 862 | # 863 | # Define API 864 | # 865 | # -------------------------------------------------- 866 | 867 | install = staticmethod(install) 868 | config = staticmethod(config) 869 | build = staticmethod(build) 870 | init = staticmethod(init) 871 | help = staticmethod(help) 872 | 873 | # -------------------------------------------------- 874 | # 875 | # Start 876 | # 877 | # -------------------------------------------------- 878 | 879 | # Compile regex 880 | RegEx.compile() 881 | 882 | # Setup a console 883 | console = logging.getLogger() 884 | channel = logging.StreamHandler() 885 | 886 | console.setLevel(logging.DEBUG) 887 | console.addHandler(channel) 888 | 889 | # Grab command line arguments 890 | arguments = sys.argv[1:] 891 | 892 | if len(arguments) >= 1: 893 | 894 | # Method is first argument 895 | task = arguments[0].lower() 896 | 897 | # Configure with remaining args 898 | Config.init(arguments[1:]) 899 | 900 | # Call Springboard task, if it exists 901 | if not Utils.callMethod(Springboard, task): 902 | 903 | # If call fails, show help 904 | Springboard.help() 905 | 906 | else: 907 | 908 | # Show help if no arguments were provided 909 | Springboard.help() 910 | -------------------------------------------------------------------------------- /templates/default/.sbconfig: -------------------------------------------------------------------------------- 1 | # Project source path 2 | SOURCE_PATH = source 3 | 4 | # Project output path 5 | DEPLOY_PATH = deploy 6 | 7 | # Break line at this column (0 breaks after each rule) 8 | CSS_LINE_BREAK = 0 9 | 10 | # Externs file for Closure compiler 11 | EXTERNS_FILES = js/externs.js 12 | 13 | # Closure compiler compilation level 14 | COMPILATION_LEVEL = ADVANCED_OPTIMIZATIONS 15 | 16 | # Closure compiler warning level 17 | WARNING_LEVEL = VERBOSE 18 | 19 | # Any additional arguments 20 | COMPILER_ARGS = '--debug' 21 | 22 | # Regex for files to remove 23 | REMOVE = \.less$ -------------------------------------------------------------------------------- /templates/default/deploy/css/styles.min.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css 2011-09-22T17:42 UTC - http://github.com/necolas/normalize.css */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block} 2 | audio,canvas,video{display:inline-block;*display:inline;*zoom:1} 3 | audio:not([controls]){display:none} 4 | [hidden]{display:none} 5 | html{font-size:100%;overflow-y:scroll;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%} 6 | body{margin:0} 7 | body,button,input,select,textarea{font-family:sans-serif} 8 | a{color:#00e} 9 | a:visited{color:#551a8b} 10 | a:focus{outline:thin dotted} 11 | a:hover,a:active{outline:0} 12 | abbr[title]{border-bottom:1px dotted} 13 | b,strong{font-weight:bold} 14 | blockquote{margin:1em 40px} 15 | dfn{font-style:italic} 16 | mark{background:#ff0;color:#000} 17 | pre,code,kbd,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em} 18 | pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word} 19 | q{quotes:none} 20 | q:before,q:after{content:'';content:none} 21 | small{font-size:75%} 22 | sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} 23 | sup{top:-0.5em} 24 | sub{bottom:-0.25em} 25 | ul,ol{margin:1em 0;padding:0 0 0 40px} 26 | dd{margin:0 0 0 40px} 27 | nav ul,nav ol{list-style:none;list-style-image:none} 28 | img{border:0;-ms-interpolation-mode:bicubic} 29 | svg:not(:root){overflow:hidden} 30 | figure{margin:0} 31 | form{margin:0} 32 | fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em} 33 | legend{border:0;*margin-left:-7px} 34 | button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle} 35 | button,input{line-height:normal} 36 | button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;*overflow:visible} 37 | input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0} 38 | input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box} 39 | input[type="search"]::-webkit-search-decoration{-webkit-appearance:none} 40 | button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} 41 | textarea{overflow:auto;vertical-align:top} 42 | table{border-collapse:collapse;border-spacing:0}html,body{background:#1b1b1b;font-family:"Courier New",Courier,monospace;font-size:13px;line-height:1.4} 43 | #container{margin:100px auto 0 auto;color:#DDD;width:620px} 44 | #container h1{color:#FFF;margin:25px 0;font-size:24px;font-weight:300} 45 | #container h2{color:#FFF;margin:25px 0;font-size:18px;font-weight:300} 46 | #container strong{font-style:italic} 47 | #container pre{border:1px solid #333;background:#222;margin:20px 0;padding:15px;color:#a9da88} 48 | #container a{text-decoration:none;color:#fe4365} 49 | #container a:hover{text-decoration:underline} -------------------------------------------------------------------------------- /templates/default/deploy/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Welcome to Springboard! 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |

Welcome to Springboard!

17 |

Springboard is installed to:

18 |

19 | 			

This is the default Springboard template, which you should now edit to suit your needs. You can also create new templates simply by adding them to the templates directory and then use them like so:

20 |
$ cd /YourWorkspace/NewProject/
21 | $ sb init template-name
22 |

To access the templates directory, just run the config command:

23 |
$ sb config
24 |

For more information, please refer to the README file in the repo: https://github.com/soulwire/Springboard

25 |

Note

26 |

The following message is set via JavaScript and will be true in the project source directory but false in deploy. This utilises Springboard's ability to show or hide blocks of code during the build process, useful in this instance for toggling a DEBUG flag automatically…

27 |

28 | 		
29 | 30 | 33 | 34 | 35 | 36 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /templates/default/deploy/js/libs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Just an empty file. 3 | */ 4 | 5 | /** 6 | * Detect the location of Springboard based on 7 | * the default template path. 8 | */ 9 | 10 | parts = window.location.pathname.split('/'); 11 | parts.splice(parts.indexOf('templates')); 12 | 13 | items = document.getElementsByClassName('sbpath'); 14 | 15 | SB_PATH = parts.join('/'); 16 | 17 | for (var i = 0, n = items.length; i < n; i++) { 18 | items[i].innerHTML = SB_PATH; 19 | } 20 | -------------------------------------------------------------------------------- /templates/default/deploy/js/scripts.js: -------------------------------------------------------------------------------- 1 | document.getElementById("message").innerHTML="Debug = ${DEBUG};".replace(/\${DEBUG}/g,!1); 2 | -------------------------------------------------------------------------------- /templates/default/source/css/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css 2011-09-22T17:42 UTC - http://github.com/necolas/normalize.css */ 2 | 3 | /* ============================================================================= 4 | HTML5 display definitions 5 | ========================================================================== */ 6 | 7 | /* 8 | * Corrects block display not defined in IE6/7/8/9 & FF3 9 | */ 10 | 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | hgroup, 19 | nav, 20 | section { 21 | display: block; 22 | } 23 | 24 | /* 25 | * Corrects inline-block display not defined in IE6/7/8/9 & FF3 26 | */ 27 | 28 | audio, 29 | canvas, 30 | video { 31 | display: inline-block; 32 | *display: inline; 33 | *zoom: 1; 34 | } 35 | 36 | /* 37 | * Prevents modern browsers from displaying 'audio' without controls 38 | */ 39 | 40 | audio:not([controls]) { 41 | display: none; 42 | } 43 | 44 | /* 45 | * Addresses styling for 'hidden' attribute not present in IE7/8/9, FF3, S4 46 | * Known issue: no IE6 support 47 | */ 48 | 49 | [hidden] { 50 | display: none; 51 | } 52 | 53 | 54 | /* ============================================================================= 55 | Base 56 | ========================================================================== */ 57 | 58 | /* 59 | * 1. Corrects text resizing oddly in IE6/7 when body font-size is set using em units 60 | * http://clagnut.com/blog/348/#c790 61 | * 2. Keeps page centred in all browsers regardless of content height 62 | * 3. Prevents iOS text size adjust after orientation change, without disabling user zoom 63 | * www.456bereastreet.com/archive/201012/controlling_text_size_in_safari_for_ios_without_disabling_user_zoom/ 64 | */ 65 | 66 | html { 67 | font-size: 100%; /* 1 */ 68 | overflow-y: scroll; /* 2 */ 69 | -webkit-text-size-adjust: 100%; /* 3 */ 70 | -ms-text-size-adjust: 100%; /* 3 */ 71 | } 72 | 73 | /* 74 | * Addresses margins handled incorrectly in IE6/7 75 | */ 76 | 77 | body { 78 | margin: 0; 79 | } 80 | 81 | /* 82 | * Addresses font-family inconsistency between 'textarea' and other form elements. 83 | */ 84 | 85 | body, 86 | button, 87 | input, 88 | select, 89 | textarea { 90 | font-family: sans-serif; 91 | } 92 | 93 | 94 | /* ============================================================================= 95 | Links 96 | ========================================================================== */ 97 | 98 | a { 99 | color: #00e; 100 | } 101 | 102 | a:visited { 103 | color: #551a8b; 104 | } 105 | 106 | /* 107 | * Addresses outline displayed oddly in Chrome 108 | */ 109 | 110 | a:focus { 111 | outline: thin dotted; 112 | } 113 | 114 | /* 115 | * Improves readability when focused and also mouse hovered in all browsers 116 | * people.opera.com/patrickl/experiments/keyboard/test 117 | */ 118 | 119 | a:hover, 120 | a:active { 121 | outline: 0; 122 | } 123 | 124 | 125 | /* ============================================================================= 126 | Typography 127 | ========================================================================== */ 128 | 129 | /* 130 | * Addresses styling not present in IE7/8/9, S5, Chrome 131 | */ 132 | 133 | abbr[title] { 134 | border-bottom: 1px dotted; 135 | } 136 | 137 | /* 138 | * Addresses style set to 'bolder' in FF3/4, S4/5, Chrome 139 | */ 140 | 141 | b, 142 | strong { 143 | font-weight: bold; 144 | } 145 | 146 | blockquote { 147 | margin: 1em 40px; 148 | } 149 | 150 | /* 151 | * Addresses styling not present in S5, Chrome 152 | */ 153 | 154 | dfn { 155 | font-style: italic; 156 | } 157 | 158 | /* 159 | * Addresses styling not present in IE6/7/8/9 160 | */ 161 | 162 | mark { 163 | background: #ff0; 164 | color: #000; 165 | } 166 | 167 | /* 168 | * Corrects font family set oddly in IE6, S4/5, Chrome 169 | * en.wikipedia.org/wiki/User:Davidgothberg/Test59 170 | */ 171 | 172 | pre, 173 | code, 174 | kbd, 175 | samp { 176 | font-family: monospace, serif; 177 | _font-family: 'courier new', monospace; 178 | font-size: 1em; 179 | } 180 | 181 | /* 182 | * Improves readability of pre-formatted text in all browsers 183 | */ 184 | 185 | pre { 186 | white-space: pre; 187 | white-space: pre-wrap; 188 | word-wrap: break-word; 189 | } 190 | 191 | /* 192 | * 1. Addresses CSS quotes not supported in IE6/7 193 | * 2. Addresses quote property not supported in S4 194 | */ 195 | 196 | /* 1 */ 197 | 198 | q { 199 | quotes: none; 200 | } 201 | 202 | /* 2 */ 203 | 204 | q:before, 205 | q:after { 206 | content: ''; 207 | content: none; 208 | } 209 | 210 | small { 211 | font-size: 75%; 212 | } 213 | 214 | /* 215 | * Prevents sub and sup affecting line-height in all browsers 216 | * gist.github.com/413930 217 | */ 218 | 219 | sub, 220 | sup { 221 | font-size: 75%; 222 | line-height: 0; 223 | position: relative; 224 | vertical-align: baseline; 225 | } 226 | 227 | sup { 228 | top: -0.5em; 229 | } 230 | 231 | sub { 232 | bottom: -0.25em; 233 | } 234 | 235 | 236 | /* ============================================================================= 237 | Lists 238 | ========================================================================== */ 239 | 240 | ul, 241 | ol { 242 | margin: 1em 0; 243 | padding: 0 0 0 40px; 244 | } 245 | 246 | dd { 247 | margin: 0 0 0 40px; 248 | } 249 | 250 | nav ul, 251 | nav ol { 252 | list-style: none; 253 | list-style-image: none; 254 | } 255 | 256 | 257 | /* ============================================================================= 258 | Embedded content 259 | ========================================================================== */ 260 | 261 | /* 262 | * 1. Removes border when inside 'a' element in IE6/7/8/9, FF3 263 | * 2. Improves image quality when scaled in IE7 264 | * code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ 265 | */ 266 | 267 | img { 268 | border: 0; /* 1 */ 269 | -ms-interpolation-mode: bicubic; /* 2 */ 270 | } 271 | 272 | /* 273 | * Corrects overflow displayed oddly in IE9 274 | */ 275 | 276 | svg:not(:root) { 277 | overflow: hidden; 278 | } 279 | 280 | 281 | /* ============================================================================= 282 | Figures 283 | ========================================================================== */ 284 | 285 | /* 286 | * Addresses margin not present in IE6/7/8/9, S5, O11 287 | */ 288 | 289 | figure { 290 | margin: 0; 291 | } 292 | 293 | 294 | /* ============================================================================= 295 | Forms 296 | ========================================================================== */ 297 | 298 | /* 299 | * Corrects margin displayed oddly in IE6/7 300 | */ 301 | 302 | form { 303 | margin: 0; 304 | } 305 | 306 | /* 307 | * Define consistent border, margin, and padding 308 | */ 309 | 310 | fieldset { 311 | border: 1px solid #c0c0c0; 312 | margin: 0 2px; 313 | padding: 0.35em 0.625em 0.75em; 314 | } 315 | 316 | /* 317 | * 1. Corrects color not being inherited in IE6/7/8/9 318 | * 2. Corrects alignment displayed oddly in IE6/7 319 | */ 320 | 321 | legend { 322 | border: 0; /* 1 */ 323 | *margin-left: -7px; /* 2 */ 324 | } 325 | 326 | /* 327 | * 1. Corrects font size not being inherited in all browsers 328 | * 2. Addresses margins set differently in IE6/7, FF3/4, S5, Chrome 329 | * 3. Improves appearance and consistency in all browsers 330 | */ 331 | 332 | button, 333 | input, 334 | select, 335 | textarea { 336 | font-size: 100%; /* 1 */ 337 | margin: 0; /* 2 */ 338 | vertical-align: baseline; /* 3 */ 339 | *vertical-align: middle; /* 3 */ 340 | } 341 | 342 | /* 343 | * Addresses FF3/4 setting line-height on 'input' using !important in the UA stylesheet 344 | */ 345 | 346 | button, 347 | input { 348 | line-height: normal; /* 1 */ 349 | } 350 | 351 | /* 352 | * 1. Improves usability and consistency of cursor style between image-type 'input' and others 353 | * 2. Corrects inability to style clickable 'input' types in iOS 354 | * 3. Corrects inner spacing displayed oddly in IE7 without effecting normal text inputs 355 | * Known issue: inner spacing remains in IE6 356 | */ 357 | 358 | button, 359 | input[type="button"], 360 | input[type="reset"], 361 | input[type="submit"] { 362 | cursor: pointer; /* 1 */ 363 | -webkit-appearance: button; /* 2 */ 364 | *overflow: visible; /* 3 */ 365 | } 366 | 367 | /* 368 | * 1. Addresses box sizing set to content-box in IE8/9 369 | * 2. Addresses excess padding in IE8/9 370 | */ 371 | 372 | input[type="checkbox"], 373 | input[type="radio"] { 374 | box-sizing: border-box; /* 1 */ 375 | padding: 0; /* 2 */ 376 | } 377 | 378 | /* 379 | * 1. Addresses appearance set to searchfield in S5, Chrome 380 | * 2. Addresses box sizing set to border-box in S5, Chrome (include -moz to future-proof) 381 | */ 382 | 383 | input[type="search"] { 384 | -webkit-appearance: textfield; /* 1 */ 385 | -moz-box-sizing: content-box; 386 | -webkit-box-sizing: content-box; /* 2 */ 387 | box-sizing: content-box; 388 | } 389 | 390 | /* 391 | * Corrects inner padding displayed oddly in S5, Chrome on OSX 392 | */ 393 | 394 | input[type="search"]::-webkit-search-decoration { 395 | -webkit-appearance: none; 396 | } 397 | 398 | /* 399 | * Corrects inner padding and border displayed oddly in FF3/4 400 | * www.sitepen.com/blog/2008/05/14/the-devils-in-the-details-fixing-dojos-toolbar-buttons/ 401 | */ 402 | 403 | button::-moz-focus-inner, 404 | input::-moz-focus-inner { 405 | border: 0; 406 | padding: 0; 407 | } 408 | 409 | /* 410 | * 1. Removes default vertical scrollbar in IE6/7/8/9 411 | * 2. Improves readability and alignment in all browsers 412 | */ 413 | 414 | textarea { 415 | overflow: auto; /* 1 */ 416 | vertical-align: top; /* 2 */ 417 | } 418 | 419 | 420 | /* ============================================================================= 421 | Tables 422 | ========================================================================== */ 423 | 424 | /* 425 | * Remove most spacing between table cells 426 | */ 427 | 428 | table { 429 | border-collapse: collapse; 430 | border-spacing: 0; 431 | } 432 | -------------------------------------------------------------------------------- /templates/default/source/css/styles.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | background: #1b1b1b; 3 | font-family: "Courier New", Courier, monospace; 4 | font-size: 13px; 5 | line-height: 1.4; 6 | } 7 | 8 | #container { 9 | margin: 100px auto 0 auto; 10 | color: #DDD; 11 | width: 620px; 12 | } 13 | 14 | #container h1 { 15 | color: #FFF; 16 | margin: 25px 0; 17 | font-size: 24px; 18 | font-weight: 300; 19 | } 20 | 21 | #container h2 { 22 | color: #FFF; 23 | margin: 25px 0; 24 | font-size: 18px; 25 | font-weight: 300; 26 | } 27 | 28 | #container strong { 29 | font-style: italic; 30 | } 31 | 32 | #container pre { 33 | border: 1px solid #333; 34 | background: #222; 35 | margin: 20px 0; 36 | padding: 15px; 37 | color: #A9DA88; 38 | } 39 | 40 | #container a { 41 | text-decoration: none; 42 | color: #FE4365; 43 | } 44 | 45 | #container a:hover { 46 | text-decoration: underline; 47 | } -------------------------------------------------------------------------------- /templates/default/source/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Welcome to Springboard! 6 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |

Welcome to Springboard!

20 |

Springboard is installed to:

21 |

22 | 			

This is the default Springboard template, which you should now edit to suit your needs. You can also create new templates simply by adding them to the templates directory and then use them like so:

23 |
$ cd /YourWorkspace/NewProject/
24 | $ sb init template-name
25 |

To access the templates directory, just run the config command:

26 |
$ sb config
27 |

For more information, please refer to the README file in the repo: https://github.com/soulwire/Springboard

28 |

Note

29 |

The following message is set via JavaScript and will be true in the project source directory but false in deploy. This utilises Springboard's ability to show or hide blocks of code during the build process, useful in this instance for toggling a DEBUG flag automatically…

30 |

31 | 		
32 | 33 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /templates/default/source/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | 2 | var DEBUG = false; 3 | // sb: hide 4 | DEBUG = true; 5 | // sb: end 6 | 7 | Project.init(); -------------------------------------------------------------------------------- /templates/default/source/js/externs.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulwire/Springboard/5a50d523683c7d021fd80982d952cefa594cbeba/templates/default/source/js/externs.js -------------------------------------------------------------------------------- /templates/default/source/js/libs/empty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Just an empty file. 3 | */ -------------------------------------------------------------------------------- /templates/default/source/js/libs/sbpath.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Detect the location of Springboard based on 4 | * the default template path. 5 | */ 6 | 7 | parts = window.location.pathname.split('/'); 8 | parts.splice(parts.indexOf('templates')); 9 | 10 | items = document.getElementsByClassName('sbpath'); 11 | 12 | SB_PATH = parts.join('/'); 13 | 14 | for (var i = 0, n = items.length; i < n; i++) { 15 | items[i].innerHTML = SB_PATH; 16 | } -------------------------------------------------------------------------------- /templates/default/source/js/script.js: -------------------------------------------------------------------------------- 1 | var Project = (function() { 2 | 3 | var message = 'Debug = ${DEBUG};'; 4 | 5 | return { 6 | 7 | init: function() { 8 | 9 | var container = document.getElementById('message'); 10 | container.innerHTML = message.replace(/\${DEBUG}/g, DEBUG); 11 | } 12 | }; 13 | 14 | })(); -------------------------------------------------------------------------------- /tools/compiler.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulwire/Springboard/5a50d523683c7d021fd80982d952cefa594cbeba/tools/compiler.jar -------------------------------------------------------------------------------- /tools/compressor.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulwire/Springboard/5a50d523683c7d021fd80982d952cefa594cbeba/tools/compressor.jar --------------------------------------------------------------------------------