├── .DS_Store ├── README.md ├── framer-md-app.framer ├── ..social.html.icloud ├── ..viewer.html.icloud ├── .app.coffee.icloud ├── .gitignore ├── .gitignore 2 ├── .index.html.icloud ├── framer │ ├── ..framer.modules.js.hash.icloud │ ├── .bookmark │ ├── .bookmark 2 │ ├── .config.json.icloud │ ├── .design.vekter.icloud │ ├── .framer.js.map.icloud │ ├── .manifest.txt.icloud │ ├── .preview.png.icloud │ ├── .social-800x600.png.icloud │ ├── .social-80x80.png.icloud │ ├── .social-880x460.png.icloud │ ├── .style.css.icloud │ ├── coffee-script.js │ ├── config 2.json │ ├── design 2.vekter │ ├── framer 2.js │ ├── framer.generated.js │ ├── framer.init.js │ ├── framer.js │ ├── framer.modules.js │ ├── framer.vekter.js │ ├── images │ │ ├── cursor-active.png │ │ ├── cursor-active@2x.png │ │ ├── cursor.png │ │ ├── cursor@2x.png │ │ ├── icon-120.png │ │ ├── icon-152.png │ │ ├── icon-180.png │ │ ├── icon-192.png │ │ └── icon-76.png │ └── version ├── images │ ├── .gitkeep │ └── .gitkeep 2 └── modules │ ├── fmd.sublime-workspace │ ├── md-components │ ├── ActionButton.coffee │ ├── App.coffee │ ├── BottomNav.coffee │ ├── Button.coffee │ ├── Card.coffee │ ├── Checkbox.coffee │ ├── Dialog.coffee │ ├── Divider.coffee │ ├── Dropdown.coffee │ ├── Elevation.coffee │ ├── GridList.coffee │ ├── Header.coffee │ ├── Icon.coffee │ ├── Menu.coffee │ ├── MenuButton.coffee │ ├── MenuOverlay.coffee │ ├── Notification.coffee │ ├── Page.coffee │ ├── Radiobox.coffee │ ├── Ripple.coffee │ ├── RowItem.coffee │ ├── Select.coffee │ ├── Slider.coffee │ ├── Snackbar.coffee │ ├── StackView.coffee │ ├── StatusBar.coffee │ ├── Switch.coffee │ ├── Table.coffee │ ├── TableCard.coffee │ ├── TextArea.coffee │ ├── TextField.coffee │ ├── Theme.coffee │ ├── Tile.coffee │ ├── Toast.coffee │ ├── Type.coffee │ └── View.coffee │ ├── md-fonts │ ├── Apache License.txt │ ├── Roboto-Black.ttf │ ├── Roboto-BlackItalic.ttf │ ├── Roboto-Bold.ttf │ ├── Roboto-BoldItalic.ttf │ ├── Roboto-Italic.ttf │ ├── Roboto-Light.ttf │ ├── Roboto-LightItalic.ttf │ ├── Roboto-Medium.ttf │ ├── Roboto-MediumItalic.ttf │ ├── Roboto-Regular.ttf │ ├── Roboto-Thin.ttf │ └── Roboto-ThinItalic.ttf │ ├── md-images │ ├── Group.svg │ ├── keyboard.png │ ├── nav_bar.png │ ├── status_bar.png │ └── status_bar.svg │ └── md.coffee └── framer-md-dev.framer ├── ..social.html.icloud ├── ..viewer 2.html.icloud ├── .gitignore ├── app.coffee ├── framer ├── .bookmark ├── coffee-script.js ├── config.json ├── design.vekter ├── framer.generated.js ├── framer.init.js ├── framer.js ├── framer.js.map ├── framer.modules.js ├── framer.vekter.js ├── images │ ├── cursor-active.png │ ├── cursor-active@2x.png │ ├── cursor.png │ ├── cursor@2x.png │ ├── icon-120.png │ ├── icon-152.png │ ├── icon-180.png │ ├── icon-192.png │ └── icon-76.png ├── style.css └── version ├── images └── .gitkeep ├── index.html └── modules ├── fmd.sublime-workspace ├── md-components ├── ActionButton.coffee ├── App.coffee ├── BottomNav.coffee ├── Button.coffee ├── Card.coffee ├── Checkbox.coffee ├── Dialog.coffee ├── Divider.coffee ├── Dropdown.coffee ├── Elevation.coffee ├── GridList.coffee ├── Header.coffee ├── Icon.coffee ├── Menu.coffee ├── MenuButton.coffee ├── MenuOverlay.coffee ├── Notification.coffee ├── Page.coffee ├── Radiobox.coffee ├── Ripple.coffee ├── RowItem.coffee ├── Select.coffee ├── Slider.coffee ├── Snackbar.coffee ├── StackView.coffee ├── StatusBar.coffee ├── Switch.coffee ├── Table.coffee ├── TableCard.coffee ├── TextArea.coffee ├── TextField.coffee ├── Theme.coffee ├── Tile.coffee ├── Toast.coffee ├── Type.coffee └── View.coffee ├── md-fonts ├── Apache License.txt ├── Roboto-Black.ttf ├── Roboto-BlackItalic.ttf ├── Roboto-Bold.ttf ├── Roboto-BoldItalic.ttf ├── Roboto-Italic.ttf ├── Roboto-Light.ttf ├── Roboto-LightItalic.ttf ├── Roboto-Medium.ttf ├── Roboto-MediumItalic.ttf ├── Roboto-Regular.ttf ├── Roboto-Thin.ttf └── Roboto-ThinItalic.ttf ├── md-images ├── Group.svg ├── keyboard.png ├── nav_bar.png ├── status_bar.png └── status_bar.svg └── md.coffee /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # framer-md 2 | A Material Design UI kit for Framer. 3 | -------------------------------------------------------------------------------- /framer-md-app.framer/..social.html.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/..social.html.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/..viewer.html.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/..viewer.html.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/.app.coffee.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/.app.coffee.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/.gitignore: -------------------------------------------------------------------------------- 1 | # Framer Git Ignore 2 | 3 | # General OSX 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # Framer Specific 31 | .*.html 32 | .app.js 33 | framer/*.old* 34 | framer/.*.hash 35 | framer/backup.coffee 36 | framer/backups/* 37 | framer/manifest.txt 38 | framer/preview.png 39 | framer/social-*x*.png 40 | -------------------------------------------------------------------------------- /framer-md-app.framer/.gitignore 2: -------------------------------------------------------------------------------- 1 | # Framer Git Ignore 2 | 3 | # General OSX 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # Framer Specific 31 | .*.html 32 | .app.js 33 | framer/*.old* 34 | framer/.*.hash 35 | framer/backup.coffee 36 | framer/backups/* 37 | framer/manifest.txt 38 | framer/preview.png 39 | framer/social-*x*.png 40 | -------------------------------------------------------------------------------- /framer-md-app.framer/.index.html.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/.index.html.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/..framer.modules.js.hash.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/..framer.modules.js.hash.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.bookmark: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.bookmark -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.bookmark 2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.bookmark 2 -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.config.json.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.config.json.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.design.vekter.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.design.vekter.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.framer.js.map.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.framer.js.map.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.manifest.txt.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.manifest.txt.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.preview.png.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.preview.png.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.social-800x600.png.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.social-800x600.png.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.social-80x80.png.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.social-80x80.png.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.social-880x460.png.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.social-880x460.png.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/.style.css.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/.style.css.icloud -------------------------------------------------------------------------------- /framer-md-app.framer/framer/config 2.json: -------------------------------------------------------------------------------- 1 | { 2 | "orientation" : 0, 3 | "updateDelay" : 0, 4 | "designModeSelected" : 0, 5 | "cachedDeviceHeight" : 640, 6 | "contentScale" : 1, 7 | "cachedDeviceWidth" : 360, 8 | "fullScreen" : false, 9 | "deviceType" : "google-nexus-5x", 10 | "sharedPrototype" : true, 11 | "propertyPanelToggleStates" : { 12 | 13 | }, 14 | "projectId" : "161AFC90-3E15-49FB-B518-BF8A8B6C4D4E", 15 | "deviceOrientation" : 0, 16 | "selectedHand" : "", 17 | "showBezel" : false, 18 | "foldedCodeRanges" : [ 19 | "{181, 1369}", 20 | "{1599, 795}", 21 | "{2395, 2771}" 22 | ], 23 | "deviceScale" : "fit" 24 | } -------------------------------------------------------------------------------- /framer-md-app.framer/framer/framer.generated.js: -------------------------------------------------------------------------------- 1 | // This is autogenerated by Framer 2 | 3 | 4 | if (!window.Framer && window._bridge) {window._bridge('runtime.error', {message:'[framer.js] Framer library missing or corrupt. Select File → Update Framer Library.'})} 5 | if (DeviceComponent) {DeviceComponent.Devices["iphone-6-silver"].deviceImageJP2 = false}; 6 | if (window.Framer) {window.Framer.Defaults.DeviceView = {"deviceScale":"fit","selectedHand":"","deviceType":"google-nexus-5x","contentScale":1,"hideBezel":true,"orientation":0}; 7 | } 8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":"fit","selectedHand":"","deviceType":"google-nexus-5x","contentScale":1,"hideBezel":true,"orientation":0}; 9 | } 10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"framer-md-app.framer"}; 11 | 12 | Framer.Device = new Framer.DeviceView(); 13 | Framer.Device.setupContext(); -------------------------------------------------------------------------------- /framer-md-app.framer/framer/framer.init.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function isFileLoadingAllowed() { 4 | return (window.location.protocol.indexOf("file") == -1) 5 | } 6 | 7 | function isHomeScreened() { 8 | return ("standalone" in window.navigator) && window.navigator.standalone == true 9 | } 10 | 11 | function isCompatibleBrowser() { 12 | return Utils.isWebKit() 13 | } 14 | 15 | var alertNode; 16 | 17 | function dismissAlert() { 18 | alertNode.parentElement.removeChild(alertNode) 19 | loadProject() 20 | } 21 | 22 | function showAlert(html) { 23 | 24 | alertNode = document.createElement("div") 25 | 26 | alertNode.classList.add("framerAlertBackground") 27 | alertNode.innerHTML = html 28 | 29 | document.addEventListener("DOMContentLoaded", function(event) { 30 | document.body.appendChild(alertNode) 31 | }) 32 | 33 | window.dismissAlert = dismissAlert; 34 | } 35 | 36 | function showBrowserAlert() { 37 | var html = "" 38 | html += "
" 39 | html += "Error: Not A WebKit Browser" 40 | html += "Your browser is not supported.
Please use Safari or Chrome.
" 41 | html += "Try anyway" 42 | html += "
" 43 | 44 | showAlert(html) 45 | } 46 | 47 | function showFileLoadingAlert() { 48 | var html = "" 49 | html += "
" 50 | html += "Error: Local File Restrictions" 51 | html += "Preview this prototype with Framer Mirror or learn more about " 52 | html += "file restrictions.
" 53 | html += "Try anyway" 54 | html += "
" 55 | 56 | showAlert(html) 57 | } 58 | 59 | function loadProject(callback) { 60 | CoffeeScript.load("app.coffee", callback) 61 | } 62 | 63 | function setDefaultPageTitle() { 64 | // If no title was set we set it to the project folder name so 65 | // you get a nice name on iOS if you bookmark to desktop. 66 | document.addEventListener("DOMContentLoaded", function() { 67 | if (document.title == "") { 68 | if (window.FramerStudioInfo && window.FramerStudioInfo.documentTitle) { 69 | document.title = window.FramerStudioInfo.documentTitle 70 | } else { 71 | document.title = window.location.pathname.replace(/\//g, "") 72 | } 73 | } 74 | }) 75 | } 76 | 77 | function init() { 78 | 79 | if (Utils.isFramerStudio()) { 80 | return 81 | } 82 | 83 | setDefaultPageTitle() 84 | 85 | if (!isCompatibleBrowser()) { 86 | return showBrowserAlert() 87 | } 88 | 89 | if (!isFileLoadingAllowed()) { 90 | return showFileLoadingAlert() 91 | } 92 | 93 | loadProject(function(){ 94 | // CoffeeScript: Framer?.CurrentContext?.emit?("loaded:project") 95 | var context; 96 | if (typeof Framer !== "undefined" && Framer !== null) { 97 | if ((context = Framer.CurrentContext) != null) { 98 | if (typeof context.emit === "function") { 99 | context.emit("loaded:project"); 100 | } 101 | } 102 | } 103 | }) 104 | } 105 | 106 | init() 107 | 108 | })() 109 | -------------------------------------------------------------------------------- /framer-md-app.framer/framer/images/cursor-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/images/cursor-active.png -------------------------------------------------------------------------------- /framer-md-app.framer/framer/images/cursor-active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/images/cursor-active@2x.png -------------------------------------------------------------------------------- /framer-md-app.framer/framer/images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/images/cursor.png -------------------------------------------------------------------------------- /framer-md-app.framer/framer/images/cursor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/images/cursor@2x.png -------------------------------------------------------------------------------- /framer-md-app.framer/framer/images/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/images/icon-120.png -------------------------------------------------------------------------------- /framer-md-app.framer/framer/images/icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/images/icon-152.png -------------------------------------------------------------------------------- /framer-md-app.framer/framer/images/icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/images/icon-180.png -------------------------------------------------------------------------------- /framer-md-app.framer/framer/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/images/icon-192.png -------------------------------------------------------------------------------- /framer-md-app.framer/framer/images/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/framer/images/icon-76.png -------------------------------------------------------------------------------- /framer-md-app.framer/framer/version: -------------------------------------------------------------------------------- 1 | 10 -------------------------------------------------------------------------------- /framer-md-app.framer/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/images/.gitkeep -------------------------------------------------------------------------------- /framer-md-app.framer/images/.gitkeep 2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/images/.gitkeep 2 -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/ActionButton.coffee: -------------------------------------------------------------------------------- 1 | # .d888888 dP oo 888888ba dP dP 2 | # d8' 88 88 88 `8b 88 88 3 | # 88aaaaa88a .d8888b. d8888P dP .d8888b. 88d888b. a88aaaa8P' dP dP d8888P d8888P .d8888b. 88d888b. 4 | # 88 88 88' `"" 88 88 88' `88 88' `88 88 `8b. 88 88 88 88 88' `88 88' `88 5 | # 88 88 88. ... 88 88 88. .88 88 88 88 .88 88. .88 88 88 88. .88 88 88 6 | # 88 88 `88888P' dP dP `88888P' dP dP 88888888P `88888P' dP dP `88888P' dP dP 7 | 8 | { Ripple } = require 'md-components/Ripple' 9 | { Icon } = require 'md-components/Icon' 10 | { Theme } = require 'md-components/Theme' 11 | 12 | exports.ActionButton = class ActionButton extends Layer 13 | constructor: (options = {}) -> 14 | 15 | @_action = options.action ? -> null 16 | @_icon = options.icon ? 'plus' 17 | 18 | { app } = require 'md-components/App' 19 | 20 | super _.defaults options, 21 | name: 'Action Button' 22 | x: Align.right(-16), y: Align.bottom(-17) 23 | width: 64, height: 64, borderRadius: 32 24 | backgroundColor: Theme.fab.backgroundColor 25 | shadowY: 2, shadowBlur: 3 26 | shadowColor: 'rgba(0,0,0,.25)' 27 | animationOptions: {time: .15} 28 | 29 | if app? 30 | @y = Align.bottom(-app.footer.height - 17) 31 | app.actionButton = @ 32 | 33 | # icon 34 | 35 | @iconLayer = new Icon 36 | name: '.', parent: @ 37 | x: Align.center, y: Align.center 38 | icon: @_icon, 39 | color: Theme.fab.color 40 | 41 | # mask 42 | 43 | @mask = new Layer 44 | parent: @ 45 | size: @size 46 | backgroundColor: null 47 | borderRadius: @borderRadius 48 | clip: true 49 | opacity: 1 50 | 51 | @mask.placeBehind @iconLayer 52 | @ripple = new Ripple( @mask, null ) 53 | 54 | # events 55 | 56 | @onTouchStart (event) -> 57 | @showTouched() 58 | Utils.delay 1, => @reset() 59 | 60 | @onTouchEnd (event) -> 61 | @_action() 62 | @reset() 63 | 64 | showTouched: -> 65 | @animate {shadowY: 3, shadowSpread: 1} 66 | 67 | reset: -> 68 | @animate 69 | shadowY: 2 70 | shadowSpread: 0 71 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/App.coffee: -------------------------------------------------------------------------------- 1 | # .d888888 2 | # d8' 88 3 | # 88aaaaa88a 88d888b. 88d888b. 4 | # 88 88 88' `88 88' `88 5 | # 88 88 88. .88 88. .88 6 | # 88 88 88Y888P' 88Y888P' 7 | # 88 88 8 | # dP dP 9 | 10 | { Header } = require 'md-components/Header' 11 | { BottomNav } = require 'md-components/BottomNav' 12 | { MenuOverlay } = require 'md-components/MenuOverlay' 13 | { Theme } = require 'md-components/Theme' 14 | 15 | exports.app # set by class 16 | 17 | class exports.App extends FlowComponent 18 | constructor: (options = {}) -> 19 | @__constructor = true 20 | 21 | exports.app = @ 22 | 23 | @activeInput 24 | @header 25 | @keyboard 26 | 27 | @notifications = [] 28 | 29 | super _.defaults options, 30 | name: 'App' 31 | 32 | # Header 33 | 34 | @header = new Header 35 | title: '' 36 | icon: '' 37 | 38 | # Keyboard 39 | 40 | @keyboard = new Layer 41 | name: 'Keyboard' 42 | y: @maxY, image: Theme.keyboard.image 43 | width: @width, height: 222 44 | index: 1000 45 | animationOptions: 46 | time: .25 47 | 48 | @keyboard.onTap @closeKeyboard 49 | 50 | # App Footer 51 | 52 | @footer = new Layer 53 | name: 'Footer' 54 | width: Screen.width, height: 48 55 | image: Theme.footer.image 56 | index: 999 57 | y: Align.bottom() 58 | clip: true 59 | 60 | flash = undefined 61 | 62 | @backButton = new Layer 63 | name: 'Back Button', parent: @footer 64 | x: 56 65 | width: 40, height: 40, borderRadius: 24 66 | opacity: 0, backgroundColor: 'rgba(255, 255, 255, .2)' 67 | animationOptions: {time: .15} 68 | 69 | @backButton.onTapStart => 70 | flash?.destroy() 71 | flash = @backButton.copy() 72 | flash.ignoreEvents = true 73 | flash.parent = @footer 74 | flash.animate {x: 32, width: 100, y: 0, height: 48, opacity: 1} 75 | 76 | @backButton.onTap => 77 | flash?.animateStop() 78 | flash?.animate {opacity: 0, options:{time: .5}} 79 | return if @current.constructor.name is 'View' 80 | @showPrevious() 81 | 82 | @menuOverlay = new MenuOverlay 83 | title: @name 84 | 85 | # Transition Events 86 | 87 | @onTransitionStart (prev, next, direction) => 88 | Utils.delay 0, => @onChange(next) 89 | 90 | # On changing to a new page 91 | 92 | onChange: (next) -> 93 | return if typeof next is 'string' 94 | if !_.includes(['View', 'Page'], next.constructor?.name) 95 | throw 'App only words with Views and Pages.' 96 | return 97 | 98 | @setHeader(next.headerOptions) 99 | next.contentInset.top = @header.maxY + 16 100 | 101 | next.scrollY = 0 102 | next.onLoad() 103 | 104 | # Transitions 105 | 106 | showNextRight: (nav, layerA, layerB, overlay) -> 107 | options = {curve: "spring(300, 35, 0)"} 108 | 109 | transition = 110 | layerA: 111 | show: {options: options, x: 0, y: 0} 112 | hide: {options: options, x: 0 - layerA?.width / 2, y: 0} 113 | layerB: 114 | show: {options: options, x: 0, y: 0} 115 | hide: {options: options, x: layerB.width, y: 0} 116 | 117 | showNextLeft: (nav, layerA, layerB, overlay) -> 118 | options = {curve: "spring(300, 35, 0)"} 119 | 120 | transition = 121 | layerA: 122 | show: {options: options, x: 0, y: 0} 123 | hide: {options: options, x: 0 + layerA?.width / 2, y: 0} 124 | layerB: 125 | show: {options: options, x: 0, y: 0} 126 | hide: {options: options, x: -layerB.width, y: 0} 127 | 128 | # keyboard 129 | 130 | openKeyboard: () => 131 | @footer.visible = false 132 | return if Utils.isMobile() 133 | 134 | @keyboard.bringToFront() 135 | @animate { y: -@keyboard.height } 136 | @keyboard.animate { y: Screen.height - @keyboard.height } 137 | 138 | closeKeyboard: => 139 | @footer.visible = true 140 | @animate { y: 0 } 141 | @keyboard.animate { y: Screen.height } 142 | 143 | # menu 144 | 145 | showMenu: -> 146 | @menuOverlay.show() 147 | 148 | hideMenu: -> 149 | @menuOverlay.hide() 150 | 151 | # header 152 | 153 | setHeader: (options = {}) -> 154 | @header.setHeader(options) 155 | 156 | # add view 157 | 158 | addView: (options = {}) -> 159 | @menuOverlay.addLink(options) 160 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/BottomNav.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP dP 888888ba 2 | # 88 `8b 88 88 88 `8b 3 | # a88aaaa8P' .d8888b. d8888P d8888P .d8888b. 88d8b.d8b. 88 88 .d8888b. dP .dP 4 | # 88 `8b. 88' `88 88 88 88' `88 88'`88'`88 88 88 88' `88 88 d8' 5 | # 88 .88 88. .88 88 88 88. .88 88 88 88 88 88 88. .88 88 .88' 6 | # 88888888P `88888P' dP dP `88888P' dP dP dP dP dP `88888P8 8888P' 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Icon } = require 'md-components/Icon' 11 | { Theme } = require 'md-components/Theme' 12 | 13 | exports.BottomNav = class BottomNav extends Layer 14 | constructor: (options = {}) -> 15 | 16 | @_destinations = options.destinations ? throw 'Needs at least one destination.' 17 | @_items = [] 18 | @_initialDestination = options.initialDestination ? undefined 19 | # destination should be: [{name: string, icon: iconString, action: function}] 20 | @_activeDestination = @_initialDestination ? @_items[0] 21 | @_app = options.app 22 | @view = options.view 23 | 24 | super _.defaults options, 25 | name: 'Bottom Nav' 26 | y: Align.bottom 27 | width: Screen.width, height: 56 28 | backgroundColor: Theme.bottomNav.backgroundColor 29 | shadowY: Theme.bottomNav.shadowY 30 | shadowBlur: Theme.bottomNav.shadowBlur 31 | shadowColor: Theme.bottomNav.shadowColor 32 | clip: true 33 | 34 | for destination, i in @_destinations 35 | 36 | item = new Layer 37 | name: '.', parent: @ 38 | x: @width/@_destinations.length * i 39 | width: @width/@_destinations.length, height: @height 40 | color: Theme.primary 41 | backgroundColor: null 42 | 43 | nav = @ 44 | 45 | do _.bind( -> 46 | 47 | @mask = new Layer 48 | parent: @ 49 | x: Align.center, y: Align.center() 50 | height: @height * 1.72 51 | width: @height * 1.7 52 | borderRadius: @height 53 | backgroundColor: null 54 | clip: true 55 | opacity: 1 56 | 57 | @ripple = new Ripple( @mask , external = true, undefined, events = false) 58 | 59 | @iconLayer = new Icon 60 | name: '.', parent: @ 61 | x: Align.center, y: Align.center(-8) 62 | icon: destination.icon 63 | animationOptions: {time: .15} 64 | 65 | @labelLayer = new Type.Caption 66 | name: '.', parent: @ 67 | x: Align.center, y: Align.center(14) 68 | width: @width, 69 | textAlign: 'center' 70 | text: destination.title 71 | animationOptions: {time: .15} 72 | 73 | # set events on entire item 74 | @onTapStart ( event ) => @ripple.show( event.point ) 75 | @onTapEnd @ripple.hide 76 | @onPanEnd @ripple.hide 77 | 78 | @view = destination.view 79 | 80 | @onTap -> nav._app.changeView(@view) 81 | 82 | , item) 83 | 84 | @_items.push(item) 85 | 86 | @showActive(@_items[0]) 87 | 88 | @define "activeDestination", 89 | get: -> return @_activeDestination 90 | set: (destination) -> 91 | return if destination is @_activeDestination 92 | @_activeDestination = destination 93 | 94 | @showActive(@_activeDestination) 95 | 96 | @_app.changeView(@_activeDestination.view) 97 | 98 | showActive: (item) -> 99 | item.labelLayer.animate {color: Theme.primary, opacity: 1} 100 | item.iconLayer.color = Theme.primary 101 | 102 | for sib in item.siblings 103 | sib.labelLayer.animate {color: '#777'} 104 | sib.iconLayer.color = '#777' -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Button.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP dP 2 | # 88 `8b 88 88 3 | # a88aaaa8P' dP dP d8888P d8888P .d8888b. 88d888b. 4 | # 88 `8b. 88 88 88 88 88' `88 88' `88 5 | # 88 .88 88. .88 88 88 88. .88 88 88 6 | # 88888888P `88888P' dP dP `88888P' dP dP 7 | 8 | 9 | Type = require 'md-components/Type' 10 | { Ripple } = require 'md-components/Ripple' 11 | { Icon } = require 'md-components/Icon' 12 | { Theme } = require 'md-components/Theme' 13 | 14 | exports.Button = class Button extends Layer 15 | constructor: (options = {}) -> 16 | @__constructor = true 17 | showLayers = options.showLayers 18 | 19 | # if an icon is passed in, return an icon class and bail 20 | if options.icon 21 | options.action ?= -> null 22 | options.color ?= Theme.colors.primary.main 23 | return new Icon(options) 24 | 25 | @_disabled 26 | @_action 27 | @_raised 28 | @_type 29 | @_base 30 | @_labelText 31 | 32 | @_explicitWidth = options.width? 33 | @_startX = options.x 34 | 35 | @_type = options.type ? if options.raised then 'raised' else 'flat' 36 | 37 | # properties by type 38 | switch @_type 39 | when 'flat' 40 | @_base = 41 | name: 'Flat Button' 42 | height: 36 43 | width: 999 44 | borderRadius: 2 45 | backgroundColor: null 46 | color: Theme.colors.secondary.main 47 | shadowY: 0 48 | shadowColor: 'rgba(0,0,0,.26)' 49 | shadowBlur: 0 50 | animationOptions: {time: .15} 51 | when 'raised' 52 | @_base = 53 | name: 'Raised Button' 54 | height: 36 55 | width: 999 56 | borderRadius: 2 57 | backgroundColor: Theme.colors.secondary.main 58 | color: Theme.colors.secondary.text 59 | shadowY: 2 60 | shadowColor: 'rgba(0,0,0,.26)' 61 | shadowBlur: 4 62 | animationOptions: {time: .15} 63 | 64 | super _.defaults options, @_base 65 | 66 | # text label 67 | @labelLayer = new Type.Button 68 | name: if showLayers then 'Label' else '.' 69 | parent: @ 70 | height: 36 71 | text: '{labelText}' 72 | textTransform: 'uppercase' 73 | textAlign: 'center' 74 | color: @color 75 | animationOptions: {time: .15} 76 | padding: 77 | left: 16.5, right: 16.5 78 | top: 9, bottom: 11 79 | 80 | # events 81 | @onTapStart -> 82 | @showRaised() 83 | 84 | @onTapEnd -> 85 | return if @_disabled 86 | @_action() 87 | @refresh() 88 | 89 | @labelLayer.on "change:width", => 90 | return if @_explicitWidth 91 | @width = @labelLayer.width 92 | @_base.width = @labelLayer.width 93 | @setRipple() 94 | 95 | @on "change:width", => 96 | return if @width is @labelLayer.width 97 | @labelLayer.width = @width 98 | @setRipple() 99 | 100 | # set props 101 | @action = options.action 102 | @disabled = options.disabled ? false 103 | 104 | delete @__constructor 105 | 106 | @text = options.text ? 'button' 107 | 108 | showRaised: => 109 | return if @disabled 110 | return if @type isnt 'raised' 111 | @animate {shadowY: 5, shadowBlur: 8} 112 | 113 | setRipple: -> 114 | @mask?.destroy() 115 | 116 | @mask = new Layer 117 | parent: @ 118 | size: @size 119 | backgroundColor: null 120 | borderRadius: 2 121 | clip: true 122 | opacity: 1 123 | 124 | @mask.placeBehind @labelLayer 125 | 126 | switch @type 127 | when 'flat' 128 | @ripple = new Ripple( @mask, null, colorOverride = 'rgba(0,0,0,.05)' ) 129 | when 'raised' 130 | @ripple = new Ripple( @mask, null ) 131 | 132 | refresh: => 133 | @animateStop() 134 | if @disabled 135 | if @type is 'raised' 136 | @animate 137 | backgroundColor: 'rgba(0,0,0,.12)' 138 | shadowY: 0 139 | shadowBlur: 0 140 | @labelLayer.animate 141 | color: 'rgba(0,0,0,.26)' 142 | else 143 | @animate @_base 144 | @labelLayer.animate 145 | color: @_base.color 146 | 147 | @define "type", 148 | get: -> return @_type 149 | 150 | @define "disabled", 151 | get: -> return @_disabled 152 | set: (bool = false) -> 153 | return if bool is @_disabled 154 | @_disabled = bool 155 | 156 | @emit("change:disabled", @_disabled, @) 157 | 158 | return if @__constructor 159 | @refresh() 160 | 161 | @define "action", 162 | get: -> return @_action 163 | set: (func = -> null) -> 164 | return if func is @_action 165 | @_action = func 166 | 167 | @define "text", 168 | get: -> return @_labelText 169 | set: (text = '') -> 170 | return if @__constructor 171 | @_labelText = text 172 | 173 | @labelLayer.visible = text.length > 0 174 | @labelLayer.template = text 175 | 176 | @x = @_startX 177 | @refresh() -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Card.coffee: -------------------------------------------------------------------------------- 1 | # a88888b. dP 2 | # d8' `88 88 3 | # 88 .d8888b. 88d888b. .d888b88 4 | # 88 88' `88 88' `88 88' `88 5 | # Y8. .88 88. .88 88 88. .88 6 | # Y88888P' `88888P8 dP `88888P8 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Icon } = require 'md-components/Icon' 11 | { Theme } = require 'md-components/Theme' 12 | { Divider } = require 'md-components/Divider' 13 | { Button } = require 'md-components/Button' 14 | { Elevation } = require 'md-components/Elevation' 15 | 16 | exports.Card = class Card extends Layer 17 | constructor: (options = {}) -> 18 | showLayers = options.showLayers ? true 19 | 20 | @_stack = [] 21 | 22 | @padding = options.padding ? { 23 | top: 16, right: 16, 24 | bottom: 16, left: 16 25 | stack: 16 26 | } 27 | 28 | @_elevation 29 | @_raised = undefined 30 | 31 | _initExpand = options.expanded 32 | options.expanded = undefined 33 | 34 | @_expanded = false 35 | @_expand = options.expand 36 | 37 | @_baseHeight = options.height ? 200 38 | @_baseFooterHeight = 0 39 | 40 | @_baseY = options.y ? 8 41 | @_expand = options.expand 42 | @_actions = options.actions ? [] # [{text: "", action: ->}] 43 | @_verticalActions = options.verticalActions ? false 44 | 45 | super _.defaults options, 46 | name: 'Card' 47 | y: 8 48 | width: Screen.width - 16 49 | borderRadius: 2 50 | backgroundColor: '#f9f9f9' 51 | shadowY: 2, shadowBlur: 3 52 | clip: true 53 | animationOptions: {time: .15} 54 | 55 | @footer = new Layer 56 | name: '.', parent: @ 57 | height: 52, width: @width 58 | y: Align.bottom 59 | backgroundColor: @backgroundColor 60 | animationOptions: {time: .15} 61 | 62 | @divider = new Divider 63 | name: 'Divider', parent: @footer 64 | visible: false 65 | 66 | if @_expand? 67 | 68 | @divider.visible = true 69 | @footer.visible = true 70 | 71 | @expandIcon = new Icon 72 | name: 'Expand Icon', parent: @footer 73 | x: Align.right(-12), y: Align.bottom(-12) 74 | icon: 'chevron-down', color: '#000' 75 | animationOptions: {time: .15} 76 | action: => @expanded = !@expanded 77 | 78 | if @_actions.length > 0 79 | 80 | @divider.visible = true 81 | @footer.visible = true 82 | 83 | startX = 8; startY = 8 84 | 85 | for action in @_actions 86 | @actionButtons = [] 87 | 88 | button = new Button 89 | name: "#{action.text} Button", parent: @footer 90 | x: startX, y: Align.bottom(-startY) 91 | action: _.bind(action.action, @) 92 | text: action.text 93 | 94 | if !@_verticalActions then startX = button.maxX + 4 95 | if @_verticalActions 96 | startY = @height - button.y + 4 97 | @footer.y = button.y - 8 98 | @footer.height += button.height + 8 99 | 100 | @actionButtons.push(button) 101 | 102 | @_baseFooterHeight = @footer.height 103 | 104 | # add a layer to the stack 105 | addToStack: (layers = [], position) => 106 | if not _.isArray(layers) then layers = [layers] 107 | last = _.last(@stack) 108 | 109 | if last? 110 | startY = last.maxY + (@padding.stack ? 0) 111 | else 112 | startY = @padding.top ? 0 113 | 114 | for layer in layers 115 | 116 | if layer.constructor.name is 'Card' then position = 'full' 117 | 118 | layer.props = 119 | parent: @ 120 | x: _.clamp( 121 | @padding.left + layer.x, 122 | @padding.left, 123 | @width - @padding.right - layer.width 124 | ) 125 | y: startY 126 | 127 | switch position 128 | when 'full' 129 | layer.width = @width - ( @padding.left + @padding.right ) 130 | when 'left' 131 | layer.props = 132 | width: (@width / 2) - @padding.left 133 | x: @padding.left 134 | when 'right' 135 | layer.props = 136 | width: (@width / 2) - @padding.right 137 | x: Align.right(-@padding.right) 138 | when 'center' 139 | layer.x = Align.center 140 | 141 | @stack.push(layer) 142 | 143 | layer.on "change:height", => @moveStack(@) 144 | 145 | @_setHeight() 146 | 147 | # pull a layer from the stack 148 | removeFromStack: (layer) => 149 | _.pull(@stack, layer) 150 | @refresh() 151 | 152 | # stack layers in stack, with optional padding and animation 153 | _stackView: ( 154 | animate = false, 155 | padding = @padding.stack, 156 | top = @padding.top, 157 | animationOptions = {time: .25} 158 | ) => 159 | 160 | for layer, i in @stack 161 | 162 | if animate is true 163 | if i is 0 then layer.animate 164 | y: top 165 | options: animationOptions 166 | 167 | else layer.animate 168 | y: @stack[i - 1].maxY + padding 169 | options: animationOptions 170 | else 171 | if i is 0 then layer.y = top 172 | else layer.y = @stack[i - 1].maxY + padding 173 | 174 | @_setHeight() 175 | 176 | # move stack when layer height changes 177 | _moveStack: (layer) => 178 | index = _.indexOf(@stack, layer) 179 | for layer, i in @stack 180 | if i > 0 and i > index 181 | layer.y = @stack[i - 1].maxY + @padding.stack 182 | 183 | @_setHeight() 184 | 185 | _setHeight: -> 186 | @height = _.last(@stack).maxY + (@padding.bottom ? 16) 187 | 188 | # build with page as bound object 189 | build: (func) -> do _.bind(func, @) 190 | 191 | # refresh page 192 | refresh: -> @_stackView() 193 | 194 | @define "stack", 195 | get: -> return @_stack 196 | set: (layers) -> 197 | layer.destroy() for layer in @stack 198 | @addToStack(layers) 199 | 200 | @define "expanded", 201 | get: -> return @_expanded 202 | set: (bool) -> 203 | return if bool is @_expanded 204 | @_expanded = bool 205 | 206 | if @_expanded 207 | @bringToFront() 208 | @expandIcon.animate {rotation: 180} 209 | @animate {height: @height + @_expand} 210 | @footer.animate {height: @_expand} 211 | else 212 | @expandIcon.animate {rotation: 0} 213 | @animate {height: @_baseHeight} 214 | @footer.animate {height: @_baseFooterHeight} 215 | 216 | @emit "change:expanded", @_expanded, @ 217 | 218 | @define "raised", 219 | get: -> return @_raised 220 | set: (bool) -> 221 | return if bool is @_raised 222 | @_raised = bool 223 | 224 | if @_raised then @elevation = 8 225 | else @elevation = 2 226 | 227 | @define 'elevation', 228 | get: -> return @_elevation 229 | set: (number) -> 230 | Elevation(@, number) 231 | 232 | 233 | 234 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Checkbox.coffee: -------------------------------------------------------------------------------- 1 | # a88888b. dP dP dP 2 | # d8' `88 88 88 88 3 | # 88 88d888b. .d8888b. .d8888b. 88 .dP 88d888b. .d8888b. dP. .dP 4 | # 88 88' `88 88ooood8 88' `"" 88888" 88' `88 88' `88 `8bd8' 5 | # Y8. .88 88 88 88. ... 88. ... 88 `8b. 88. .88 88. .88 .d88b. 6 | # Y88888P' dP dP `88888P' `88888P' dP `YP 88Y8888' `88888P' dP' `dP 7 | 8 | { Icon } = require 'md-components/Icon' 9 | { Theme } = require 'md-components/Theme' 10 | 11 | exports.Checkbox = CheckBox = class Checkbox extends Icon 12 | constructor: (options = {}) -> 13 | 14 | @_group = undefined 15 | 16 | super _.defaults options, 17 | name: '.' 18 | animationOptions: {time: .15} 19 | icon: 'checkbox-blank-outline' 20 | color: Theme.primary 21 | toggle: true 22 | action: -> null 23 | 24 | @on "change:isOn", @updateIcon 25 | 26 | updateIcon: => 27 | @icon = if @isOn then 'checkbox-marked' else 'checkbox-blank-outline' 28 | 29 | @define "group", 30 | get: -> return @_group 31 | set: (array) -> 32 | return if array is @_group 33 | @_group = array 34 | 35 | # add this checkbox to the group array if not in it already 36 | if not _.includes(@_group, @) then @_group.push(@) -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Dialog.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba oo dP 2 | # 88 `8b 88 3 | # 88 88 dP .d8888b. 88 .d8888b. .d8888b. 4 | # 88 88 88 88' `88 88 88' `88 88' `88 5 | # 88 .8P 88 88. .88 88 88. .88 88. .88 6 | # 8888888P dP `88888P8 dP `88888P' `8888P88 7 | # .88 8 | # d8888P 9 | 10 | Type = require 'md-components/Type' 11 | { Icon } = require 'md-components/Icon' 12 | { Theme } = require 'md-components/Theme' 13 | { Button } = require 'md-components/Button' 14 | 15 | # simplify: create an actions array, with text, action, color? 16 | # this needs to be standardized across apis 17 | 18 | exports.Dialog = class Dialog extends Layer 19 | constructor: (options = {}) -> 20 | 21 | showLayers = options.showLayers ? false 22 | 23 | @_title = options.title ? 'Default Title' 24 | @_body = options.body ? 'Body text goes here.' 25 | @_acceptText = options.acceptText ? 'confirm' 26 | @_acceptAction = options.acceptAction ? -> null 27 | @_declineText = options.declineText ? '' 28 | @_declineAction = options.declineAction ? -> null 29 | 30 | super _.defaults options, 31 | name: if showLayers then 'Dialog' else '.' 32 | size: Screen.size 33 | backgroundColor: 'rgba(0, 0, 0, .5)' 34 | opacity: 0 35 | 36 | @on Events.Tap, (event) -> event.stopPropagation() 37 | 38 | @container = new Layer 39 | name: 'container', parent: @ 40 | x: Align.center 41 | height: 128, width: Screen.width - 80 42 | backgroundColor: Theme.dialog.backgroundColor 43 | shadowX: 0, shadowY: 7, shadowBlur: 30 44 | opacity: 0 45 | shadowColor: 'rgba(0,0,0,.3)' 46 | 47 | @title = new Type.Title 48 | name: '.', parent: @container 49 | x: 24, y: 20 50 | fontSize: 16, fontWeight: 500, color: Theme.text.title 51 | text: @_title 52 | 53 | @body = new Type.Subhead 54 | name: 'body', parent: @container 55 | x: 24, y: 52 56 | width: @container.width - 42 57 | text: @_body 58 | 59 | buttonsY = if @_body is '' then 128 else @body.maxY + 16 60 | 61 | @accept = new Button 62 | name: '.', parent: @container 63 | x: Align.right(-16), y: buttonsY 64 | text: @_acceptText.toUpperCase() 65 | action: @_acceptAction 66 | 67 | if @_declineText isnt '' 68 | @decline = new Button 69 | name: '.', parent: @container 70 | x: 0, y: buttonsY 71 | text: @_declineText.toUpperCase() 72 | action: @_declineAction 73 | 74 | # set positions 75 | @container.height = @accept.maxY + 12 76 | @decline?.maxX = @accept.x - 16 77 | @container.y = Align.center(16) 78 | 79 | # add close actions to confirm and cancel 80 | for button in [@accept, @decline] 81 | button?.onTap => Utils.delay .25, @close 82 | 83 | # ON LOAD 84 | @open() 85 | 86 | open: => 87 | @animate 88 | opacity: 1 89 | options: 90 | time: .25 91 | 92 | @container.animate 93 | opacity: 1 94 | options: 95 | time: .25 96 | delay: .15 97 | 98 | close: => 99 | @container.animate 100 | opacity: 0 101 | options: 102 | time: .25 103 | 104 | @animate 105 | opacity: 0 106 | options: 107 | time: .25 108 | 109 | Utils.delay .5, => @destroy() -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Divider.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba oo oo dP 2 | # 88 `8b 88 3 | # 88 88 dP dP .dP dP .d888b88 .d8888b. 88d888b. 4 | # 88 88 88 88 d8' 88 88' `88 88ooood8 88' `88 5 | # 88 .8P 88 88 .88' 88 88. .88 88. ... 88 6 | # 8888888P dP 8888P' dP `88888P8 `88888P' dP 7 | 8 | Type = require 'md-components/Type' 9 | { Theme } = require 'md-components/Theme' 10 | 11 | class exports.Divider extends Layer 12 | constructor: (options = {}) -> 13 | 14 | width = 0 # check if parent is a View and adjust to padding 15 | showLayers = options.showLayers 16 | 17 | @_labelText = undefined 18 | @_backgroundColor = options.backgroundColor 19 | 20 | options.backgroundColor = Theme.divider.backgroundColor 21 | 22 | super _.defaults options, 23 | name: if showLayers then 'Divider' else '.' 24 | width: options.parent?.width ? 200, height: 1, 25 | backgroundColor: Theme.divider.backgroundColor 26 | 27 | @labelLayer = new Type.Caption 28 | name: if showLayers then 'Label' else '.' 29 | parent: @ 30 | x: Align.center 31 | y: Align.center 32 | padding: {left: 16, right: 16} 33 | textAlign: 'center' 34 | textTransform: 'uppercase' 35 | text: '{labelText}' 36 | visible: false 37 | backgroundColor: @_backgroundColor 38 | 39 | @text = options.text 40 | 41 | @define "text", 42 | get: -> return @_labelText 43 | set: (text) -> 44 | if not text? then text = '' 45 | @_labelText = text 46 | 47 | @labelLayer?.visible = @text.length > 0 48 | @labelLayer?.template = @text 49 | @labelLayer?.x = Align.center 50 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Elevation.coffee: -------------------------------------------------------------------------------- 1 | # 88888888b dP dP oo 2 | # 88 88 88 3 | # a88aaaa 88 .d8888b. dP .dP .d8888b. d8888P dP .d8888b. 88d888b. 4 | # 88 88 88ooood8 88 d8' 88' `88 88 88 88' `88 88' `88 5 | # 88 88 88. ... 88 .88' 88. .88 88 88 88. .88 88 88 6 | # 88888888P dP `88888P' 8888P' `88888P8 dP dP `88888P' dP dP 7 | 8 | # thanks to @ma_rylou 9 | 10 | exports.Elevation = (layer, elevationnumber = 0, animate = true, options = {time: .2, curve: 'ease'}) -> 11 | 12 | # Error handling 13 | if typeof elevationnumber isnt "number" 14 | throw Error "Elevation must be a number." 15 | 16 | # Clamp elevation number to between 0 and 24 17 | elevationnumber = _.clamp(elevationnumber, 0, 24) 18 | 19 | props = 20 | shadowSpread: 0 21 | shadowX: 0 22 | shadowY: elevationnumber 23 | shadowBlur: elevationnumber 24 | shadowColor:"rgba(0, 0, 0, 0.24)" 25 | 26 | animProps = _.merge(props, {options: options}) 27 | 28 | #target layer 29 | if animate then layer.animate animProps 30 | else layer.props = props 31 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/GridList.coffee: -------------------------------------------------------------------------------- 1 | 2 | # .88888. oo dP dP oo dP 3 | # d8' `88 88 88 88 4 | # 88 88d888b. dP .d888b88 88 dP .d8888b. d8888P 5 | # 88 YP88 88' `88 88 88' `88 88 88 Y8ooooo. 88 6 | # Y8. .88 88 88 88. .88 88 88 88 88 7 | # `88888' dP dP `88888P8 88888888P dP `88888P' dP 8 | 9 | Type = require 'md-components/Type' 10 | { Ripple } = require 'md-components/Ripple' 11 | { Icon } = require 'md-components/Icon' 12 | { Theme } = require 'md-components/Theme' 13 | 14 | exports.GridList = class GridList extends Layer 15 | constructor: (options = {}) -> 16 | 17 | @_columns = options.columns ? 2 18 | 19 | super _.defaults options, 20 | name: '.' 21 | width: Screen.width 22 | backgroundColor: null 23 | 24 | @tiles = [] 25 | @tileWidth = (@width - 24) / @_columns 26 | @tileHeight = options.tileHeight ? Screen.width / @_columns 27 | 28 | addTile: (tile) -> 29 | tile.i = @tiles.length 30 | tile.gridList = @ 31 | @tiles.push(tile) 32 | 33 | tile.x = 8 + (@tileWidth + 8) * (tile.i % @_columns) 34 | tile.y = 8 + (@tileHeight + 8) * Math.floor(tile.i / @_columns) 35 | 36 | @height = _.last(@tiles).maxY 37 | 38 | if @parent?.parent?.content? then @parent.parent.updateContent() 39 | 40 | removeTile: (tile) -> 41 | _.pull(@tiles, tile) 42 | tile.destroy() 43 | @repositionTiles() 44 | 45 | repositionTiles: -> 46 | for tile, i in @tiles 47 | tile.i = i 48 | tile.animate 49 | x: 8 + (@tileWidth + 8) * (tile.i % @_columns) 50 | y: 8 + (@tileHeight + 8) * Math.floor(tile.i / @_columns) 51 | @height = _.last(@tiles).maxY 52 | 53 | if @parent?.parent?.content? then @parent.parent.updateContent() 54 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Header.coffee: -------------------------------------------------------------------------------- 1 | # dP dP dP 2 | # 88 88 88 3 | # 88aaaaa88a .d8888b. .d8888b. .d888b88 .d8888b. 88d888b. 4 | # 88 88 88ooood8 88' `88 88' `88 88ooood8 88' `88 5 | # 88 88 88. ... 88. .88 88. .88 88. ... 88 6 | # dP dP `88888P' `88888P8 `88888P8 `88888P' dP 7 | 8 | Type = require 'md-components/Type' 9 | { Icon } = require 'md-components/Icon' 10 | { Theme } = require 'md-components/Theme' 11 | { modifyColor } = require 'md-components/Theme' 12 | { StatusBar } = require 'md-components/StatusBar' 13 | 14 | exports.Header = class Header extends Layer 15 | constructor: (options = {}) -> 16 | @__constructor = true 17 | 18 | # properties 19 | 20 | @_title 21 | options.title ?= 'Header' 22 | 23 | @_icon 24 | options.icon ?= 'menu' 25 | 26 | @_action 27 | options.action ?= -> null 28 | 29 | # assign forced options 30 | _.assign options, 31 | width: Screen.width 32 | height: 80 33 | shadowY: 2, 34 | shadowBlur: 3, 35 | shadowColor: 'rgba(0,0,0,.24)' 36 | 37 | # set default options 38 | super _.defaults options, 39 | name: options.title 40 | backgroundColor: Theme.header.backgroundColor ? '#777' 41 | color: Theme.header.title ? '#FFF' 42 | 43 | # title 44 | 45 | @titleLayer = new Type.Title 46 | name: '.', parent: @ 47 | x: 72, y: Align.bottom(-14) 48 | color: @color 49 | text: '' 50 | 51 | # icon 52 | 53 | @iconLayer = new Icon 54 | name: '.', parent: @, 55 | x: 12, y: Align.center(12) 56 | icon: options.icon ? 'menu' 57 | color: @color 58 | 59 | # status bar 60 | 61 | @statusBar = new StatusBar 62 | name: '.', parent: @ 63 | 64 | # events 65 | 66 | @iconLayer.onTapEnd => @_action() 67 | 68 | @on "change:color", => 69 | @titleLayer.color = @color 70 | @iconLayer.color = @color 71 | @statusBar.color = @color 72 | 73 | @on "change:backgroundColor", => 74 | @statusBar.backgroundColor = modifyColor( 75 | @backgroundColor, -1, -7, -12 76 | ) 77 | 78 | delete @__constructor 79 | 80 | # set options that require layers 81 | 82 | @title = options.title 83 | @icon = options.icon 84 | @action = options.action 85 | 86 | setHeader: (options = {}) -> 87 | 88 | for layer in [@titleLayer, @iconLayer] 89 | layer.animate {opacity: 0, options: {time: .15}} 90 | 91 | Utils.delay .25, => 92 | 93 | _.assign(@, options) 94 | 95 | for layer in [@titleLayer, @iconLayer] 96 | layer.animate {opacity: 1, options: {time: .15}} 97 | 98 | @define "title", 99 | get: -> return @_title 100 | set: (titleText) -> 101 | return if @__constructor 102 | @_title = titleText 103 | @titleLayer.text = titleText 104 | 105 | @define "icon", 106 | get: -> return @_icon 107 | set: (iconName) -> 108 | return if @__constructor 109 | @_icon = iconName 110 | @iconLayer.icon = iconName 111 | 112 | @define "action", 113 | get: -> return @_action 114 | set: (action) -> 115 | return if @__constructor 116 | @_action = action 117 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/MenuButton.coffee: -------------------------------------------------------------------------------- 1 | # 8888ba.88ba 888888ba dP dP 2 | # 88 `8b `8b 88 `8b 88 88 3 | # 88 88 88 .d8888b. 88d888b. dP dP a88aaaa8P' dP dP d8888P d8888P .d8888b. 88d888b. 4 | # 88 88 88 88ooood8 88' `88 88 88 88 `8b. 88 88 88 88 88' `88 88' `88 5 | # 88 88 88 88. ... 88 88 88. .88 88 .88 88. .88 88 88 88. .88 88 88 6 | # dP dP dP `88888P' dP dP `88888P' 88888888P `88888P' dP dP `88888P' dP dP 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Icon } = require 'md-components/Icon' 11 | { Theme } = require 'md-components/Theme' 12 | 13 | 14 | exports.MenuButton = class MenuButton extends Layer 15 | constructor: (options = {}) -> 16 | 17 | { app } = require 'md-components/App' 18 | 19 | @_icon = options.icon ? 'home' 20 | @_text = options.text ? 'Default' 21 | @_action = options.action ? -> null 22 | @_view = options.view 23 | @_app = options.app 24 | @_i = options.i 25 | 26 | super _.defaults options, 27 | height: 48, width: 304 28 | backgroundColor: null 29 | 30 | @iconLayer = new Icon 31 | name: '.', parent: @ 32 | y: Align.center 33 | icon: @_icon, color: Theme.menuOverlay.text 34 | action: -> null 35 | 36 | @labelLayer = new Type.Regular 37 | name: 'label', parent: @ 38 | x: @iconLayer.maxX + 16 39 | y: Align.center() 40 | color: Theme.menuOverlay.text 41 | text: @_text 42 | 43 | @onTapEnd -> 44 | if @_view? 45 | if @_view.i > @_i 46 | app?.transition(@_view, app.showNextRight) 47 | else 48 | app?.transition(@_view, app.showNextLeft) 49 | Utils.delay .25, => @parent.hide() -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/MenuOverlay.coffee: -------------------------------------------------------------------------------- 1 | # 8888ba.88ba .88888. dP 2 | # 88 `8b `8b d8' `8b 88 3 | # 88 88 88 .d8888b. 88d888b. dP dP 88 88 dP .dP .d8888b. 88d888b. 88 .d8888b. dP dP 4 | # 88 88 88 88ooood8 88' `88 88 88 88 88 88 d8' 88ooood8 88' `88 88 88' `88 88 88 5 | # 88 88 88 88. ... 88 88 88. .88 Y8. .8P 88 .88' 88. ... 88 88 88. .88 88. .88 6 | # dP dP dP `88888P' dP dP `88888P' `8888P' 8888P' `88888P' dP dP `88888P8 `8888P88 7 | # .88 8 | # d8888P 9 | 10 | Type = require 'md-components/Type' 11 | { Ripple } = require 'md-components/Ripple' 12 | { Icon } = require 'md-components/Icon' 13 | { Theme } = require 'md-components/Theme' 14 | { MenuButton } = require 'md-components/MenuButton' 15 | 16 | exports.MenuOverlay = class MenuOverlay extends Layer 17 | constructor: (options = {}) -> 18 | 19 | @links = [] 20 | @_title = options.title ? 'Menu' 21 | @_image = options.image ? null 22 | @_app = options.app 23 | 24 | 25 | super _.defaults options, 26 | height: Screen.height 27 | width: 304 28 | visible: false 29 | backgroundColor: Theme.menuOverlay.backgroundColor 30 | animationOptions: {curve: "spring(300, 35, 0)"} 31 | 32 | 33 | @scrim = new Layer 34 | name: '.', 35 | size: Screen.size 36 | backgroundColor: 'rgba(0,0,0,.6)' 37 | opacity: 0 38 | visible: false 39 | animationOptions: 40 | time: .25 41 | 42 | @scrim.onTap => @hide() 43 | @onSwipeLeftEnd => @hide() 44 | 45 | @header = new Layer 46 | name: '.', parent: @ 47 | width: @width, height: 173 48 | image: Theme.user.image 49 | backgroundColor: Theme.menuOverlay.header.backgroundColor 50 | 51 | @titleIcon = new Layer 52 | name: '.', parent: @header 53 | x: 16, y: 40 54 | height: 64, width: 64 55 | borderRadius: 32 56 | backgroundColor: Theme.menuOverlay.header.icon 57 | 58 | @subheaderExpand = new Icon 59 | name: '.', parent: @header 60 | x: Align.right(-16) 61 | y: Align.bottom(-16) 62 | icon: 'menu-down' 63 | color: Theme.menuOverlay.subheader.icon 64 | 65 | @subheader = new Type.Body1 66 | name: '.', parent: @header 67 | width: @width 68 | x: 16, y: Align.bottom(-18) 69 | text: @_title 70 | color: Theme.menuOverlay.subheader.text 71 | 72 | show: -> 73 | @bringToFront() 74 | @visible = true 75 | @x = -Screen.width 76 | @animate 77 | x: 0 78 | 79 | @scrim.placeBehind(@) 80 | @scrim.visible = true 81 | @scrim.animate 82 | opacity: 1 83 | 84 | hide: -> 85 | @animate 86 | x: -Screen.width 87 | 88 | @scrim.animate 89 | opacity: 0 90 | 91 | Utils.delay .3, => 92 | @visible = false 93 | @scrim.visible = false 94 | @sendToBack() 95 | @scrim.sendToBack() 96 | 97 | addLink: (options) -> 98 | lastY = _.last(@links)?.maxY ? 189 99 | @links.push new MenuButton 100 | name: '.', parent: @ 101 | x: 16, y: lastY 102 | text: options.title 103 | icon: options.icon 104 | view: options.view 105 | 106 | options.view.i = @links.length -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Notification.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP oo .8888b oo dP oo 2 | # 88 `8b 88 88 " 88 3 | # 88 88 .d8888b. d8888P dP 88aaa dP .d8888b. .d8888b. d8888P dP .d8888b. 88d888b. 4 | # 88 88 88' `88 88 88 88 88 88' `"" 88' `88 88 88 88' `88 88' `88 5 | # 88 88 88. .88 88 88 88 88 88. ... 88. .88 88 88 88. .88 88 88 6 | # dP dP `88888P' dP dP dP dP `88888P' `88888P8 dP dP `88888P' dP dP 7 | 8 | # Notification does not require an app property, however if one is not set then notifications will not app around eachother. 9 | 10 | # TODO: replace action1 and action2 with array of actions. 11 | 12 | Type = require 'md-components/Type' 13 | { Icon } = require 'md-components/Icon' 14 | { Theme } = require 'md-components/Theme' 15 | { Divider } = require 'md-components/Divider' 16 | 17 | exports.Notification = Notification = class Notification extends Layer 18 | constructor: (options = {}) -> 19 | 20 | { app } = require 'md-components/App' 21 | 22 | @_title = options.title ? 'Notification' 23 | @_body = options.body ? 'This is a notification.' 24 | @_icon = options.icon ? undefined 25 | @_iconColor = options.iconColor ? Theme.text.secondary 26 | @_iconBackgroundColor = options.iconBackgroundColor ? Theme.secondary 27 | 28 | @_actions = options.actions ? [] 29 | 30 | @_time = options.time ? new Date() 31 | @_timeout = options.timeout ? 5 32 | @_group = app?.notifications ? options.group ? [] 33 | 34 | # actions should be: 35 | # {title: 'archive', icon: 'archive', color: '', backgroundColor: ''} 36 | 37 | super _.defaults options, 38 | name: options.name ? '.' 39 | width: Screen.width - 16, borderRadius: 2 40 | x: Align.center 41 | backgroundColor: Theme.dialog.backgroundColor 42 | shadowX: 0, shadowY: 2, shadowBlur: 3 43 | opacity: 0, shadowColor: 'rgba(0,0,0,.3)' 44 | animationOptions: {time: .25} 45 | 46 | @iconLayer = new Layer 47 | name: 'Icon Container' 48 | parent: @ 49 | x: 12, y: 12 50 | height: 40, width: 40, borderRadius: 20 51 | backgroundColor: @_iconBackgroundColor 52 | 53 | if @_icon 54 | @icon = new Icon 55 | name: 'Icon' 56 | parent: @iconLayer 57 | x: Align.center, y: Align.center 58 | color: @_iconColor 59 | icon: @_icon 60 | 61 | @title = new Type.Subhead 62 | name: 'Title' 63 | parent: @ 64 | x: 64, y: 8 65 | width: @width - 72 66 | color: 'rgba(0,0,0,.87)' 67 | text: @_title 68 | 69 | @body = new Type.Body1 70 | name: 'Body' 71 | parent: @ 72 | x: 64, y: @title.maxY 73 | width: @width - 72 74 | text: @_body 75 | 76 | @date = new Type.Caption 77 | name: 'Date' 78 | parent: @ 79 | x: Align.right(-9), y: 15 80 | text: @_time.toLocaleTimeString([], hour: "numeric", minute: "2-digit") 81 | 82 | @height = _.clamp(@body.maxY + 13, 64, Infinity) 83 | 84 | # actions 85 | 86 | if @_actions.length > 0 87 | 88 | divider = new Divider 89 | name: 'Divider' 90 | parent: @ 91 | x: 64, y: @body.maxY + 11 92 | width: @width - 64 93 | 94 | @height = divider.maxY + 46 95 | 96 | startX = 64 97 | notification = @ 98 | 99 | for action in @_actions 100 | actionButton = new Layer 101 | name: 'Action 1', parent: @ 102 | x: startX, y: divider.maxY + 11 103 | width: 80, height: 24, backgroundColor: null 104 | 105 | do _.bind( -> # actionButton 106 | 107 | @icon = new Icon 108 | name: 'Icon', parent: @ 109 | width: 18, height: 18 110 | color: 'rgba(0,0,0,.54)' 111 | icon: action.icon 112 | 113 | @label = new Type.Caption 114 | name: 'Label', parent: @ 115 | x: @icon.maxX + 8 116 | fontSize: 13 117 | textTransform: 'uppercase' 118 | text: action.title 119 | 120 | @width = @label.maxX + 20 121 | startX += @width 122 | 123 | do (action) => 124 | @onTap => 125 | notification.close() 126 | if action.action? 127 | Utils.delay .25, _.bind(action.action, notification) 128 | 129 | actionButton) 130 | 131 | # swipes 132 | 133 | @onSwipeLeftEnd => @close('left') 134 | @onSwipeRightEnd => @close('right') 135 | 136 | @open() 137 | 138 | open: => 139 | startY = _.last(@_group)?.maxY ? 24 140 | startY += 8 141 | 142 | @y = startY 143 | 144 | @animate {opacity: 1} 145 | @_group.push(@) 146 | 147 | Utils.delay @_timeout, => if not @closed then @close('right') 148 | 149 | 150 | close: (direction) => 151 | _.pull(@_group, @) 152 | 153 | newY = 32 154 | for layer, i in @_group 155 | layer.animate { y: newY } 156 | newY += layer.height + 8 157 | 158 | @animate 159 | x: if direction is 'left' then -Screen.width else Screen.width 160 | opacity: 0 161 | 162 | @closed = true 163 | 164 | Utils.delay .5, => @destroy() 165 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Page.coffee: -------------------------------------------------------------------------------- 1 | 2 | # 888888ba 3 | # 88 `8b 4 | # a88aaaa8P' .d8888b. .d8888b. .d8888b. 5 | # 88 88' `88 88' `88 88ooood8 6 | # 88 88. .88 88. .88 88. ... 7 | # dP `88888P8 `8888P88 `88888P' 8 | # .88 9 | # d8888P 10 | 11 | # simplify header controls 12 | # remove template(?) 13 | 14 | { Theme } = require 'md-components/Theme' 15 | { StackView } = require 'md-components/StackView' 16 | 17 | exports.Page = class Page extends StackView 18 | constructor: (options = {}) -> 19 | @__constructor = true 20 | 21 | { app } = require 'md-components/App' 22 | 23 | options.icon ?= 'arrow-left' 24 | options.action ?= -> app.showPrevious() 25 | 26 | # header 27 | @headerOptions = { 28 | title: options.title 29 | icon: options.icon 30 | action: options.action 31 | actions: options.actions 32 | } 33 | 34 | # on load 35 | @onLoad = options.onLoad ? -> null 36 | 37 | # refresh 38 | @refresh = options.refresh ? -> null 39 | 40 | super _.defaults options, 41 | name: options.title ? 'View' 42 | size: Screen.size 43 | scrollHorizontal: false 44 | backgroundColor: Theme.page.primary.backgroundColor 45 | shadowSpread: 1 46 | shadowColor: 'rgba(0,0,0,.16)' 47 | shadowBlur: 3 48 | contentInset: {top: app.header?.height, bottom: 241} 49 | 50 | @content.backgroundColor = null 51 | 52 | @sendToBack() 53 | 54 | delete @__constructor 55 | 56 | onLoad: -> null 57 | refresh: -> null -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Radiobox.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP oo dP 2 | # 88 `8b 88 88 3 | # a88aaaa8P' .d8888b. .d888b88 dP .d8888b. 88d888b. .d8888b. dP. .dP 4 | # 88 `8b. 88' `88 88' `88 88 88' `88 88' `88 88' `88 `8bd8' 5 | # 88 88 88. .88 88. .88 88 88. .88 88. .88 88. .88 .d88b. 6 | # dP dP `88888P8 `88888P8 dP `88888P' 88Y8888' `88888P' dP' `dP 7 | 8 | 9 | { Icon } = require 'md-components/Icon' 10 | { Theme } = require 'md-components/Theme' 11 | 12 | exports.Radiobox = Radiobox = class Radiobox extends Icon 13 | constructor: (options = {}) -> 14 | 15 | @_group = undefined 16 | 17 | super _.defaults options, 18 | name: '.' 19 | animationOptions: {time: .15} 20 | icon: 'radiobox-blank' 21 | color: Theme.primary 22 | toggle: true 23 | toggleLock: true 24 | action: -> null 25 | 26 | @on "change:isOn", -> 27 | @updateIcon() 28 | @updateSiblings() 29 | 30 | updateIcon: => 31 | @icon = if @isOn then 'radiobox-marked' else 'radiobox-blank' 32 | 33 | updateSiblings: => 34 | if @isOn then sib.isOn = false for sib in _.without(@_group, @) 35 | 36 | @define "group", 37 | get: -> return @_group 38 | set: (array) -> 39 | return if array is @_group 40 | @_group = array 41 | 42 | # add this checkbox to the group array if not in it already 43 | if not _.includes(@_group, @) then @_group.push(@) 44 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Ripple.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba oo dP 2 | # 88 `8b 88 3 | # a88aaaa8P' dP 88d888b. 88d888b. 88 .d8888b. 4 | # 88 `8b. 88 88' `88 88' `88 88 88ooood8 5 | # 88 88 88 88. .88 88. .88 88 88. ... 6 | # dP dP dP 88Y888P' 88Y888P' dP `88888P' 7 | # 88 88 8 | # dP dP 9 | 10 | # By default, shows an expanding circle over a layer, clipped to its frame. 11 | # On the layer's touchEnd event, the circle and its mask will disappear. 12 | 13 | # required: 14 | # layer (Layer), the layer over which to show the ripple effect 15 | # point (object), the ripple origin point, usually a onTouchStart's event.point 16 | 17 | # optional: 18 | # placeBehind (Layer), a child of layer behind which the ripple should appear 19 | # color (string or color object), a custom color for the ripple 20 | 21 | class exports.Ripple extends Layer 22 | constructor: (@mask, @external = false, @colorOverride = undefined, events = true) -> 23 | 24 | @mask ?= throw 'Ripple needs a mask layer' 25 | 26 | super 27 | name: 'Ripple', parent: @mask 28 | point: Align.center 29 | backgroundColor: @_color 30 | width: 8, height: 8 31 | opacity: 0 32 | 33 | fullWidth = if @mask.width > @mask.height then @mask.width else @mask.height 34 | @_fullWidth = fullWidth * 2 35 | 36 | if events 37 | @mask.onTapStart ( event ) => @show( event.point ) 38 | @mask.onTapEnd @hide 39 | @mask.onPanEnd @hide 40 | @mask.onPan (event, layer) => 41 | isTooFar = (num) -> Math.abs(num) >= 24 42 | @hide() if isTooFar(event.offset.x) or isTooFar(event.offset.y) 43 | 44 | show: (point = @point) => 45 | return if @mask.parent?.disabled 46 | 47 | @animateStop() 48 | 49 | fullWidth = @_fullWidth 50 | parent = @mask.parent 51 | color = undefined 52 | 53 | if @colorOverride? 54 | color = @colorOverride 55 | else if @external 56 | color = new Color( parent.color ) 57 | .alpha( .25 ) 58 | else 59 | color = new Color( parent.backgroundColor ) 60 | .alpha( .5 ) 61 | .lighten( 15 ) 62 | .saturate ( 15 ) 63 | 64 | @props = 65 | x: point.x - 4 66 | y: point.y - 4 67 | height: 8 68 | width: 8 69 | borderRadius: 4 70 | backgroundColor: color 71 | opacity: 0 72 | 73 | @animate 74 | opacity: 1 75 | options: { time: .1 } 76 | 77 | @animate 78 | x: point.x - 4 - ( fullWidth ) 79 | y: point.y - 4 - ( fullWidth ) 80 | height: fullWidth * 2 81 | width: fullWidth * 2 82 | borderRadius: ( fullWidth ) 83 | options: { time: .6 } 84 | 85 | hide: => 86 | @animate 87 | opacity: 0 88 | options: { time: .45 , delay: .1 } 89 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/RowItem.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP dP 2 | # 88 `8b 88 88 3 | # a88aaaa8P' .d8888b. dP dP dP 88 d8888P .d8888b. 88d8b.d8b. 4 | # 88 `8b. 88' `88 88 88 88 88 88 88ooood8 88'`88'`88 5 | # 88 88 88. .88 88.88b.88' 88 88 88. ... 88 88 88 6 | # dP dP `88888P' 8888P Y8P dP dP `88888P' dP dP dP 7 | 8 | Type = require 'md-components/Type' 9 | { Theme } = require 'md-components/Theme' 10 | { Divider } = require 'md-components/Divider' 11 | 12 | 13 | exports.RowItem = class RowItem extends Layer 14 | constructor: (options = {}) -> 15 | 16 | @_icon = options.icon 17 | @_iconBackgroundColor = options.iconBackgroundColor ? '#777' 18 | @_text = options.text ? 'Row item' 19 | @_row = options.row ? 0 20 | @_y = 32 + (@_row * 48) 21 | 22 | super _.defaults options, 23 | width: Screen.width 24 | y: @_y 25 | height: 48 26 | backgroundColor: null 27 | 28 | @icon = new Layer 29 | name: '.', parent: @ 30 | x: 16, y: Align.center 31 | height: 32, width: 32, borderRadius: 16 32 | backgroundColor: @_iconBackgroundColor 33 | image: @_icon 34 | 35 | @labelLayer = new Type.Regular 36 | name: '.', parent: @ 37 | x: @icon.maxX + 16, y: Align.center 38 | color: Theme.text.text 39 | text: @_text -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Select.coffee: -------------------------------------------------------------------------------- 1 | Type = require 'md-components/Type' 2 | { Theme } = require 'md-components/Theme' 3 | { TextField } = require 'md-components/TextField' 4 | { Dropdown } = require 'md-components/Dropdown' 5 | { Icon } = require 'md-components/Icon' 6 | 7 | 8 | # .d88888b dP dP 9 | # 88. "' 88 88 10 | # `Y88888b. .d8888b. 88 .d8888b. .d8888b. d8888P 11 | # `8b 88ooood8 88 88ooood8 88' `"" 88 12 | # d8' .8P 88. ... 88 88. ... 88. ... 88 13 | # Y88888P `88888P' dP `88888P' `88888P' dP 14 | # 15 | # 16 | 17 | 18 | class exports.Select extends TextField 19 | constructor: (options = {}) -> 20 | 21 | @_options = options.options ? ['Select Menu'] 22 | 23 | # TODO 24 | # add an explicit width prop to textfield and use this prop instead of useMenuWidth 25 | 26 | useMenuWidth = options.useMenuWidth ? false 27 | 28 | super _.defaults options, 29 | name: 'Downdown Select' 30 | type: 'dropdown' 31 | inputType: 'input' 32 | readOnly: true 33 | clip: false 34 | 35 | @dropdown = new Dropdown 36 | parent: @ 37 | x: 0, y: 4 38 | width: if not useMenuWidth then @width 39 | options: @_options 40 | 41 | if useMenuWidth then @width = @dropdown.width 42 | 43 | @dropdown.on "change:selection", (selection) => 44 | @_input.value = selection 45 | @setValue() 46 | 47 | @dropdown.on "change:isOpen", (isOpen) => 48 | @focused = isOpen 49 | 50 | showFocused: => 51 | return if @disabled 52 | 53 | baseY = 0 54 | 55 | if @focused 56 | @bringToFront() 57 | 58 | @animateStop() 59 | 60 | @_app?.focused = @ 61 | 62 | if @screenFrame.y + @height > Screen.height - 222 63 | @scrollLayer?.scrollToLayer(@, 0, .45) 64 | else if @screenFrame.y < Screen.height * .15 65 | @scrollLayer?.scrollToLayer(@, 0, .15) 66 | 67 | @labelTextLayer?.animate 68 | y: baseY 69 | fontSize: 12 70 | color: @tint 71 | 72 | @inputLine?.animate 73 | height: 1 74 | backgroundColor: @tint 75 | 76 | else 77 | @animateStop() 78 | 79 | if this.hasTextContent() 80 | @labelTextLayer?.animate 81 | y: baseY 82 | fontSize: 12 83 | color: @labelTextColor 84 | else 85 | @labelTextLayer?.animate 86 | y: 22 87 | fontSize: 16 88 | color: @labelTextColor 89 | 90 | @inputLine?.animate 91 | height: 1 92 | backgroundColor: 'rgba(0, 0, 0, .42)' 93 | 94 | if @_app?.focused is @ 95 | @_app?.focused = undefined 96 | 97 | @setPlaceholder() 98 | 99 | @define "focused", 100 | get: -> return @_focused 101 | set: (value) -> 102 | return if @_focused is value 103 | if typeof value isnt 'boolean' then throw 'Focused must be either true or false.' 104 | 105 | @_focused = value 106 | 107 | @emit("change:focused", value, @) 108 | 109 | @showFocused() -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Slider.coffee: -------------------------------------------------------------------------------- 1 | # .d88888b dP oo dP 2 | # 88. "' 88 88 3 | # `Y88888b. 88 dP .d888b88 .d8888b. 88d888b. 4 | # `8b 88 88 88' `88 88ooood8 88' `88 5 | # d8' .8P 88 88 88. .88 88. ... 88 6 | # Y88888P dP dP `88888P8 `88888P' dP 7 | 8 | { Ripple } = require 'md-components/Ripple' 9 | { Icon } = require 'md-components/Icon' 10 | { Theme } = require 'md-components/Theme' 11 | 12 | exports.Slider = class Slider extends SliderComponent 13 | constructor: (options = {}) -> 14 | 15 | @_notched = options.notched ? false 16 | @_notches = options.notches ? 10 17 | @_notchWidth = undefined 18 | 19 | super _.defaults options, 20 | name: '.', height: 2 21 | backgroundColor: 'rgba(0,0,0,.26)' 22 | min: 0, max: 10 23 | animationOptions: {time: .15} 24 | 25 | @fill.backgroundColor = Theme.primary 26 | @knobSize = 44 27 | 28 | @knob.props = 29 | name: 'Knob' 30 | backgroundColor: null 31 | shadowX: 0 32 | shadowY: 0 33 | shadowBlur: 0 34 | color: Theme.primary 35 | 36 | @knob.draggable.propagateEvents = false 37 | 38 | @thumb = new Layer 39 | name: 'Thumb', parent: @knob 40 | x: Align.center, y: Align.center 41 | height: 12, width: 12, borderRadius: 12 42 | backgroundColor: Theme.primary 43 | animationOptions: {time: .15} 44 | 45 | if @_notched 46 | 47 | @_notchWidth = @width / @_notches 48 | 49 | for i in [0...@_notches] 50 | notch = new Layer 51 | name: '.', parent: @ 52 | x: i * @_notchWidth 53 | width: 2, height: 2, borderRadius: 2, 54 | backgroundColor: Theme.colors.primary.text 55 | 56 | notch.placeBehind(@knob) 57 | 58 | @tip = new Layer 59 | name: 'Tip', parent: @knob 60 | x: Align.center, y: -24 61 | width: 26, height: 32 62 | html: '' 63 | backgroundColor: null, opacity: 0 64 | animationOptions: {time: .15} 65 | 66 | @tipValue = new TextLayer 67 | name: 'Tip Value', parent: @tip 68 | y: 5, width: 26 69 | color: Theme.colors.primary.text 70 | fontSize: 12, fontFamily: 'Roboto', textAlign: 'center' 71 | text: "{value}" 72 | 73 | @tipValue.template = @value 74 | 75 | @onTouchStart @_showNotchedDragging 76 | 77 | @onValueChange -> 78 | @_setNotchedValue() 79 | @_setTipValue() 80 | 81 | 82 | else 83 | @knob.onTouchStart @_showDragging 84 | 85 | 86 | @knob.onTouchEnd @showDefault 87 | @knob.onDragEnd @showDefault 88 | @knob.onDrag @_setThumbColor 89 | @_setThumbColor() 90 | 91 | _roundValue: (number, nearest) -> 92 | return (Math.round(number / nearest) + 1) * nearest 93 | 94 | _setNotchedValue: (value) => 95 | if @knob.midX % @_notchWidth > 0 96 | @knob.x = @_roundValue(@knob.x, @_notchWidth) - (@knob.width / 2) 97 | 98 | _setTipValue: => 99 | @tipValue.template = Math.round(@value) 100 | @_setTipColor() 101 | 102 | _setTipColor: => 103 | color = if @value is @min then 'rgba(190, 190, 190, 1)' else Theme.primary 104 | @tip.html = '' 105 | 106 | _showNotchedDragging: => 107 | @_setTipColor() 108 | @thumb.animate {opacity: 0} 109 | @tip.animate {opacity: 1} 110 | 111 | _showDragging: => 112 | @_setThumbColor() 113 | @thumb.animate {width: 18, height: 18, x: 13, y: 13} 114 | 115 | _setThumbColor: => 116 | @thumb.backgroundColor = if @value is @min then 'rgba(190, 190, 190, 1)' else Theme.primary 117 | 118 | showDefault: => 119 | @animateStop() 120 | @_setThumbColor() 121 | @thumb.animate {opacity: 1, width: 12, height: 12, x: 15, y: 15} 122 | if @_notched 123 | @_setTipColor() 124 | @tip.animate {opacity: 0} 125 | 126 | 127 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Snackbar.coffee: -------------------------------------------------------------------------------- 1 | # .d88888b dP dP 2 | # 88. "' 88 88 3 | # `Y88888b. 88d888b. .d8888b. .d8888b. 88 .dP 88d888b. .d8888b. 88d888b. 4 | # `8b 88' `88 88' `88 88' `"" 88888" 88' `88 88' `88 88' `88 5 | # d8' .8P 88 88 88. .88 88. ... 88 `8b. 88. .88 88. .88 88 6 | # Y88888P dP dP `88888P8 `88888P' dP `YP 88Y8888' `88888P8 dP 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Theme } = require 'md-components/Theme' 11 | { Button } = require 'md-components/Button' 12 | 13 | class exports.Snackbar extends Layer 14 | constructor: (options = {}) -> 15 | 16 | { app } = require 'md-components/App' 17 | @_app = app 18 | 19 | @_title = options.title ? 'Snackbar' 20 | @_timeout = options.timeout ? 4 21 | @_action = options.action 22 | 23 | super _.defaults options, 24 | name: '.' 25 | y: Screen.maxY 26 | width: Screen.width 27 | clip: true 28 | backgroundColor: Theme.snackbar.backgroundColor 29 | animationOptions: {time: .25} 30 | visible: false 31 | 32 | titleWidth = @width - 48 33 | 34 | if @_action? 35 | @action = new Button 36 | parent: @ 37 | x: Align.right(-8), y: 4 38 | color: @_action.color ? Theme.colors.primary.light 39 | text: @_action.title.toUpperCase() 40 | action: @_action.action 41 | 42 | @action.onTap @hide 43 | titleWidth = @action.x - 8 - 24 44 | 45 | @textLabel = new Type.Body1 46 | name: 'Title', parent: @ 47 | x: 24, y: 14 48 | width: titleWidth 49 | text: @_title 50 | color: Theme.snackbar.color 51 | 52 | @height = @textLabel.maxY + 14 53 | @action?.y = Align.center 54 | 55 | 56 | 57 | Utils.delay @_timeout, @hide 58 | 59 | @show() 60 | 61 | show: => 62 | if @_app? 63 | if @_app.snackbar? 64 | @_app.snackbar.hide() 65 | Utils.delay 1, @show 66 | return 67 | else 68 | @_app.snackbar = @ 69 | @_app.actionButton?.animate {y: @_app.actionButton.y - @height, options: @animationOptions} 70 | 71 | height = @height 72 | 73 | @y = Screen.height - @_app.footer.height 74 | @height = 0 75 | @visible = true 76 | @animate 77 | y: @y - (height - 1) 78 | height: height 79 | else 80 | @visible = true 81 | @y = Screen.height 82 | @animate {y: Screen.height - @height} 83 | 84 | hide: => 85 | if @_app? 86 | @_app.snackbar = undefined 87 | @_app.actionButton?.animate {y: @_app.actionButton.y + @height, options: @animationOptions} 88 | 89 | @animate {height: 0, y: @y + @height} 90 | Utils.delay .5, => @destroy() -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/StackView.coffee: -------------------------------------------------------------------------------- 1 | # add stackview to any layer 2 | 3 | class exports.StackView extends ScrollComponent 4 | constructor: (options = {}) -> 5 | showLayers = options.showLayers ? false 6 | 7 | # stack related 8 | @_stack = [] 9 | @padding = options.padding ? { 10 | top: 16, right: 16, 11 | bottom: 0, left: 16 12 | stack: 16 13 | } 14 | 15 | super _.defaults options, 16 | name: 'StackView' 17 | size: Screen.size 18 | scrollHorizontal: false 19 | contentInset: { bottom: 16 } 20 | 21 | @content.clip = false 22 | @content.backgroundColor = Screen.backgroundColor 23 | @content.name = if options.showLayers then 'content' else '.' 24 | 25 | # add a layer to the stack 26 | addToStack: (layers = [], position) => 27 | if not _.isArray(layers) then layers = [layers] 28 | last = _.last(@stack) 29 | 30 | if last? 31 | startY = last.maxY + (@padding.stack ? 0) 32 | else 33 | startY = @padding.top ? 0 34 | 35 | for layer in layers 36 | 37 | if layer.constructor.name is 'Card' then position = 'full' 38 | 39 | layer.props = 40 | parent: @content 41 | x: _.clamp( 42 | @padding.left + layer.x, 43 | @padding.left, 44 | @width - @padding.right - layer.width 45 | ) 46 | y: startY 47 | 48 | switch position 49 | when 'full' 50 | layer.width = @width - ( @padding.left + @padding.right ) 51 | when 'left' 52 | layer.props = 53 | width: (@width / 2) - @padding.left 54 | x: @padding.left 55 | when 'right' 56 | layer.props = 57 | width: (@width / 2) - @padding.right 58 | x: Align.right(-@padding.right) 59 | when 'center' 60 | layer.x = Align.center 61 | 62 | @stack.push(layer) 63 | 64 | layer.on "change:height", => @moveStack(@) 65 | 66 | @updateContent() 67 | 68 | # pull a layer from the stack 69 | removeFromStack: (layer) => 70 | _.pull(@stack, layer) 71 | 72 | # stack layers in stack, with optional padding and animation 73 | stackView: ( 74 | animate = false, 75 | padding = @padding.stack, 76 | top = @padding.top, 77 | animationOptions = {time: .25} 78 | ) => 79 | 80 | for layer, i in @stack 81 | 82 | if animate is true 83 | if i is 0 then layer.animate 84 | y: top 85 | options: animationOptions 86 | 87 | else layer.animate 88 | y: @stack[i - 1].maxY + padding 89 | options: animationOptions 90 | else 91 | if i is 0 then layer.y = top 92 | else layer.y = @stack[i - 1].maxY + padding 93 | 94 | @updateContent() 95 | 96 | # move stack when layer height changes 97 | moveStack: (layer) => 98 | index = _.indexOf(@stack, layer) 99 | for layer, i in @stack 100 | if i > 0 and i > index 101 | layer.y = @stack[i - 1].maxY + @padding.stack 102 | 103 | 104 | # build with page as bound object 105 | build: (func) -> do _.bind(func, @) 106 | 107 | # refresh page 108 | refresh: -> null 109 | 110 | @define "stack", 111 | get: -> return @_stack 112 | set: (layers) -> 113 | layer.destroy() for layer in @stack 114 | @addToStack(layers) 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/StatusBar.coffee: -------------------------------------------------------------------------------- 1 | # .d88888b dP dP 888888ba 2 | # 88. "' 88 88 88 `8b 3 | # `Y88888b. d8888P .d8888b. d8888P dP dP .d8888b. a88aaaa8P' .d8888b. 88d888b. 4 | # `8b 88 88' `88 88 88 88 Y8ooooo. 88 `8b. 88' `88 88' `88 5 | # d8' .8P 88 88. .88 88 88. .88 88 88 .88 88. .88 88 6 | # Y88888P dP `88888P8 dP `88888P' `88888P' 88888888P `88888P8 dP 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Icon } = require 'md-components/Icon' 11 | { Theme } = require 'md-components/Theme' 12 | 13 | exports.StatusBar = class StatusBar extends Layer 14 | constructor: (options = {}) -> 15 | 16 | super _.defaults options, 17 | name: '.' 18 | width: Screen.width, height: 24 19 | backgroundColor: Theme.statusBar.backgroundColor 20 | 21 | @items = new Layer 22 | name: '.', parent: @ 23 | width: 100 24 | height: 15 25 | x: Align.right(-8) 26 | y: 5 27 | backgroundColor: null 28 | style: 29 | lineHeight: 0 30 | 31 | @on "change:color", => @setSVG() 32 | @color = '#FFF' 33 | 34 | setSVG: -> 35 | @items.html = """ 36 | 44 | 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 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 12:30 84 | 85 | 86 | 87 | 88 | """ -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Switch.coffee: -------------------------------------------------------------------------------- 1 | 2 | # .d88888b oo dP dP 3 | # 88. "' 88 88 4 | # `Y88888b. dP dP dP dP d8888P .d8888b. 88d888b. 5 | # `8b 88 88 88 88 88 88' `"" 88' `88 6 | # d8' .8P 88.88b.88' 88 88 88. ... 88 88 7 | # Y88888P 8888P Y8P dP dP `88888P' dP dP 8 | 9 | Type = require 'md-components/Type' 10 | { Ripple } = require 'md-components/Ripple' 11 | { Icon } = require 'md-components/Icon' 12 | { Theme } = require 'md-components/Theme' 13 | 14 | exports.Switch = class Switch extends Layer 15 | constructor: (options = {}) -> 16 | 17 | @_isOn = false 18 | 19 | super _.defaults options, 20 | name: 'Switch' 21 | width: 34, height: 14, borderRadius: 7 22 | color: new Color(Theme.primary).desaturate(100).alpha(.84) 23 | backgroundColor: 'rgba(0,0,0,.54)' 24 | animationOptions: {time: .15} 25 | 26 | @mask = new Layer 27 | name: 'Mask', parent: @ 28 | x: -12, y: Align.center 29 | width: 44, height: 44 30 | borderRadius: 20 31 | backgroundColor: null 32 | clip: true 33 | opacity: 1 34 | animationOptions: {time: .15} 35 | 36 | @ripple = new Ripple( @mask, external = true ) 37 | 38 | @knob = new Layer 39 | name: 'Knob', parent: @mask 40 | x: Align.center, y: Align.center 41 | width: 20, height: 20, borderRadius: 10 42 | backgroundColor: 'rgba(250, 250, 250, 1)' 43 | shadowY: 2, shadowBlur: 3 44 | animationOptions: {time: .15} 45 | 46 | @onTap -> @isOn = !@isOn 47 | 48 | @define "isOn", 49 | get: -> return @_isOn 50 | set: (bool) -> 51 | return if bool is @_isOn 52 | 53 | @_isOn = bool 54 | @emit("change:isOn", @_isOn, @) 55 | @update() 56 | 57 | update: -> 58 | if @_isOn 59 | @mask.animate {x: Align.right(12)} 60 | @color = Theme.primary 61 | @knob.animate {backgroundColor: Theme.primary} 62 | @animate {backgroundColor: Theme.colors.primary.light} 63 | else 64 | @mask.animate {x: -12} 65 | @color = new Color(Theme.primary).desaturate(100).alpha(.84) 66 | @knob.animate {backgroundColor: 'rgba(250, 250, 250, 1)'} 67 | @animate {backgroundColor: 'rgba(0,0,0,.54)'} 68 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/TextArea.coffee: -------------------------------------------------------------------------------- 1 | Type = require 'md-components/Type' 2 | { Theme } = require 'md-components/Theme' 3 | { TextField } = require 'md-components/TextField' 4 | 5 | 6 | # d888888P dP .d888888 7 | # 88 88 d8' 88 8 | # 88 .d8888b. dP. .dP d8888P 88aaaaa88a 88d888b. .d8888b. .d8888b. 9 | # 88 88ooood8 `8bd8' 88 88 88 88' `88 88ooood8 88' `88 10 | # 88 88. ... .d88b. 88 88 88 88 88. ... 88. .88 11 | # dP `88888P' dP' `dP dP 88 88 dP `88888P' `88888P8 12 | # 13 | # 14 | 15 | exports.TextArea = class TextArea extends TextField 16 | constructor: (options = {}) -> 17 | 18 | @_rows = options.rows ? 4 19 | 20 | super _.defaults options, 21 | name: 'Text Area' 22 | width: 300 23 | borderRadius: 4 24 | borderWidth: 2, borderColor: options.tint 25 | padding: {top: 28, bottom: 16, right: 16, left: 16} 26 | clip: true 27 | inputType: 'textarea' 28 | 29 | # Label Text 30 | 31 | @labelTextLayer.props = 32 | x: 16, y: 16 33 | 34 | @helperTextLayer.visible = false 35 | 36 | # Input Line 37 | 38 | @inputLine.destroy() 39 | 40 | # Textarea Element 41 | 42 | @setInputAttribute('rows', @_rows) 43 | @setInputAttribute('resize', @_rows) 44 | 45 | @height = @_input.clientHeight 46 | 47 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Theme.coffee: -------------------------------------------------------------------------------- 1 | # d888888P dP 2 | # 88 88 3 | # 88 88d888b. .d8888b. 88d8b.d8b. .d8888b. 4 | # 88 88' `88 88ooood8 88'`88'`88 88ooood8 5 | # 88 88 88 88. ... 88 88 88 88. ... 6 | # dP dP dP `88888P' dP dP dP `88888P' 7 | 8 | 9 | # When loaded, this module will attempt to create a new theme based on 10 | # the Design Mode template. 11 | 12 | Screen.backgroundColor = '#000' 13 | 14 | exports.modifyColor = modifyColor = (color, h, s, l) -> 15 | clip = _.replace(_.replace(color.toHslString().slice(4, -1), '%', ''), '%', '') .split(', ') 16 | 17 | newColor = new Color( 18 | h: _.parseInt(clip[0]) + h, 19 | s: (_.parseInt(clip[1]) + s)/100, 20 | l: (_.parseInt(clip[2]) + l)/100, 21 | a: 1) 22 | 23 | return newColor 24 | 25 | primaryColor = new Color('#0F6CC8') 26 | primaryTextColor = new Color('#FFFFFF') 27 | 28 | secondaryColor = new Color('#1B9DFF') 29 | secondaryTextColor = new Color('#FFFFFF') 30 | 31 | menuColor = new Color ('#CCCCCC') 32 | menuTextColor = new Color('#000000') 33 | 34 | pageColor = new Color('#FFFFFF') 35 | pageTextColor = new Color('#333333') 36 | 37 | exports.colors = colors = 38 | primary: 39 | main: primaryColor 40 | light: modifyColor(primaryColor, 13, -5, 15) 41 | dark: modifyColor(primaryColor, -1, -7, -12) 42 | text: primaryTextColor 43 | 44 | secondary: 45 | main: secondaryColor 46 | light: modifyColor(secondaryColor, 13, -5, 15) 47 | dark: modifyColor(secondaryColor, -1, -7, -12) 48 | text: secondaryTextColor 49 | menu: 50 | main: menuColor 51 | light: modifyColor(menuColor, 13, -5, 15) 52 | dark: modifyColor(menuColor, -1, -7, -12) 53 | text: menuTextColor 54 | page: 55 | main: pageColor 56 | light: modifyColor(pageColor, 13, -5, 15) 57 | dark: modifyColor(pageColor, -1, -7, -12) 58 | text: pageTextColor 59 | 60 | exports.Theme = 61 | tint: colors.secondary.main 62 | primary: colors.primary.main 63 | secondary: colors.secondary.main 64 | page: colors.page.main 65 | menu: colors.menu.light 66 | colors: colors 67 | 68 | user: 69 | image: undefined 70 | 71 | header: 72 | backgroundColor: colors.primary.main 73 | title: colors.primary.text 74 | icon: 75 | color: colors.primary.text 76 | tabs: 77 | backgroundColor: colors.primary.light 78 | color: colors.primary.text 79 | selector: colors.secondary.main 80 | 81 | statusBar: 82 | image: 'modules/md-images/status_bar.png' 83 | backgroundColor: colors.primary.dark 84 | 85 | bottomNav: 86 | backgroundColor: '#FFFFFF' 87 | shadowY: -2 88 | shadowBlur: 6 89 | shadowColor: 'rgba(0,0,0,.1)' 90 | 91 | navBar: 92 | backgroundColor: '#000000' 93 | 94 | keyboard: 95 | image: 'modules/md-images/keyboard.png' 96 | 97 | footer: 98 | image: 'modules/md-images/nav_bar.png' 99 | 100 | page: 101 | primary: 102 | backgroundColor: colors.page.main 103 | text: colors.page.text 104 | secondary: 105 | backgroundColor: '#F5F5F6' 106 | 107 | menuOverlay: 108 | header: 109 | backgroundColor: colors.secondary.main 110 | icon: colors.secondary.light 111 | text: colors.secondary.text 112 | subheader: 113 | color: colors.menu.text 114 | text: colors.secondary.text 115 | icon: colors.secondary.text 116 | backgroundColor: colors.menu.light 117 | text: colors.menu.text 118 | slider: 119 | knob: colors.secondary.light 120 | fill: colors.secondary.dark 121 | 122 | button: 123 | flat: 124 | backgroundColor: null 125 | color: colors.secondary.main 126 | shadowY: 0 127 | shadowColor: 'rgba(0,0,0,.18)' 128 | shadowBlur: 0 129 | 130 | raised: 131 | backgroundColor: colors.secondary.main 132 | color: colors.secondary.text 133 | shadowY: 2 134 | shadowColor: 'rgba(0,0,0,.18)' 135 | shadowBlur: 6 136 | 137 | fab: 138 | backgroundColor: colors.secondary.main 139 | color: colors.secondary.text 140 | 141 | dialog: 142 | backgroundColor:'#FAFAFA' 143 | 144 | divider: 145 | backgroundColor: 'rgba(0,0,0,.12)' 146 | 147 | text: 148 | primary: colors.primary.text 149 | secondary: colors.secondary.text 150 | 151 | table: 152 | backgroundColor: '#FFFFFF' 153 | text: colors.primary.text 154 | checkBox: 155 | backgroundColor: null 156 | borderColor: '#D3D3D3' 157 | selected: 158 | backgroundColor: colors.secondary.main 159 | text: colors.primary.text 160 | checkBox: 161 | backgroundColor: colors.secondary.dark 162 | borderColor: null 163 | snackbar: 164 | backgroundColor: 'rgba(51, 51, 51, 1)' 165 | color: 'rgba(255, 255, 255, 1)' 166 | 167 | toast: 168 | backgroundColor: 'rgba(51, 51, 51, 1)' 169 | color: 'rgba(255, 255, 255, 1)' 170 | 171 | slider: 172 | knob: colors.primary.light 173 | fill: colors.primary.dark 174 | 175 | card: 176 | header: colors.secondary.dark 177 | 178 | color_pallete?.destroy() -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Tile.coffee: -------------------------------------------------------------------------------- 1 | # d888888P oo dP 2 | # 88 88 3 | # 88 dP 88 .d8888b. 4 | # 88 88 88 88ooood8 5 | # 88 88 88 88. ... 6 | # dP dP dP `88888P' 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Icon } = require 'md-components/Icon' 11 | { Theme } = require 'md-components/Theme' 12 | 13 | exports.Tile = Tile = class Tile extends Layer 14 | constructor: (options = {}) -> 15 | 16 | @_header = options.header ? false 17 | @_footer = options.footer ? false 18 | @_action = options.action ? -> null 19 | @_headerAction = options.headerAction ? -> null 20 | @_footerAction = options.footerAction ? -> null 21 | 22 | if @_header and @_footer then throw 'Tile cannot have both a header and a footer.' 23 | 24 | @_icon = options.icon 25 | @gridList = options.gridList # ? throw 'Tile needs a grid property.' 26 | 27 | super _.defaults options, 28 | name: '.', parent: @gridList 29 | width: @gridList.tileWidth 30 | height: @gridList.tileHeight 31 | animationOptions: {time: .3} 32 | 33 | @onTouchStart (event) -> 34 | if @gridList.parent?.parent?.content and @gridList.parent?.parent?.isMoving is false 35 | Ripple(@, event.point, @header, options.RippleColor ? 'rgba(0,0,0,.1)') 36 | 37 | @onTap @_action 38 | @onTap (event) -> event.stopPropagation() 39 | 40 | if @_header or @_footer 41 | @header = new Layer 42 | name: '.', parent: @ 43 | y: if @_footer then Align.bottom() 44 | width: @width 45 | height: if options.support then 68 else 48 46 | backgroundColor: options.backgroundColor ? 'rgba(0,0,0,.5)' 47 | 48 | @header.onTouchStart (event) -> Ripple(@, event.point, @title) 49 | 50 | if @_footer then @header.onTap @_footerAction 51 | else @header.onTap @_headerAction 52 | 53 | @header.onTap (event) -> event.stopPropagation() 54 | 55 | if options.title 56 | @header.title = new Type.Regular 57 | name: '.', parent: @header 58 | x: 8, y: if options.support then 12 else Align.center() 59 | color: @color 60 | text: options.title ? 'Two Line' 61 | 62 | if options.support 63 | @header.support = new TextLayer 64 | name: '.', parent: @header 65 | x: 8, y: 35 66 | fontSize: 12 67 | fontFamily: 'Roboto' 68 | color: @color 69 | text: options.support ? 'Support text' 70 | 71 | if options.icon 72 | @header.icon = new Icon 73 | name: '.', parent: @header 74 | x: Align.right(-12), y: if options.support then 20 else Align.center() 75 | icon: options.icon 76 | color: @color 77 | 78 | @i = undefined 79 | @gridList.addTile(@) -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Toast.coffee: -------------------------------------------------------------------------------- 1 | # d888888P dP 2 | # 88 88 3 | # 88 .d8888b. .d8888b. .d8888b. d8888P 4 | # 88 88' `88 88' `88 Y8ooooo. 88 5 | # 88 88. .88 88. .88 88 88 6 | # dP `88888P' `88888P8 `88888P' dP 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Theme } = require 'md-components/Theme' 11 | { Button } = require 'md-components/Button' 12 | 13 | # currently identical to snackbar 14 | 15 | class exports.Toast extends Layer 16 | constructor: (options = {}) -> 17 | 18 | { app } = require 'md-components/App' 19 | @_app = app 20 | 21 | @_title = options.title ? 'Toast' 22 | @_timeout = options.timeout ? 4 23 | @_action = options.action 24 | 25 | super _.defaults options, 26 | name: '.' 27 | y: Screen.maxY 28 | width: Screen.width 29 | clip: true 30 | backgroundColor: Theme.toast.backgroundColor 31 | animationOptions: {time: .25} 32 | visible: false 33 | 34 | titleWidth = @width - 48 35 | 36 | if @_action? 37 | @action = new Button 38 | parent: @ 39 | x: Align.right(-8), y: 4 40 | color: @_action.color ? Theme.colors.primary.light 41 | text: @_action.title.toUpperCase() 42 | action: @_action.action 43 | 44 | @action.onTap @hide 45 | titleWidth = @action.x - 8 - 24 46 | 47 | @textLabel = new Type.Body1 48 | name: 'Title', parent: @ 49 | x: 24, y: 14 50 | width: titleWidth 51 | text: @_title 52 | color: Theme.toast.color 53 | 54 | @height = @textLabel.maxY + 14 55 | @action?.y = Align.center 56 | 57 | 58 | 59 | Utils.delay @_timeout, @hide 60 | 61 | @show() 62 | 63 | show: => 64 | if @_app? 65 | if @_app.toast? 66 | @_app.toast.hide() 67 | Utils.delay 1, @show 68 | return 69 | else 70 | @_app.toast = @ 71 | @_app.actionButton?.animate {y: @_app.actionButton.y - @height, options: @animationOptions} 72 | 73 | height = @height 74 | 75 | @y = Screen.height - @_app.footer.height 76 | @height = 0 77 | @visible = true 78 | @animate 79 | y: @y - (height - 1) 80 | height: height 81 | else 82 | @visible = true 83 | @y = Screen.height 84 | @animate {y: Screen.height - @height} 85 | 86 | hide: => 87 | if @_app? 88 | @_app.toast = undefined 89 | @_app.actionButton?.animate {y: @_app.actionButton.y + @height, options: @animationOptions} 90 | 91 | @animate {height: 0, y: @y + @height} 92 | Utils.delay .5, => @destroy() -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/Type.coffee: -------------------------------------------------------------------------------- 1 | Theme = require 'md-components/Theme' 2 | 3 | # d888888P dP 4 | # 88 88 5 | # 88 dP dP 88d888b. .d8888b. .d8888b. 88d888b. .d8888b. 88d888b. 88d888b. dP dP 6 | # 88 88 88 88' `88 88' `88 88' `88 88' `88 88' `88 88' `88 88' `88 88 88 7 | # 88 88. .88 88. .88 88. .88 88. .88 88 88. .88 88. .88 88 88 88. .88 8 | # dP `8888P88 88Y888P' `88888P' `8888P88 dP `88888P8 88Y888P' dP dP `8888P88 9 | # .88 88 .88 88 .88 10 | # d8888P dP d8888P dP d8888P 11 | 12 | Utils.insertCSS( 13 | """ 14 | @font-face { 15 | font-family: "Roboto"; 16 | src: url("modules/md-fonts/Roboto-Regular.ttf"); 17 | """) 18 | 19 | class exports.Headline extends TextLayer 20 | constructor: (options) -> 21 | super _.defaults options, 22 | name: '.' 23 | fontFamily: 'Roboto' 24 | fontSize: 24 25 | fontWeight: 400 26 | lineHeight: 1.3 27 | color: 'rgba(0,0,0,.87)' 28 | 29 | class exports.Subhead extends TextLayer 30 | constructor: (options) -> 31 | super _.defaults options, 32 | name: '.' 33 | fontFamily: 'Roboto' 34 | fontSize: 16 35 | fontWeight: 400, 36 | lineHeight: 1.5, 37 | color: 'rgba(0,0,0,.54)' 38 | 39 | class exports.Title extends TextLayer 40 | constructor: (options) -> 41 | super _.defaults options, 42 | name: '.' 43 | fontFamily: 'Roboto' 44 | fontSize: 20 45 | fontWeight: 500 46 | lineHeight: 1.3 47 | color: 'rgba(0,0,0,.87)' 48 | class exports.Regular extends TextLayer 49 | constructor: (options) -> 50 | super _.defaults options, 51 | name: '.' 52 | fontFamily: 'Roboto' 53 | fontSize: 16 54 | fontWeight: 400 55 | lineHeight: 1.3 56 | color: 'rgba(0,0,0,.87)' 57 | class exports.Body2 extends TextLayer 58 | constructor: (options) -> 59 | super _.defaults options, 60 | name: '.' 61 | fontFamily: 'Roboto' 62 | fontSize: 14 63 | fontWeight: 500 64 | lineHeight: 1.3 65 | color: 'rgba(0,0,0,.87)' 66 | class exports.Menu extends TextLayer 67 | constructor: (options) -> 68 | super _.defaults options, 69 | name: '.' 70 | fontFamily: 'Roboto' 71 | fontSize: 14 72 | fontWeight: 500 73 | lineHeight: 1.7 74 | color: 'rgba(0,0,0,.87)' 75 | class exports.Body1 extends TextLayer 76 | constructor: (options) -> 77 | super _.defaults options, 78 | name: '.' 79 | fontFamily: 'Roboto' 80 | fontSize: 14 81 | fontWeight: 400 82 | lineHeight: 1.4 83 | color: 'rgba(0,0,0,.87)' 84 | class exports.Caption extends TextLayer 85 | constructor: (options) -> 86 | super _.defaults options, 87 | name: '.' 88 | fontFamily: 'Roboto' 89 | fontSize: 12 90 | fontWeight: 400 91 | lineHeight: 1.3 92 | color: 'rgba(0,0,0,.54)' 93 | class exports.Button extends TextLayer 94 | constructor: (options) -> 95 | super _.defaults options, 96 | name: '.' 97 | fontFamily: 'Roboto' 98 | fontSize: 14 99 | fontWeight: 500 100 | lineHeight: 1.3 101 | color: '#009688' 102 | letterSpacing: 0.5 103 | padding: {left: 4, right: 4, top: 8, bottom: 0}, -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-components/View.coffee: -------------------------------------------------------------------------------- 1 | # dP dP oo 2 | # 88 88 3 | # 88 .8P dP .d8888b. dP dP dP 4 | # 88 d8' 88 88ooood8 88 88 88 5 | # 88 .d8P 88 88. ... 88.88b.88' 6 | # 888888' dP `88888P' 8888P Y8P 7 | 8 | # Works without an app, but will integrate with app if set with options.app. 9 | 10 | { Theme } = require 'md-components/Theme' 11 | { Page } = require 'md-components/Page' 12 | 13 | exports.View = class View extends Page 14 | constructor: (options = {}) -> 15 | 16 | { app } = require 'md-components/App' 17 | 18 | @_icon = options.icon ? 'open-in-new' 19 | 20 | options.title ?= 'New View' 21 | options.icon = 'menu' 22 | options.action = -> app.showMenu() 23 | 24 | super options 25 | 26 | app.addView 27 | title: options.title 28 | icon: @_icon 29 | view: @ -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-Black.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-Thin.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-fonts/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-fonts/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-images/Group.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 12:30 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-images/keyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-images/keyboard.png -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-images/nav_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-images/nav_bar.png -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-images/status_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-app.framer/modules/md-images/status_bar.png -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md-images/status_bar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | time 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 12:30 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /framer-md-app.framer/modules/md.coffee: -------------------------------------------------------------------------------- 1 | 2 | Framer.Extras.Hints.disable() 3 | 4 | 5 | { ActionButton } = require 'md-components/ActionButton' 6 | { App } = require 'md-components/App' 7 | { BottomNav } = require 'md-components/BottomNav' 8 | { Button } = require 'md-components/Button' 9 | { Card } = require 'md-components/Card' 10 | { Checkbox } = require 'md-components/Checkbox' 11 | { Dialog } = require 'md-components/Dialog' 12 | { Divider } = require 'md-components/Divider' 13 | { Dropdown } = require 'md-components/Dropdown' 14 | { Elevation } = require 'md-components/Elevation' 15 | App = require 'md-components/App' 16 | { GridList } = require 'md-components/GridList' 17 | { Header } = require 'md-components/Header' 18 | { Icon } = require 'md-components/Icon' 19 | { MenuButton } = require 'md-components/MenuButton' 20 | { MenuOverlay } = require 'md-components/MenuOverlay' 21 | { Notification } = require 'md-components/Notification' 22 | { Page } = require 'md-components/Page' 23 | { Radiobox } = require 'md-components/Radiobox' 24 | { Ripple } = require 'md-components/Ripple' 25 | { RowItem } = require 'md-components/RowItem' 26 | { Select } = require 'md-components/Select' 27 | { Slider } = require 'md-components/Slider' 28 | { Snackbar } = require 'md-components/Snackbar' 29 | { StatusBar } = require 'md-components/StatusBar' 30 | { StackView } = require 'md-components/StackView' 31 | { Switch } = require 'md-components/Switch' 32 | { Table } = require 'md-components/Table' 33 | { TableCard } = require 'md-components/TableCard' 34 | { TextArea } = require 'md-components/TextArea' 35 | { TextField } = require 'md-components/TextField' 36 | { Theme } = require 'md-components/Theme' 37 | { Toast } = require 'md-components/Toast' 38 | Type = require 'md-components/Type' 39 | { Tile } = require 'md-components/Tile' 40 | { View } = require 'md-components/View' 41 | 42 | exports.ActionButton = ActionButton 43 | exports.App = App 44 | exports.Button = Button 45 | exports.Card = Card 46 | exports.Checkbox = Checkbox 47 | exports.Dialog = Dialog 48 | exports.Divider = Divider 49 | exports.Dropdown = Dropdown 50 | exports.Elevation = Elevation 51 | exports.App = App.App 52 | exports.app = App.app 53 | exports.GridList = GridList 54 | exports.Header = Header 55 | exports.Icon = Icon 56 | exports.MenuButton = MenuButton 57 | exports.MenuOverlay = MenuOverlay 58 | exports.Notification = Notification 59 | exports.Page = Page 60 | exports.Radiobox = Radiobox 61 | exports.Ripple = Ripple 62 | exports.RowItem = RowItem 63 | exports.Select = Select 64 | exports.Slider = Slider 65 | exports.Snackbar = Snackbar 66 | exports.StackView = StackView 67 | exports.StatusBar = StatusBar 68 | exports.Switch = Switch 69 | exports.Table = Table 70 | exports.TableCard = TableCard 71 | exports.TextArea = TextArea 72 | exports.TextField = TextField 73 | exports.Theme = Theme 74 | exports.Toast = Toast 75 | exports.Tile = Tile 76 | exports.Type = Type 77 | exports.View = View 78 | 79 | exports.Headline = Type.Headline 80 | exports.Subhead = Type.Subhead 81 | exports.Title = Type.Title 82 | exports.Regular = Type.Regular 83 | exports.Menu = Type.Menu 84 | exports.Body1 = Type.Body1 85 | exports.Body2 = Type.Body2 86 | exports.Caption = Type.Caption 87 | 88 | loading_screen?.destroy() 89 | color_pallette?.destroy() 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /framer-md-dev.framer/..social.html.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/..social.html.icloud -------------------------------------------------------------------------------- /framer-md-dev.framer/..viewer 2.html.icloud: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/..viewer 2.html.icloud -------------------------------------------------------------------------------- /framer-md-dev.framer/.gitignore: -------------------------------------------------------------------------------- 1 | # Framer Git Ignore 2 | 3 | # General OSX 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | # Framer Specific 31 | .*.html 32 | .app.js 33 | framer/*.old* 34 | framer/.*.hash 35 | framer/backup.coffee 36 | framer/backups/* 37 | framer/manifest.txt 38 | framer/preview.png 39 | framer/social-*x*.png 40 | -------------------------------------------------------------------------------- /framer-md-dev.framer/app.coffee: -------------------------------------------------------------------------------- 1 | ### Notes / Todo 2 | 3 | REFERENCE: 4 | https://material.io/guidelines/ 5 | https://materialdesignicons.com/ 6 | 7 | ### 8 | 9 | md = require "md" 10 | Screen.backgroundColor = '#FFF' 11 | 12 | header = new md.Header 13 | icon: 'menu' 14 | title: 'Hello World!' 15 | action: -> print 'hello' 16 | 17 | header.icon = 'star' 18 | 19 | Utils.delay 3, => 20 | header.setHeader 21 | title: 'whaddup world' 22 | action: -> print 'whaddup' 23 | backgroundColor: 'FF0077' 24 | 25 | # app = new md.App 26 | # name: 'Framer Introduction' 27 | 28 | # ################################### 29 | # Pages 30 | 31 | # refactored: 32 | 33 | # Button 34 | # Notification 35 | # StackView 36 | # Card 37 | # View 38 | # Snackbar 39 | # Toast 40 | 41 | 42 | # to do: 43 | 44 | # Text Inputs 45 | # combine into a single class - wrap everything in a container layer, so that I can adjus height depending on whether label or helpertext exists. 46 | 47 | 48 | # Home 49 | 50 | # home = new md.View 51 | # title: 'Refactoring!' 52 | # icon: 'home' 53 | # showLayers: true 54 | # 55 | # home.build -> 56 | # @addToStack new md.Button 57 | # action: -> new md.Toast 58 | # 59 | # app.showNext(home) 60 | 61 | # myView = new md.View 62 | # 63 | # app.showNext(myView) 64 | -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/.bookmark: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/.bookmark -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "orientation" : 0, 3 | "updateDelay" : 0.3, 4 | "designModeSelected" : 0, 5 | "cachedDeviceHeight" : 640, 6 | "contentScale" : 1, 7 | "cachedDeviceWidth" : 360, 8 | "fullScreen" : false, 9 | "deviceType" : "google-nexus-5x", 10 | "sharedPrototype" : true, 11 | "propertyPanelToggleStates" : { 12 | 13 | }, 14 | "projectId" : "21022926-504E-444C-B827-2ABD14EAC5FE", 15 | "deviceOrientation" : 0, 16 | "selectedHand" : "", 17 | "showBezel" : false, 18 | "foldedCodeRanges" : [ 19 | 20 | ], 21 | "deviceScale" : "fit" 22 | } -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/framer.generated.js: -------------------------------------------------------------------------------- 1 | // This is autogenerated by Framer 2 | 3 | 4 | if (!window.Framer && window._bridge) {window._bridge('runtime.error', {message:'[framer.js] Framer library missing or corrupt. Select File → Update Framer Library.'})} 5 | if (DeviceComponent) {DeviceComponent.Devices["iphone-6-silver"].deviceImageJP2 = false}; 6 | if (window.Framer) {window.Framer.Defaults.DeviceView = {"deviceScale":"fit","selectedHand":"","deviceType":"google-nexus-5x","contentScale":1,"hideBezel":true,"orientation":0}; 7 | } 8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":"fit","selectedHand":"","deviceType":"google-nexus-5x","contentScale":1,"hideBezel":true,"orientation":0}; 9 | } 10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"framer-md-dev.framer"}; 11 | 12 | Framer.Device = new Framer.DeviceView(); 13 | Framer.Device.setupContext(); -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/framer.init.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | function isFileLoadingAllowed() { 4 | return (window.location.protocol.indexOf("file") == -1) 5 | } 6 | 7 | function isHomeScreened() { 8 | return ("standalone" in window.navigator) && window.navigator.standalone == true 9 | } 10 | 11 | function isCompatibleBrowser() { 12 | return Utils.isWebKit() 13 | } 14 | 15 | var alertNode; 16 | 17 | function dismissAlert() { 18 | alertNode.parentElement.removeChild(alertNode) 19 | loadProject() 20 | } 21 | 22 | function showAlert(html) { 23 | 24 | alertNode = document.createElement("div") 25 | 26 | alertNode.classList.add("framerAlertBackground") 27 | alertNode.innerHTML = html 28 | 29 | document.addEventListener("DOMContentLoaded", function(event) { 30 | document.body.appendChild(alertNode) 31 | }) 32 | 33 | window.dismissAlert = dismissAlert; 34 | } 35 | 36 | function showBrowserAlert() { 37 | var html = "" 38 | html += "
" 39 | html += "Error: Not A WebKit Browser" 40 | html += "Your browser is not supported.
Please use Safari or Chrome.
" 41 | html += "Try anyway" 42 | html += "
" 43 | 44 | showAlert(html) 45 | } 46 | 47 | function showFileLoadingAlert() { 48 | var html = "" 49 | html += "
" 50 | html += "Error: Local File Restrictions" 51 | html += "Preview this prototype with Framer Mirror or learn more about " 52 | html += "file restrictions.
" 53 | html += "Try anyway" 54 | html += "
" 55 | 56 | showAlert(html) 57 | } 58 | 59 | function loadProject(callback) { 60 | CoffeeScript.load("app.coffee", callback) 61 | } 62 | 63 | function setDefaultPageTitle() { 64 | // If no title was set we set it to the project folder name so 65 | // you get a nice name on iOS if you bookmark to desktop. 66 | document.addEventListener("DOMContentLoaded", function() { 67 | if (document.title == "") { 68 | if (window.FramerStudioInfo && window.FramerStudioInfo.documentTitle) { 69 | document.title = window.FramerStudioInfo.documentTitle 70 | } else { 71 | document.title = window.location.pathname.replace(/\//g, "") 72 | } 73 | } 74 | }) 75 | } 76 | 77 | function init() { 78 | 79 | if (Utils.isFramerStudio()) { 80 | return 81 | } 82 | 83 | setDefaultPageTitle() 84 | 85 | if (!isCompatibleBrowser()) { 86 | return showBrowserAlert() 87 | } 88 | 89 | if (!isFileLoadingAllowed()) { 90 | return showFileLoadingAlert() 91 | } 92 | 93 | loadProject(function(){ 94 | // CoffeeScript: Framer?.CurrentContext?.emit?("loaded:project") 95 | var context; 96 | if (typeof Framer !== "undefined" && Framer !== null) { 97 | if ((context = Framer.CurrentContext) != null) { 98 | if (typeof context.emit === "function") { 99 | context.emit("loaded:project"); 100 | } 101 | } 102 | } 103 | }) 104 | } 105 | 106 | init() 107 | 108 | })() 109 | -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/images/cursor-active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/images/cursor-active.png -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/images/cursor-active@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/images/cursor-active@2x.png -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/images/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/images/cursor.png -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/images/cursor@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/images/cursor@2x.png -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/images/icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/images/icon-120.png -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/images/icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/images/icon-152.png -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/images/icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/images/icon-180.png -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/images/icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/images/icon-192.png -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/images/icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/framer/images/icon-76.png -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | border: none; 5 | -webkit-user-select: none; 6 | -webkit-tap-highlight-color: rgba(0,0,0,0); 7 | } 8 | 9 | body { 10 | background-color: #fff; 11 | font: 28px/1em "Helvetica"; 12 | color: gray; 13 | overflow: hidden; 14 | } 15 | 16 | a { 17 | color: gray; 18 | } 19 | 20 | body { 21 | cursor: url('images/cursor.png') 32 32, auto; 22 | cursor: -webkit-image-set( 23 | url('images/cursor.png') 1x, 24 | url('images/cursor@2x.png') 2x 25 | ) 32 32, auto; 26 | } 27 | 28 | body:active { 29 | cursor: url('images/cursor-active.png') 32 32, auto; 30 | cursor: -webkit-image-set( 31 | url('images/cursor-active.png') 1x, 32 | url('images/cursor-active@2x.png') 2x 33 | ) 32 32, auto; 34 | } 35 | 36 | .framerAlertBackground { 37 | position: absolute; top:0px; left:0px; right:0px; bottom:0px; 38 | z-index: 1000; 39 | background-color: #fff; 40 | } 41 | 42 | .framerAlert { 43 | font:400 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif; 44 | -webkit-font-smoothing:antialiased; 45 | color:#616367; text-align:center; 46 | position: absolute; top:40%; left:50%; width:260px; margin-left:-130px; 47 | } 48 | .framerAlert strong { font-weight:500; color:#000; margin-bottom:8px; display:block; } 49 | .framerAlert a { color:#28AFFA; } 50 | .framerAlert .btn { 51 | font-weight:500; text-decoration:none; line-height:1; 52 | display:inline-block; padding:6px 12px 7px 12px; 53 | border-radius:3px; margin-top:12px; 54 | background:#28AFFA; color:#fff; 55 | } 56 | 57 | ::-webkit-scrollbar { 58 | display: none; 59 | } -------------------------------------------------------------------------------- /framer-md-dev.framer/framer/version: -------------------------------------------------------------------------------- 1 | 10 -------------------------------------------------------------------------------- /framer-md-dev.framer/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/images/.gitkeep -------------------------------------------------------------------------------- /framer-md-dev.framer/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/ActionButton.coffee: -------------------------------------------------------------------------------- 1 | # .d888888 dP oo 888888ba dP dP 2 | # d8' 88 88 88 `8b 88 88 3 | # 88aaaaa88a .d8888b. d8888P dP .d8888b. 88d888b. a88aaaa8P' dP dP d8888P d8888P .d8888b. 88d888b. 4 | # 88 88 88' `"" 88 88 88' `88 88' `88 88 `8b. 88 88 88 88 88' `88 88' `88 5 | # 88 88 88. ... 88 88 88. .88 88 88 88 .88 88. .88 88 88 88. .88 88 88 6 | # 88 88 `88888P' dP dP `88888P' dP dP 88888888P `88888P' dP dP `88888P' dP dP 7 | 8 | { Ripple } = require 'md-components/Ripple' 9 | { Icon } = require 'md-components/Icon' 10 | { Theme } = require 'md-components/Theme' 11 | 12 | exports.ActionButton = class ActionButton extends Layer 13 | constructor: (options = {}) -> 14 | 15 | @_action = options.action ? -> null 16 | @_icon = options.icon ? 'plus' 17 | 18 | { app } = require 'md-components/App' 19 | 20 | super _.defaults options, 21 | name: 'Action Button' 22 | x: Align.right(-16), y: Align.bottom(-17) 23 | width: 64, height: 64, borderRadius: 32 24 | backgroundColor: Theme.fab.backgroundColor 25 | shadowY: 2, shadowBlur: 3 26 | shadowColor: 'rgba(0,0,0,.25)' 27 | animationOptions: {time: .15} 28 | 29 | if app? 30 | @y = Align.bottom(-app.footer.height - 17) 31 | app.actionButton = @ 32 | 33 | # icon 34 | 35 | @iconLayer = new Icon 36 | name: '.', parent: @ 37 | x: Align.center, y: Align.center 38 | icon: @_icon, 39 | color: Theme.fab.color 40 | 41 | # mask 42 | 43 | @mask = new Layer 44 | parent: @ 45 | size: @size 46 | backgroundColor: null 47 | borderRadius: @borderRadius 48 | clip: true 49 | opacity: 1 50 | 51 | @mask.placeBehind @iconLayer 52 | @ripple = new Ripple( @mask, null ) 53 | 54 | # events 55 | 56 | @onTouchStart (event) -> 57 | @showTouched() 58 | Utils.delay 1, => @reset() 59 | 60 | @onTouchEnd (event) -> 61 | @_action() 62 | @reset() 63 | 64 | showTouched: -> 65 | @animate {shadowY: 3, shadowSpread: 1} 66 | 67 | reset: -> 68 | @animate 69 | shadowY: 2 70 | shadowSpread: 0 71 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/App.coffee: -------------------------------------------------------------------------------- 1 | # .d888888 2 | # d8' 88 3 | # 88aaaaa88a 88d888b. 88d888b. 4 | # 88 88 88' `88 88' `88 5 | # 88 88 88. .88 88. .88 6 | # 88 88 88Y888P' 88Y888P' 7 | # 88 88 8 | # dP dP 9 | 10 | { Header } = require 'md-components/Header' 11 | { BottomNav } = require 'md-components/BottomNav' 12 | { MenuOverlay } = require 'md-components/MenuOverlay' 13 | { Theme } = require 'md-components/Theme' 14 | 15 | exports.app # set by class 16 | 17 | class exports.App extends FlowComponent 18 | constructor: (options = {}) -> 19 | @__constructor = true 20 | 21 | exports.app = @ 22 | 23 | @activeInput 24 | @header 25 | @keyboard 26 | 27 | @notifications = [] 28 | 29 | super _.defaults options, 30 | name: 'App' 31 | 32 | # Header 33 | 34 | @header = new Header 35 | title: '' 36 | icon: '' 37 | 38 | # Keyboard 39 | 40 | @keyboard = new Layer 41 | name: 'Keyboard' 42 | y: @maxY, image: Theme.keyboard.image 43 | width: @width, height: 222 44 | index: 1000 45 | animationOptions: 46 | time: .25 47 | 48 | @keyboard.onTap @closeKeyboard 49 | 50 | # App Footer 51 | 52 | @footer = new Layer 53 | name: 'Footer' 54 | width: Screen.width, height: 48 55 | image: Theme.footer.image 56 | index: 999 57 | y: Align.bottom() 58 | clip: true 59 | 60 | flash = undefined 61 | 62 | @backButton = new Layer 63 | name: 'Back Button', parent: @footer 64 | x: 56 65 | width: 40, height: 40, borderRadius: 24 66 | opacity: 0, backgroundColor: 'rgba(255, 255, 255, .2)' 67 | animationOptions: {time: .15} 68 | 69 | @backButton.onTapStart => 70 | flash?.destroy() 71 | flash = @backButton.copy() 72 | flash.ignoreEvents = true 73 | flash.parent = @footer 74 | flash.animate {x: 32, width: 100, y: 0, height: 48, opacity: 1} 75 | 76 | @backButton.onTap => 77 | flash?.animateStop() 78 | flash?.animate {opacity: 0, options:{time: .5}} 79 | return if @current.constructor.name is 'View' 80 | @showPrevious() 81 | 82 | @menuOverlay = new MenuOverlay 83 | title: @name 84 | 85 | # Transition Events 86 | 87 | @onTransitionStart (prev, next, direction) => 88 | Utils.delay 0, => @onChange(next) 89 | 90 | # On changing to a new page 91 | 92 | onChange: (next) -> 93 | return if typeof next is 'string' 94 | if !_.includes(['View', 'Page'], next.constructor?.name) 95 | throw 'App only words with Views and Pages.' 96 | return 97 | 98 | @setHeader(next.headerOptions) 99 | next.contentInset.top = @header.maxY + 16 100 | 101 | next.scrollY = 0 102 | next.onLoad() 103 | 104 | # Transitions 105 | 106 | showNextRight: (nav, layerA, layerB, overlay) -> 107 | options = {curve: "spring(300, 35, 0)"} 108 | 109 | transition = 110 | layerA: 111 | show: {options: options, x: 0, y: 0} 112 | hide: {options: options, x: 0 - layerA?.width / 2, y: 0} 113 | layerB: 114 | show: {options: options, x: 0, y: 0} 115 | hide: {options: options, x: layerB.width, y: 0} 116 | 117 | showNextLeft: (nav, layerA, layerB, overlay) -> 118 | options = {curve: "spring(300, 35, 0)"} 119 | 120 | transition = 121 | layerA: 122 | show: {options: options, x: 0, y: 0} 123 | hide: {options: options, x: 0 + layerA?.width / 2, y: 0} 124 | layerB: 125 | show: {options: options, x: 0, y: 0} 126 | hide: {options: options, x: -layerB.width, y: 0} 127 | 128 | # keyboard 129 | 130 | openKeyboard: () => 131 | @footer.visible = false 132 | return if Utils.isMobile() 133 | 134 | @keyboard.bringToFront() 135 | @animate { y: -@keyboard.height } 136 | @keyboard.animate { y: Screen.height - @keyboard.height } 137 | 138 | closeKeyboard: => 139 | @footer.visible = true 140 | @animate { y: 0 } 141 | @keyboard.animate { y: Screen.height } 142 | 143 | # menu 144 | 145 | showMenu: -> 146 | @menuOverlay.show() 147 | 148 | hideMenu: -> 149 | @menuOverlay.hide() 150 | 151 | # header 152 | 153 | setHeader: (options = {}) -> 154 | @header.setHeader(options) 155 | 156 | # add view 157 | 158 | addView: (options = {}) -> 159 | @menuOverlay.addLink(options) 160 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/BottomNav.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP dP 888888ba 2 | # 88 `8b 88 88 88 `8b 3 | # a88aaaa8P' .d8888b. d8888P d8888P .d8888b. 88d8b.d8b. 88 88 .d8888b. dP .dP 4 | # 88 `8b. 88' `88 88 88 88' `88 88'`88'`88 88 88 88' `88 88 d8' 5 | # 88 .88 88. .88 88 88 88. .88 88 88 88 88 88 88. .88 88 .88' 6 | # 88888888P `88888P' dP dP `88888P' dP dP dP dP dP `88888P8 8888P' 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Icon } = require 'md-components/Icon' 11 | { Theme } = require 'md-components/Theme' 12 | 13 | exports.BottomNav = class BottomNav extends Layer 14 | constructor: (options = {}) -> 15 | 16 | @_destinations = options.destinations ? throw 'Needs at least one destination.' 17 | @_items = [] 18 | @_initialDestination = options.initialDestination ? undefined 19 | # destination should be: [{name: string, icon: iconString, action: function}] 20 | @_activeDestination = @_initialDestination ? @_items[0] 21 | @_app = options.app 22 | @view = options.view 23 | 24 | super _.defaults options, 25 | name: 'Bottom Nav' 26 | y: Align.bottom 27 | width: Screen.width, height: 56 28 | backgroundColor: Theme.bottomNav.backgroundColor 29 | shadowY: Theme.bottomNav.shadowY 30 | shadowBlur: Theme.bottomNav.shadowBlur 31 | shadowColor: Theme.bottomNav.shadowColor 32 | clip: true 33 | 34 | for destination, i in @_destinations 35 | 36 | item = new Layer 37 | name: '.', parent: @ 38 | x: @width/@_destinations.length * i 39 | width: @width/@_destinations.length, height: @height 40 | color: Theme.primary 41 | backgroundColor: null 42 | 43 | nav = @ 44 | 45 | do _.bind( -> 46 | 47 | @mask = new Layer 48 | parent: @ 49 | x: Align.center, y: Align.center() 50 | height: @height * 1.72 51 | width: @height * 1.7 52 | borderRadius: @height 53 | backgroundColor: null 54 | clip: true 55 | opacity: 1 56 | 57 | @ripple = new Ripple( @mask , external = true, undefined, events = false) 58 | 59 | @iconLayer = new Icon 60 | name: '.', parent: @ 61 | x: Align.center, y: Align.center(-8) 62 | icon: destination.icon 63 | animationOptions: {time: .15} 64 | 65 | @labelLayer = new Type.Caption 66 | name: '.', parent: @ 67 | x: Align.center, y: Align.center(14) 68 | width: @width, 69 | textAlign: 'center' 70 | text: destination.title 71 | animationOptions: {time: .15} 72 | 73 | # set events on entire item 74 | @onTapStart ( event ) => @ripple.show( event.point ) 75 | @onTapEnd @ripple.hide 76 | @onPanEnd @ripple.hide 77 | 78 | @view = destination.view 79 | 80 | @onTap -> nav._app.changeView(@view) 81 | 82 | , item) 83 | 84 | @_items.push(item) 85 | 86 | @showActive(@_items[0]) 87 | 88 | @define "activeDestination", 89 | get: -> return @_activeDestination 90 | set: (destination) -> 91 | return if destination is @_activeDestination 92 | @_activeDestination = destination 93 | 94 | @showActive(@_activeDestination) 95 | 96 | @_app.changeView(@_activeDestination.view) 97 | 98 | showActive: (item) -> 99 | item.labelLayer.animate {color: Theme.primary, opacity: 1} 100 | item.iconLayer.color = Theme.primary 101 | 102 | for sib in item.siblings 103 | sib.labelLayer.animate {color: '#777'} 104 | sib.iconLayer.color = '#777' -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Button.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP dP 2 | # 88 `8b 88 88 3 | # a88aaaa8P' dP dP d8888P d8888P .d8888b. 88d888b. 4 | # 88 `8b. 88 88 88 88 88' `88 88' `88 5 | # 88 .88 88. .88 88 88 88. .88 88 88 6 | # 88888888P `88888P' dP dP `88888P' dP dP 7 | 8 | 9 | Type = require 'md-components/Type' 10 | { Ripple } = require 'md-components/Ripple' 11 | { Icon } = require 'md-components/Icon' 12 | { Theme } = require 'md-components/Theme' 13 | 14 | exports.Button = class Button extends Layer 15 | constructor: (options = {}) -> 16 | @__constructor = true 17 | showLayers = options.showLayers 18 | 19 | # if an icon is passed in, return an icon class and bail 20 | if options.icon 21 | options.action ?= -> null 22 | options.color ?= Theme.colors.primary.main 23 | return new Icon(options) 24 | 25 | @_disabled 26 | @_action 27 | @_raised 28 | @_type 29 | @_base 30 | @_labelText 31 | 32 | @_explicitWidth = options.width? 33 | @_startX = options.x 34 | 35 | @_type = options.type ? if options.raised then 'raised' else 'flat' 36 | 37 | # properties by type 38 | switch @_type 39 | when 'flat' 40 | @_base = 41 | name: 'Flat Button' 42 | height: 36 43 | width: 999 44 | borderRadius: 2 45 | backgroundColor: null 46 | color: Theme.colors.secondary.main 47 | shadowY: 0 48 | shadowColor: 'rgba(0,0,0,.26)' 49 | shadowBlur: 0 50 | animationOptions: {time: .15} 51 | when 'raised' 52 | @_base = 53 | name: 'Raised Button' 54 | height: 36 55 | width: 999 56 | borderRadius: 2 57 | backgroundColor: Theme.colors.secondary.main 58 | color: Theme.colors.secondary.text 59 | shadowY: 2 60 | shadowColor: 'rgba(0,0,0,.26)' 61 | shadowBlur: 4 62 | animationOptions: {time: .15} 63 | 64 | super _.defaults options, @_base 65 | 66 | # text label 67 | @labelLayer = new Type.Button 68 | name: if showLayers then 'Label' else '.' 69 | parent: @ 70 | height: 36 71 | text: '{labelText}' 72 | textTransform: 'uppercase' 73 | textAlign: 'center' 74 | color: @color 75 | animationOptions: {time: .15} 76 | padding: 77 | left: 16.5, right: 16.5 78 | top: 9, bottom: 11 79 | 80 | # events 81 | @onTapStart -> 82 | @showRaised() 83 | 84 | @onTapEnd -> 85 | return if @_disabled 86 | @_action() 87 | @refresh() 88 | 89 | @labelLayer.on "change:width", => 90 | return if @_explicitWidth 91 | @width = @labelLayer.width 92 | @_base.width = @labelLayer.width 93 | @setRipple() 94 | 95 | @on "change:width", => 96 | return if @width is @labelLayer.width 97 | @labelLayer.width = @width 98 | @setRipple() 99 | 100 | # set props 101 | @action = options.action 102 | @disabled = options.disabled ? false 103 | 104 | delete @__constructor 105 | 106 | @text = options.text ? 'button' 107 | 108 | showRaised: => 109 | return if @disabled 110 | return if @type isnt 'raised' 111 | @animate {shadowY: 5, shadowBlur: 8} 112 | 113 | setRipple: -> 114 | @mask?.destroy() 115 | 116 | @mask = new Layer 117 | parent: @ 118 | size: @size 119 | backgroundColor: null 120 | borderRadius: 2 121 | clip: true 122 | opacity: 1 123 | 124 | @mask.placeBehind @labelLayer 125 | 126 | switch @type 127 | when 'flat' 128 | @ripple = new Ripple( @mask, null, colorOverride = 'rgba(0,0,0,.05)' ) 129 | when 'raised' 130 | @ripple = new Ripple( @mask, null ) 131 | 132 | refresh: => 133 | @animateStop() 134 | if @disabled 135 | if @type is 'raised' 136 | @animate 137 | backgroundColor: 'rgba(0,0,0,.12)' 138 | shadowY: 0 139 | shadowBlur: 0 140 | @labelLayer.animate 141 | color: 'rgba(0,0,0,.26)' 142 | else 143 | @animate @_base 144 | @labelLayer.animate 145 | color: @_base.color 146 | 147 | @define "type", 148 | get: -> return @_type 149 | 150 | @define "disabled", 151 | get: -> return @_disabled 152 | set: (bool = false) -> 153 | return if bool is @_disabled 154 | @_disabled = bool 155 | 156 | @emit("change:disabled", @_disabled, @) 157 | 158 | return if @__constructor 159 | @refresh() 160 | 161 | @define "action", 162 | get: -> return @_action 163 | set: (func = -> null) -> 164 | return if func is @_action 165 | @_action = func 166 | 167 | @define "text", 168 | get: -> return @_labelText 169 | set: (text = '') -> 170 | return if @__constructor 171 | @_labelText = text 172 | 173 | @labelLayer.visible = text.length > 0 174 | @labelLayer.template = text 175 | 176 | @x = @_startX 177 | @refresh() -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Checkbox.coffee: -------------------------------------------------------------------------------- 1 | # a88888b. dP dP dP 2 | # d8' `88 88 88 88 3 | # 88 88d888b. .d8888b. .d8888b. 88 .dP 88d888b. .d8888b. dP. .dP 4 | # 88 88' `88 88ooood8 88' `"" 88888" 88' `88 88' `88 `8bd8' 5 | # Y8. .88 88 88 88. ... 88. ... 88 `8b. 88. .88 88. .88 .d88b. 6 | # Y88888P' dP dP `88888P' `88888P' dP `YP 88Y8888' `88888P' dP' `dP 7 | 8 | { Icon } = require 'md-components/Icon' 9 | { Theme } = require 'md-components/Theme' 10 | 11 | exports.Checkbox = CheckBox = class Checkbox extends Icon 12 | constructor: (options = {}) -> 13 | 14 | @_group = undefined 15 | 16 | super _.defaults options, 17 | name: '.' 18 | animationOptions: {time: .15} 19 | icon: 'checkbox-blank-outline' 20 | color: Theme.primary 21 | toggle: true 22 | action: -> null 23 | 24 | @on "change:isOn", @updateIcon 25 | 26 | updateIcon: => 27 | @icon = if @isOn then 'checkbox-marked' else 'checkbox-blank-outline' 28 | 29 | @define "group", 30 | get: -> return @_group 31 | set: (array) -> 32 | return if array is @_group 33 | @_group = array 34 | 35 | # add this checkbox to the group array if not in it already 36 | if not _.includes(@_group, @) then @_group.push(@) -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Dialog.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba oo dP 2 | # 88 `8b 88 3 | # 88 88 dP .d8888b. 88 .d8888b. .d8888b. 4 | # 88 88 88 88' `88 88 88' `88 88' `88 5 | # 88 .8P 88 88. .88 88 88. .88 88. .88 6 | # 8888888P dP `88888P8 dP `88888P' `8888P88 7 | # .88 8 | # d8888P 9 | 10 | Type = require 'md-components/Type' 11 | { Icon } = require 'md-components/Icon' 12 | { Theme } = require 'md-components/Theme' 13 | { Button } = require 'md-components/Button' 14 | 15 | # simplify: create an actions array, with text, action, color? 16 | # this needs to be standardized across apis 17 | 18 | exports.Dialog = class Dialog extends Layer 19 | constructor: (options = {}) -> 20 | 21 | showLayers = options.showLayers ? false 22 | 23 | @_title = options.title ? 'Default Title' 24 | @_body = options.body ? 'Body text goes here.' 25 | @_acceptText = options.acceptText ? 'confirm' 26 | @_acceptAction = options.acceptAction ? -> null 27 | @_declineText = options.declineText ? '' 28 | @_declineAction = options.declineAction ? -> null 29 | 30 | super _.defaults options, 31 | name: if showLayers then 'Dialog' else '.' 32 | size: Screen.size 33 | backgroundColor: 'rgba(0, 0, 0, .5)' 34 | opacity: 0 35 | 36 | @on Events.Tap, (event) -> event.stopPropagation() 37 | 38 | @container = new Layer 39 | name: 'container', parent: @ 40 | x: Align.center 41 | height: 128, width: Screen.width - 80 42 | backgroundColor: Theme.dialog.backgroundColor 43 | shadowX: 0, shadowY: 7, shadowBlur: 30 44 | opacity: 0 45 | shadowColor: 'rgba(0,0,0,.3)' 46 | 47 | @title = new Type.Title 48 | name: '.', parent: @container 49 | x: 24, y: 20 50 | fontSize: 16, fontWeight: 500, color: Theme.text.title 51 | text: @_title 52 | 53 | @body = new Type.Subhead 54 | name: 'body', parent: @container 55 | x: 24, y: 52 56 | width: @container.width - 42 57 | text: @_body 58 | 59 | buttonsY = if @_body is '' then 128 else @body.maxY + 16 60 | 61 | @accept = new Button 62 | name: '.', parent: @container 63 | x: Align.right(-16), y: buttonsY 64 | text: @_acceptText.toUpperCase() 65 | action: @_acceptAction 66 | 67 | if @_declineText isnt '' 68 | @decline = new Button 69 | name: '.', parent: @container 70 | x: 0, y: buttonsY 71 | text: @_declineText.toUpperCase() 72 | action: @_declineAction 73 | 74 | # set positions 75 | @container.height = @accept.maxY + 12 76 | @decline?.maxX = @accept.x - 16 77 | @container.y = Align.center(16) 78 | 79 | # add close actions to confirm and cancel 80 | for button in [@accept, @decline] 81 | button?.onTap => Utils.delay .25, @close 82 | 83 | # ON LOAD 84 | @open() 85 | 86 | open: => 87 | @animate 88 | opacity: 1 89 | options: 90 | time: .25 91 | 92 | @container.animate 93 | opacity: 1 94 | options: 95 | time: .25 96 | delay: .15 97 | 98 | close: => 99 | @container.animate 100 | opacity: 0 101 | options: 102 | time: .25 103 | 104 | @animate 105 | opacity: 0 106 | options: 107 | time: .25 108 | 109 | Utils.delay .5, => @destroy() -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Divider.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba oo oo dP 2 | # 88 `8b 88 3 | # 88 88 dP dP .dP dP .d888b88 .d8888b. 88d888b. 4 | # 88 88 88 88 d8' 88 88' `88 88ooood8 88' `88 5 | # 88 .8P 88 88 .88' 88 88. .88 88. ... 88 6 | # 8888888P dP 8888P' dP `88888P8 `88888P' dP 7 | 8 | Type = require 'md-components/Type' 9 | { Theme } = require 'md-components/Theme' 10 | 11 | class exports.Divider extends Layer 12 | constructor: (options = {}) -> 13 | 14 | width = 0 # check if parent is a View and adjust to padding 15 | showLayers = options.showLayers 16 | 17 | @_labelText = undefined 18 | @_backgroundColor = options.backgroundColor 19 | 20 | options.backgroundColor = Theme.divider.backgroundColor 21 | 22 | super _.defaults options, 23 | name: if showLayers then 'Divider' else '.' 24 | width: options.parent?.width ? 200, height: 1, 25 | backgroundColor: Theme.divider.backgroundColor 26 | 27 | @labelLayer = new Type.Caption 28 | name: if showLayers then 'Label' else '.' 29 | parent: @ 30 | x: Align.center 31 | y: Align.center 32 | padding: {left: 16, right: 16} 33 | textAlign: 'center' 34 | textTransform: 'uppercase' 35 | text: '{labelText}' 36 | visible: false 37 | backgroundColor: @_backgroundColor 38 | 39 | @text = options.text 40 | 41 | @define "text", 42 | get: -> return @_labelText 43 | set: (text) -> 44 | if not text? then text = '' 45 | @_labelText = text 46 | 47 | @labelLayer?.visible = @text.length > 0 48 | @labelLayer?.template = @text 49 | @labelLayer?.x = Align.center 50 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Elevation.coffee: -------------------------------------------------------------------------------- 1 | # 88888888b dP dP oo 2 | # 88 88 88 3 | # a88aaaa 88 .d8888b. dP .dP .d8888b. d8888P dP .d8888b. 88d888b. 4 | # 88 88 88ooood8 88 d8' 88' `88 88 88 88' `88 88' `88 5 | # 88 88 88. ... 88 .88' 88. .88 88 88 88. .88 88 88 6 | # 88888888P dP `88888P' 8888P' `88888P8 dP dP `88888P' dP dP 7 | 8 | # thanks to @ma_rylou 9 | 10 | exports.Elevation = (layer, elevationnumber = 0, animate = true, options = {time: .2, curve: 'ease'}) -> 11 | 12 | # Error handling 13 | if typeof elevationnumber isnt "number" 14 | throw Error "Elevation must be a number." 15 | 16 | # Clamp elevation number to between 0 and 24 17 | elevationnumber = _.clamp(elevationnumber, 0, 24) 18 | 19 | props = 20 | shadowSpread: 0 21 | shadowX: 0 22 | shadowY: elevationnumber 23 | shadowBlur: elevationnumber 24 | shadowColor:"rgba(0, 0, 0, 0.24)" 25 | 26 | animProps = _.merge(props, {options: options}) 27 | 28 | #target layer 29 | if animate then layer.animate animProps 30 | else layer.props = props 31 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/GridList.coffee: -------------------------------------------------------------------------------- 1 | 2 | # .88888. oo dP dP oo dP 3 | # d8' `88 88 88 88 4 | # 88 88d888b. dP .d888b88 88 dP .d8888b. d8888P 5 | # 88 YP88 88' `88 88 88' `88 88 88 Y8ooooo. 88 6 | # Y8. .88 88 88 88. .88 88 88 88 88 7 | # `88888' dP dP `88888P8 88888888P dP `88888P' dP 8 | 9 | Type = require 'md-components/Type' 10 | { Ripple } = require 'md-components/Ripple' 11 | { Icon } = require 'md-components/Icon' 12 | { Theme } = require 'md-components/Theme' 13 | 14 | exports.GridList = class GridList extends Layer 15 | constructor: (options = {}) -> 16 | 17 | @_columns = options.columns ? 2 18 | 19 | super _.defaults options, 20 | name: '.' 21 | width: Screen.width 22 | backgroundColor: null 23 | 24 | @tiles = [] 25 | @tileWidth = (@width - 24) / @_columns 26 | @tileHeight = options.tileHeight ? Screen.width / @_columns 27 | 28 | addTile: (tile) -> 29 | tile.i = @tiles.length 30 | tile.gridList = @ 31 | @tiles.push(tile) 32 | 33 | tile.x = 8 + (@tileWidth + 8) * (tile.i % @_columns) 34 | tile.y = 8 + (@tileHeight + 8) * Math.floor(tile.i / @_columns) 35 | 36 | @height = _.last(@tiles).maxY 37 | 38 | if @parent?.parent?.content? then @parent.parent.updateContent() 39 | 40 | removeTile: (tile) -> 41 | _.pull(@tiles, tile) 42 | tile.destroy() 43 | @repositionTiles() 44 | 45 | repositionTiles: -> 46 | for tile, i in @tiles 47 | tile.i = i 48 | tile.animate 49 | x: 8 + (@tileWidth + 8) * (tile.i % @_columns) 50 | y: 8 + (@tileHeight + 8) * Math.floor(tile.i / @_columns) 51 | @height = _.last(@tiles).maxY 52 | 53 | if @parent?.parent?.content? then @parent.parent.updateContent() 54 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Header.coffee: -------------------------------------------------------------------------------- 1 | # dP dP dP 2 | # 88 88 88 3 | # 88aaaaa88a .d8888b. .d8888b. .d888b88 .d8888b. 88d888b. 4 | # 88 88 88ooood8 88' `88 88' `88 88ooood8 88' `88 5 | # 88 88 88. ... 88. .88 88. .88 88. ... 88 6 | # dP dP `88888P' `88888P8 `88888P8 `88888P' dP 7 | 8 | Type = require 'md-components/Type' 9 | { Icon } = require 'md-components/Icon' 10 | { Theme } = require 'md-components/Theme' 11 | { modifyColor } = require 'md-components/Theme' 12 | { StatusBar } = require 'md-components/StatusBar' 13 | 14 | exports.Header = class Header extends Layer 15 | constructor: (options = {}) -> 16 | @__constructor = true 17 | 18 | # properties 19 | 20 | @_title 21 | options.title ?= 'Header' 22 | 23 | @_icon 24 | options.icon ?= 'menu' 25 | 26 | @_action 27 | options.action ?= -> null 28 | 29 | # assign forced options 30 | _.assign options, 31 | width: Screen.width 32 | height: 80 33 | shadowY: 2, 34 | shadowBlur: 3, 35 | shadowColor: 'rgba(0,0,0,.24)' 36 | 37 | # set default options 38 | super _.defaults options, 39 | name: options.title 40 | backgroundColor: Theme.header.backgroundColor ? '#777' 41 | color: Theme.header.title ? '#FFF' 42 | 43 | # title 44 | 45 | @titleLayer = new Type.Title 46 | name: '.', parent: @ 47 | x: 72, y: Align.bottom(-14) 48 | color: @color 49 | text: '' 50 | 51 | # icon 52 | 53 | @iconLayer = new Icon 54 | name: '.', parent: @, 55 | x: 12, y: Align.center(12) 56 | icon: options.icon ? 'menu' 57 | color: @color 58 | 59 | # status bar 60 | 61 | @statusBar = new StatusBar 62 | name: '.', parent: @ 63 | 64 | # events 65 | 66 | @iconLayer.onTapEnd => @_action() 67 | 68 | @on "change:color", => 69 | @titleLayer.color = @color 70 | @iconLayer.color = @color 71 | @statusBar.color = @color 72 | 73 | @on "change:backgroundColor", => 74 | @statusBar.backgroundColor = modifyColor( 75 | @backgroundColor, -1, -7, -12 76 | ) 77 | 78 | delete @__constructor 79 | 80 | # set options that require layers 81 | 82 | @title = options.title 83 | @icon = options.icon 84 | @action = options.action 85 | 86 | setHeader: (options = {}) -> 87 | 88 | for layer in [@titleLayer, @iconLayer] 89 | layer.animate {opacity: 0, options: {time: .15}} 90 | 91 | Utils.delay .25, => 92 | 93 | _.assign(@, options) 94 | 95 | for layer in [@titleLayer, @iconLayer] 96 | layer.animate {opacity: 1, options: {time: .15}} 97 | 98 | @define "title", 99 | get: -> return @_title 100 | set: (titleText) -> 101 | return if @__constructor 102 | @_title = titleText 103 | @titleLayer.text = titleText 104 | 105 | @define "icon", 106 | get: -> return @_icon 107 | set: (iconName) -> 108 | return if @__constructor 109 | @_icon = iconName 110 | @iconLayer.icon = iconName 111 | 112 | @define "action", 113 | get: -> return @_action 114 | set: (action) -> 115 | return if @__constructor 116 | @_action = action 117 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/MenuButton.coffee: -------------------------------------------------------------------------------- 1 | # 8888ba.88ba 888888ba dP dP 2 | # 88 `8b `8b 88 `8b 88 88 3 | # 88 88 88 .d8888b. 88d888b. dP dP a88aaaa8P' dP dP d8888P d8888P .d8888b. 88d888b. 4 | # 88 88 88 88ooood8 88' `88 88 88 88 `8b. 88 88 88 88 88' `88 88' `88 5 | # 88 88 88 88. ... 88 88 88. .88 88 .88 88. .88 88 88 88. .88 88 88 6 | # dP dP dP `88888P' dP dP `88888P' 88888888P `88888P' dP dP `88888P' dP dP 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Icon } = require 'md-components/Icon' 11 | { Theme } = require 'md-components/Theme' 12 | 13 | 14 | exports.MenuButton = class MenuButton extends Layer 15 | constructor: (options = {}) -> 16 | 17 | { app } = require 'md-components/App' 18 | 19 | @_icon = options.icon ? 'home' 20 | @_text = options.text ? 'Default' 21 | @_action = options.action ? -> null 22 | @_view = options.view 23 | @_app = options.app 24 | @_i = options.i 25 | 26 | super _.defaults options, 27 | height: 48, width: 304 28 | backgroundColor: null 29 | 30 | @iconLayer = new Icon 31 | name: '.', parent: @ 32 | y: Align.center 33 | icon: @_icon, color: Theme.menuOverlay.text 34 | action: -> null 35 | 36 | @labelLayer = new Type.Regular 37 | name: 'label', parent: @ 38 | x: @iconLayer.maxX + 16 39 | y: Align.center() 40 | color: Theme.menuOverlay.text 41 | text: @_text 42 | 43 | @onTapEnd -> 44 | if @_view? 45 | if @_view.i > @_i 46 | app?.transition(@_view, app.showNextRight) 47 | else 48 | app?.transition(@_view, app.showNextLeft) 49 | Utils.delay .25, => @parent.hide() -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/MenuOverlay.coffee: -------------------------------------------------------------------------------- 1 | # 8888ba.88ba .88888. dP 2 | # 88 `8b `8b d8' `8b 88 3 | # 88 88 88 .d8888b. 88d888b. dP dP 88 88 dP .dP .d8888b. 88d888b. 88 .d8888b. dP dP 4 | # 88 88 88 88ooood8 88' `88 88 88 88 88 88 d8' 88ooood8 88' `88 88 88' `88 88 88 5 | # 88 88 88 88. ... 88 88 88. .88 Y8. .8P 88 .88' 88. ... 88 88 88. .88 88. .88 6 | # dP dP dP `88888P' dP dP `88888P' `8888P' 8888P' `88888P' dP dP `88888P8 `8888P88 7 | # .88 8 | # d8888P 9 | 10 | Type = require 'md-components/Type' 11 | { Ripple } = require 'md-components/Ripple' 12 | { Icon } = require 'md-components/Icon' 13 | { Theme } = require 'md-components/Theme' 14 | { MenuButton } = require 'md-components/MenuButton' 15 | 16 | exports.MenuOverlay = class MenuOverlay extends Layer 17 | constructor: (options = {}) -> 18 | 19 | @links = [] 20 | @_title = options.title ? 'Menu' 21 | @_image = options.image ? null 22 | @_app = options.app 23 | 24 | 25 | super _.defaults options, 26 | height: Screen.height 27 | width: 304 28 | visible: false 29 | backgroundColor: Theme.menuOverlay.backgroundColor 30 | animationOptions: {curve: "spring(300, 35, 0)"} 31 | 32 | 33 | @scrim = new Layer 34 | name: '.', 35 | size: Screen.size 36 | backgroundColor: 'rgba(0,0,0,.6)' 37 | opacity: 0 38 | visible: false 39 | animationOptions: 40 | time: .25 41 | 42 | @scrim.onTap => @hide() 43 | @onSwipeLeftEnd => @hide() 44 | 45 | @header = new Layer 46 | name: '.', parent: @ 47 | width: @width, height: 173 48 | image: Theme.user.image 49 | backgroundColor: Theme.menuOverlay.header.backgroundColor 50 | 51 | @titleIcon = new Layer 52 | name: '.', parent: @header 53 | x: 16, y: 40 54 | height: 64, width: 64 55 | borderRadius: 32 56 | backgroundColor: Theme.menuOverlay.header.icon 57 | 58 | @subheaderExpand = new Icon 59 | name: '.', parent: @header 60 | x: Align.right(-16) 61 | y: Align.bottom(-16) 62 | icon: 'menu-down' 63 | color: Theme.menuOverlay.subheader.icon 64 | 65 | @subheader = new Type.Body1 66 | name: '.', parent: @header 67 | width: @width 68 | x: 16, y: Align.bottom(-18) 69 | text: @_title 70 | color: Theme.menuOverlay.subheader.text 71 | 72 | show: -> 73 | @bringToFront() 74 | @visible = true 75 | @x = -Screen.width 76 | @animate 77 | x: 0 78 | 79 | @scrim.placeBehind(@) 80 | @scrim.visible = true 81 | @scrim.animate 82 | opacity: 1 83 | 84 | hide: -> 85 | @animate 86 | x: -Screen.width 87 | 88 | @scrim.animate 89 | opacity: 0 90 | 91 | Utils.delay .3, => 92 | @visible = false 93 | @scrim.visible = false 94 | @sendToBack() 95 | @scrim.sendToBack() 96 | 97 | addLink: (options) -> 98 | lastY = _.last(@links)?.maxY ? 189 99 | @links.push new MenuButton 100 | name: '.', parent: @ 101 | x: 16, y: lastY 102 | text: options.title 103 | icon: options.icon 104 | view: options.view 105 | 106 | options.view.i = @links.length -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Notification.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP oo .8888b oo dP oo 2 | # 88 `8b 88 88 " 88 3 | # 88 88 .d8888b. d8888P dP 88aaa dP .d8888b. .d8888b. d8888P dP .d8888b. 88d888b. 4 | # 88 88 88' `88 88 88 88 88 88' `"" 88' `88 88 88 88' `88 88' `88 5 | # 88 88 88. .88 88 88 88 88 88. ... 88. .88 88 88 88. .88 88 88 6 | # dP dP `88888P' dP dP dP dP `88888P' `88888P8 dP dP `88888P' dP dP 7 | 8 | # Notification does not require an app property, however if one is not set then notifications will not app around eachother. 9 | 10 | # TODO: replace action1 and action2 with array of actions. 11 | 12 | Type = require 'md-components/Type' 13 | { Icon } = require 'md-components/Icon' 14 | { Theme } = require 'md-components/Theme' 15 | { Divider } = require 'md-components/Divider' 16 | 17 | exports.Notification = Notification = class Notification extends Layer 18 | constructor: (options = {}) -> 19 | 20 | { app } = require 'md-components/App' 21 | 22 | @_title = options.title ? 'Notification' 23 | @_body = options.body ? 'This is a notification.' 24 | @_icon = options.icon ? undefined 25 | @_iconColor = options.iconColor ? Theme.text.secondary 26 | @_iconBackgroundColor = options.iconBackgroundColor ? Theme.secondary 27 | 28 | @_actions = options.actions ? [] 29 | 30 | @_time = options.time ? new Date() 31 | @_timeout = options.timeout ? 5 32 | @_group = app?.notifications ? options.group ? [] 33 | 34 | # actions should be: 35 | # {title: 'archive', icon: 'archive', color: '', backgroundColor: ''} 36 | 37 | super _.defaults options, 38 | name: options.name ? '.' 39 | width: Screen.width - 16, borderRadius: 2 40 | x: Align.center 41 | backgroundColor: Theme.dialog.backgroundColor 42 | shadowX: 0, shadowY: 2, shadowBlur: 3 43 | opacity: 0, shadowColor: 'rgba(0,0,0,.3)' 44 | animationOptions: {time: .25} 45 | 46 | @iconLayer = new Layer 47 | name: 'Icon Container' 48 | parent: @ 49 | x: 12, y: 12 50 | height: 40, width: 40, borderRadius: 20 51 | backgroundColor: @_iconBackgroundColor 52 | 53 | if @_icon 54 | @icon = new Icon 55 | name: 'Icon' 56 | parent: @iconLayer 57 | x: Align.center, y: Align.center 58 | color: @_iconColor 59 | icon: @_icon 60 | 61 | @title = new Type.Subhead 62 | name: 'Title' 63 | parent: @ 64 | x: 64, y: 8 65 | width: @width - 72 66 | color: 'rgba(0,0,0,.87)' 67 | text: @_title 68 | 69 | @body = new Type.Body1 70 | name: 'Body' 71 | parent: @ 72 | x: 64, y: @title.maxY 73 | width: @width - 72 74 | text: @_body 75 | 76 | @date = new Type.Caption 77 | name: 'Date' 78 | parent: @ 79 | x: Align.right(-9), y: 15 80 | text: @_time.toLocaleTimeString([], hour: "numeric", minute: "2-digit") 81 | 82 | @height = _.clamp(@body.maxY + 13, 64, Infinity) 83 | 84 | # actions 85 | 86 | if @_actions.length > 0 87 | 88 | divider = new Divider 89 | name: 'Divider' 90 | parent: @ 91 | x: 64, y: @body.maxY + 11 92 | width: @width - 64 93 | 94 | @height = divider.maxY + 46 95 | 96 | startX = 64 97 | notification = @ 98 | 99 | for action in @_actions 100 | actionButton = new Layer 101 | name: 'Action 1', parent: @ 102 | x: startX, y: divider.maxY + 11 103 | width: 80, height: 24, backgroundColor: null 104 | 105 | do _.bind( -> # actionButton 106 | 107 | @icon = new Icon 108 | name: 'Icon', parent: @ 109 | width: 18, height: 18 110 | color: 'rgba(0,0,0,.54)' 111 | icon: action.icon 112 | 113 | @label = new Type.Caption 114 | name: 'Label', parent: @ 115 | x: @icon.maxX + 8 116 | fontSize: 13 117 | textTransform: 'uppercase' 118 | text: action.title 119 | 120 | @width = @label.maxX + 20 121 | startX += @width 122 | 123 | do (action) => 124 | @onTap => 125 | notification.close() 126 | if action.action? 127 | Utils.delay .25, _.bind(action.action, notification) 128 | 129 | actionButton) 130 | 131 | # swipes 132 | 133 | @onSwipeLeftEnd => @close('left') 134 | @onSwipeRightEnd => @close('right') 135 | 136 | @open() 137 | 138 | open: => 139 | startY = _.last(@_group)?.maxY ? 24 140 | startY += 8 141 | 142 | @y = startY 143 | 144 | @animate {opacity: 1} 145 | @_group.push(@) 146 | 147 | Utils.delay @_timeout, => if not @closed then @close('right') 148 | 149 | 150 | close: (direction) => 151 | _.pull(@_group, @) 152 | 153 | newY = 32 154 | for layer, i in @_group 155 | layer.animate { y: newY } 156 | newY += layer.height + 8 157 | 158 | @animate 159 | x: if direction is 'left' then -Screen.width else Screen.width 160 | opacity: 0 161 | 162 | @closed = true 163 | 164 | Utils.delay .5, => @destroy() 165 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Page.coffee: -------------------------------------------------------------------------------- 1 | 2 | # 888888ba 3 | # 88 `8b 4 | # a88aaaa8P' .d8888b. .d8888b. .d8888b. 5 | # 88 88' `88 88' `88 88ooood8 6 | # 88 88. .88 88. .88 88. ... 7 | # dP `88888P8 `8888P88 `88888P' 8 | # .88 9 | # d8888P 10 | 11 | # simplify header controls 12 | # remove template(?) 13 | 14 | { Theme } = require 'md-components/Theme' 15 | { StackView } = require 'md-components/StackView' 16 | 17 | exports.Page = class Page extends StackView 18 | constructor: (options = {}) -> 19 | @__constructor = true 20 | 21 | { app } = require 'md-components/App' 22 | 23 | options.icon ?= 'arrow-left' 24 | options.action ?= -> app.showPrevious() 25 | 26 | # header 27 | @headerOptions = { 28 | title: options.title 29 | icon: options.icon 30 | action: options.action 31 | actions: options.actions 32 | } 33 | 34 | # on load 35 | @onLoad = options.onLoad ? -> null 36 | 37 | # refresh 38 | @refresh = options.refresh ? -> null 39 | 40 | super _.defaults options, 41 | name: options.title ? 'View' 42 | size: Screen.size 43 | scrollHorizontal: false 44 | backgroundColor: Theme.page.primary.backgroundColor 45 | shadowSpread: 1 46 | shadowColor: 'rgba(0,0,0,.16)' 47 | shadowBlur: 3 48 | contentInset: {top: app.header?.height, bottom: 241} 49 | 50 | @content.backgroundColor = null 51 | 52 | @sendToBack() 53 | 54 | delete @__constructor 55 | 56 | onLoad: -> null 57 | refresh: -> null -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Radiobox.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP oo dP 2 | # 88 `8b 88 88 3 | # a88aaaa8P' .d8888b. .d888b88 dP .d8888b. 88d888b. .d8888b. dP. .dP 4 | # 88 `8b. 88' `88 88' `88 88 88' `88 88' `88 88' `88 `8bd8' 5 | # 88 88 88. .88 88. .88 88 88. .88 88. .88 88. .88 .d88b. 6 | # dP dP `88888P8 `88888P8 dP `88888P' 88Y8888' `88888P' dP' `dP 7 | 8 | 9 | { Icon } = require 'md-components/Icon' 10 | { Theme } = require 'md-components/Theme' 11 | 12 | exports.Radiobox = Radiobox = class Radiobox extends Icon 13 | constructor: (options = {}) -> 14 | 15 | @_group = undefined 16 | 17 | super _.defaults options, 18 | name: '.' 19 | animationOptions: {time: .15} 20 | icon: 'radiobox-blank' 21 | color: Theme.primary 22 | toggle: true 23 | toggleLock: true 24 | action: -> null 25 | 26 | @on "change:isOn", -> 27 | @updateIcon() 28 | @updateSiblings() 29 | 30 | updateIcon: => 31 | @icon = if @isOn then 'radiobox-marked' else 'radiobox-blank' 32 | 33 | updateSiblings: => 34 | if @isOn then sib.isOn = false for sib in _.without(@_group, @) 35 | 36 | @define "group", 37 | get: -> return @_group 38 | set: (array) -> 39 | return if array is @_group 40 | @_group = array 41 | 42 | # add this checkbox to the group array if not in it already 43 | if not _.includes(@_group, @) then @_group.push(@) 44 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Ripple.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba oo dP 2 | # 88 `8b 88 3 | # a88aaaa8P' dP 88d888b. 88d888b. 88 .d8888b. 4 | # 88 `8b. 88 88' `88 88' `88 88 88ooood8 5 | # 88 88 88 88. .88 88. .88 88 88. ... 6 | # dP dP dP 88Y888P' 88Y888P' dP `88888P' 7 | # 88 88 8 | # dP dP 9 | 10 | # By default, shows an expanding circle over a layer, clipped to its frame. 11 | # On the layer's touchEnd event, the circle and its mask will disappear. 12 | 13 | # required: 14 | # layer (Layer), the layer over which to show the ripple effect 15 | # point (object), the ripple origin point, usually a onTouchStart's event.point 16 | 17 | # optional: 18 | # placeBehind (Layer), a child of layer behind which the ripple should appear 19 | # color (string or color object), a custom color for the ripple 20 | 21 | class exports.Ripple extends Layer 22 | constructor: (@mask, @external = false, @colorOverride = undefined, events = true) -> 23 | 24 | @mask ?= throw 'Ripple needs a mask layer' 25 | 26 | super 27 | name: 'Ripple', parent: @mask 28 | point: Align.center 29 | backgroundColor: @_color 30 | width: 8, height: 8 31 | opacity: 0 32 | 33 | fullWidth = if @mask.width > @mask.height then @mask.width else @mask.height 34 | @_fullWidth = fullWidth * 2 35 | 36 | if events 37 | @mask.onTapStart ( event ) => @show( event.point ) 38 | @mask.onTapEnd @hide 39 | @mask.onPanEnd @hide 40 | @mask.onPan (event, layer) => 41 | isTooFar = (num) -> Math.abs(num) >= 24 42 | @hide() if isTooFar(event.offset.x) or isTooFar(event.offset.y) 43 | 44 | show: (point = @point) => 45 | return if @mask.parent?.disabled 46 | 47 | @animateStop() 48 | 49 | fullWidth = @_fullWidth 50 | parent = @mask.parent 51 | color = undefined 52 | 53 | if @colorOverride? 54 | color = @colorOverride 55 | else if @external 56 | color = new Color( parent.color ) 57 | .alpha( .25 ) 58 | else 59 | color = new Color( parent.backgroundColor ) 60 | .alpha( .5 ) 61 | .lighten( 15 ) 62 | .saturate ( 15 ) 63 | 64 | @props = 65 | x: point.x - 4 66 | y: point.y - 4 67 | height: 8 68 | width: 8 69 | borderRadius: 4 70 | backgroundColor: color 71 | opacity: 0 72 | 73 | @animate 74 | opacity: 1 75 | options: { time: .1 } 76 | 77 | @animate 78 | x: point.x - 4 - ( fullWidth ) 79 | y: point.y - 4 - ( fullWidth ) 80 | height: fullWidth * 2 81 | width: fullWidth * 2 82 | borderRadius: ( fullWidth ) 83 | options: { time: .6 } 84 | 85 | hide: => 86 | @animate 87 | opacity: 0 88 | options: { time: .45 , delay: .1 } 89 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/RowItem.coffee: -------------------------------------------------------------------------------- 1 | # 888888ba dP dP 2 | # 88 `8b 88 88 3 | # a88aaaa8P' .d8888b. dP dP dP 88 d8888P .d8888b. 88d8b.d8b. 4 | # 88 `8b. 88' `88 88 88 88 88 88 88ooood8 88'`88'`88 5 | # 88 88 88. .88 88.88b.88' 88 88 88. ... 88 88 88 6 | # dP dP `88888P' 8888P Y8P dP dP `88888P' dP dP dP 7 | 8 | Type = require 'md-components/Type' 9 | { Theme } = require 'md-components/Theme' 10 | { Divider } = require 'md-components/Divider' 11 | 12 | 13 | exports.RowItem = class RowItem extends Layer 14 | constructor: (options = {}) -> 15 | 16 | @_icon = options.icon 17 | @_iconBackgroundColor = options.iconBackgroundColor ? '#777' 18 | @_text = options.text ? 'Row item' 19 | @_row = options.row ? 0 20 | @_y = 32 + (@_row * 48) 21 | 22 | super _.defaults options, 23 | width: Screen.width 24 | y: @_y 25 | height: 48 26 | backgroundColor: null 27 | 28 | @icon = new Layer 29 | name: '.', parent: @ 30 | x: 16, y: Align.center 31 | height: 32, width: 32, borderRadius: 16 32 | backgroundColor: @_iconBackgroundColor 33 | image: @_icon 34 | 35 | @labelLayer = new Type.Regular 36 | name: '.', parent: @ 37 | x: @icon.maxX + 16, y: Align.center 38 | color: Theme.text.text 39 | text: @_text -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Select.coffee: -------------------------------------------------------------------------------- 1 | Type = require 'md-components/Type' 2 | { Theme } = require 'md-components/Theme' 3 | { TextField } = require 'md-components/TextField' 4 | { Dropdown } = require 'md-components/Dropdown' 5 | { Icon } = require 'md-components/Icon' 6 | 7 | 8 | # .d88888b dP dP 9 | # 88. "' 88 88 10 | # `Y88888b. .d8888b. 88 .d8888b. .d8888b. d8888P 11 | # `8b 88ooood8 88 88ooood8 88' `"" 88 12 | # d8' .8P 88. ... 88 88. ... 88. ... 88 13 | # Y88888P `88888P' dP `88888P' `88888P' dP 14 | # 15 | # 16 | 17 | 18 | class exports.Select extends TextField 19 | constructor: (options = {}) -> 20 | 21 | @_options = options.options ? ['Select Menu'] 22 | 23 | # TODO 24 | # add an explicit width prop to textfield and use this prop instead of useMenuWidth 25 | 26 | useMenuWidth = options.useMenuWidth ? false 27 | 28 | super _.defaults options, 29 | name: 'Downdown Select' 30 | type: 'dropdown' 31 | inputType: 'input' 32 | readOnly: true 33 | clip: false 34 | 35 | @dropdown = new Dropdown 36 | parent: @ 37 | x: 0, y: 4 38 | width: if not useMenuWidth then @width 39 | options: @_options 40 | 41 | if useMenuWidth then @width = @dropdown.width 42 | 43 | @dropdown.on "change:selection", (selection) => 44 | @_input.value = selection 45 | @setValue() 46 | 47 | @dropdown.on "change:isOpen", (isOpen) => 48 | @focused = isOpen 49 | 50 | showFocused: => 51 | return if @disabled 52 | 53 | baseY = 0 54 | 55 | if @focused 56 | @bringToFront() 57 | 58 | @animateStop() 59 | 60 | @_app?.focused = @ 61 | 62 | if @screenFrame.y + @height > Screen.height - 222 63 | @scrollLayer?.scrollToLayer(@, 0, .45) 64 | else if @screenFrame.y < Screen.height * .15 65 | @scrollLayer?.scrollToLayer(@, 0, .15) 66 | 67 | @labelTextLayer?.animate 68 | y: baseY 69 | fontSize: 12 70 | color: @tint 71 | 72 | @inputLine?.animate 73 | height: 1 74 | backgroundColor: @tint 75 | 76 | else 77 | @animateStop() 78 | 79 | if this.hasTextContent() 80 | @labelTextLayer?.animate 81 | y: baseY 82 | fontSize: 12 83 | color: @labelTextColor 84 | else 85 | @labelTextLayer?.animate 86 | y: 22 87 | fontSize: 16 88 | color: @labelTextColor 89 | 90 | @inputLine?.animate 91 | height: 1 92 | backgroundColor: 'rgba(0, 0, 0, .42)' 93 | 94 | if @_app?.focused is @ 95 | @_app?.focused = undefined 96 | 97 | @setPlaceholder() 98 | 99 | @define "focused", 100 | get: -> return @_focused 101 | set: (value) -> 102 | return if @_focused is value 103 | if typeof value isnt 'boolean' then throw 'Focused must be either true or false.' 104 | 105 | @_focused = value 106 | 107 | @emit("change:focused", value, @) 108 | 109 | @showFocused() -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Slider.coffee: -------------------------------------------------------------------------------- 1 | # .d88888b dP oo dP 2 | # 88. "' 88 88 3 | # `Y88888b. 88 dP .d888b88 .d8888b. 88d888b. 4 | # `8b 88 88 88' `88 88ooood8 88' `88 5 | # d8' .8P 88 88 88. .88 88. ... 88 6 | # Y88888P dP dP `88888P8 `88888P' dP 7 | 8 | { Ripple } = require 'md-components/Ripple' 9 | { Icon } = require 'md-components/Icon' 10 | { Theme } = require 'md-components/Theme' 11 | 12 | exports.Slider = class Slider extends SliderComponent 13 | constructor: (options = {}) -> 14 | 15 | @_notched = options.notched ? false 16 | @_notches = options.notches ? 10 17 | @_notchWidth = undefined 18 | 19 | super _.defaults options, 20 | name: '.', height: 2 21 | backgroundColor: 'rgba(0,0,0,.26)' 22 | min: 0, max: 10 23 | animationOptions: {time: .15} 24 | 25 | @fill.backgroundColor = Theme.primary 26 | @knobSize = 44 27 | 28 | @knob.props = 29 | name: 'Knob' 30 | backgroundColor: null 31 | shadowX: 0 32 | shadowY: 0 33 | shadowBlur: 0 34 | color: Theme.primary 35 | 36 | @knob.draggable.propagateEvents = false 37 | 38 | @thumb = new Layer 39 | name: 'Thumb', parent: @knob 40 | x: Align.center, y: Align.center 41 | height: 12, width: 12, borderRadius: 12 42 | backgroundColor: Theme.primary 43 | animationOptions: {time: .15} 44 | 45 | if @_notched 46 | 47 | @_notchWidth = @width / @_notches 48 | 49 | for i in [0...@_notches] 50 | notch = new Layer 51 | name: '.', parent: @ 52 | x: i * @_notchWidth 53 | width: 2, height: 2, borderRadius: 2, 54 | backgroundColor: Theme.colors.primary.text 55 | 56 | notch.placeBehind(@knob) 57 | 58 | @tip = new Layer 59 | name: 'Tip', parent: @knob 60 | x: Align.center, y: -24 61 | width: 26, height: 32 62 | html: '' 63 | backgroundColor: null, opacity: 0 64 | animationOptions: {time: .15} 65 | 66 | @tipValue = new TextLayer 67 | name: 'Tip Value', parent: @tip 68 | y: 5, width: 26 69 | color: Theme.colors.primary.text 70 | fontSize: 12, fontFamily: 'Roboto', textAlign: 'center' 71 | text: "{value}" 72 | 73 | @tipValue.template = @value 74 | 75 | @onTouchStart @_showNotchedDragging 76 | 77 | @onValueChange -> 78 | @_setNotchedValue() 79 | @_setTipValue() 80 | 81 | 82 | else 83 | @knob.onTouchStart @_showDragging 84 | 85 | 86 | @knob.onTouchEnd @showDefault 87 | @knob.onDragEnd @showDefault 88 | @knob.onDrag @_setThumbColor 89 | @_setThumbColor() 90 | 91 | _roundValue: (number, nearest) -> 92 | return (Math.round(number / nearest) + 1) * nearest 93 | 94 | _setNotchedValue: (value) => 95 | if @knob.midX % @_notchWidth > 0 96 | @knob.x = @_roundValue(@knob.x, @_notchWidth) - (@knob.width / 2) 97 | 98 | _setTipValue: => 99 | @tipValue.template = Math.round(@value) 100 | @_setTipColor() 101 | 102 | _setTipColor: => 103 | color = if @value is @min then 'rgba(190, 190, 190, 1)' else Theme.primary 104 | @tip.html = '' 105 | 106 | _showNotchedDragging: => 107 | @_setTipColor() 108 | @thumb.animate {opacity: 0} 109 | @tip.animate {opacity: 1} 110 | 111 | _showDragging: => 112 | @_setThumbColor() 113 | @thumb.animate {width: 18, height: 18, x: 13, y: 13} 114 | 115 | _setThumbColor: => 116 | @thumb.backgroundColor = if @value is @min then 'rgba(190, 190, 190, 1)' else Theme.primary 117 | 118 | showDefault: => 119 | @animateStop() 120 | @_setThumbColor() 121 | @thumb.animate {opacity: 1, width: 12, height: 12, x: 15, y: 15} 122 | if @_notched 123 | @_setTipColor() 124 | @tip.animate {opacity: 0} 125 | 126 | 127 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Snackbar.coffee: -------------------------------------------------------------------------------- 1 | # .d88888b dP dP 2 | # 88. "' 88 88 3 | # `Y88888b. 88d888b. .d8888b. .d8888b. 88 .dP 88d888b. .d8888b. 88d888b. 4 | # `8b 88' `88 88' `88 88' `"" 88888" 88' `88 88' `88 88' `88 5 | # d8' .8P 88 88 88. .88 88. ... 88 `8b. 88. .88 88. .88 88 6 | # Y88888P dP dP `88888P8 `88888P' dP `YP 88Y8888' `88888P8 dP 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Theme } = require 'md-components/Theme' 11 | { Button } = require 'md-components/Button' 12 | 13 | class exports.Snackbar extends Layer 14 | constructor: (options = {}) -> 15 | 16 | { app } = require 'md-components/App' 17 | @_app = app 18 | 19 | @_title = options.title ? 'Snackbar' 20 | @_timeout = options.timeout ? 4 21 | @_action = options.action 22 | 23 | super _.defaults options, 24 | name: '.' 25 | y: Screen.maxY 26 | width: Screen.width 27 | clip: true 28 | backgroundColor: Theme.snackbar.backgroundColor 29 | animationOptions: {time: .25} 30 | visible: false 31 | 32 | titleWidth = @width - 48 33 | 34 | if @_action? 35 | @action = new Button 36 | parent: @ 37 | x: Align.right(-8), y: 4 38 | color: @_action.color ? Theme.colors.primary.light 39 | text: @_action.title.toUpperCase() 40 | action: @_action.action 41 | 42 | @action.onTap @hide 43 | titleWidth = @action.x - 8 - 24 44 | 45 | @textLabel = new Type.Body1 46 | name: 'Title', parent: @ 47 | x: 24, y: 14 48 | width: titleWidth 49 | text: @_title 50 | color: Theme.snackbar.color 51 | 52 | @height = @textLabel.maxY + 14 53 | @action?.y = Align.center 54 | 55 | 56 | 57 | Utils.delay @_timeout, @hide 58 | 59 | @show() 60 | 61 | show: => 62 | if @_app? 63 | if @_app.snackbar? 64 | @_app.snackbar.hide() 65 | Utils.delay 1, @show 66 | return 67 | else 68 | @_app.snackbar = @ 69 | @_app.actionButton?.animate {y: @_app.actionButton.y - @height, options: @animationOptions} 70 | 71 | height = @height 72 | 73 | @y = Screen.height - @_app.footer.height 74 | @height = 0 75 | @visible = true 76 | @animate 77 | y: @y - (height - 1) 78 | height: height 79 | else 80 | @visible = true 81 | @y = Screen.height 82 | @animate {y: Screen.height - @height} 83 | 84 | hide: => 85 | if @_app? 86 | @_app.snackbar = undefined 87 | @_app.actionButton?.animate {y: @_app.actionButton.y + @height, options: @animationOptions} 88 | 89 | @animate {height: 0, y: @y + @height} 90 | Utils.delay .5, => @destroy() -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/StackView.coffee: -------------------------------------------------------------------------------- 1 | # add stackview to any layer 2 | 3 | class exports.StackView extends ScrollComponent 4 | constructor: (options = {}) -> 5 | showLayers = options.showLayers ? false 6 | 7 | # stack related 8 | @_stack = [] 9 | @padding = options.padding ? { 10 | top: 16, right: 16, 11 | bottom: 0, left: 16 12 | stack: 16 13 | } 14 | 15 | super _.defaults options, 16 | name: 'StackView' 17 | size: Screen.size 18 | scrollHorizontal: false 19 | contentInset: { bottom: 16 } 20 | 21 | @content.clip = false 22 | @content.backgroundColor = Screen.backgroundColor 23 | @content.name = if options.showLayers then 'content' else '.' 24 | 25 | # add a layer to the stack 26 | addToStack: (layers = [], position) => 27 | if not _.isArray(layers) then layers = [layers] 28 | last = _.last(@stack) 29 | 30 | if last? 31 | startY = last.maxY + (@padding.stack ? 0) 32 | else 33 | startY = @padding.top ? 0 34 | 35 | for layer in layers 36 | 37 | if layer.constructor.name is 'Card' then position = 'full' 38 | 39 | layer.props = 40 | parent: @content 41 | x: _.clamp( 42 | @padding.left + layer.x, 43 | @padding.left, 44 | @width - @padding.right - layer.width 45 | ) 46 | y: startY 47 | 48 | switch position 49 | when 'full' 50 | layer.width = @width - ( @padding.left + @padding.right ) 51 | when 'left' 52 | layer.props = 53 | width: (@width / 2) - @padding.left 54 | x: @padding.left 55 | when 'right' 56 | layer.props = 57 | width: (@width / 2) - @padding.right 58 | x: Align.right(-@padding.right) 59 | when 'center' 60 | layer.x = Align.center 61 | 62 | @stack.push(layer) 63 | 64 | layer.on "change:height", => @moveStack(@) 65 | 66 | @updateContent() 67 | 68 | # pull a layer from the stack 69 | removeFromStack: (layer) => 70 | _.pull(@stack, layer) 71 | 72 | # stack layers in stack, with optional padding and animation 73 | stackView: ( 74 | animate = false, 75 | padding = @padding.stack, 76 | top = @padding.top, 77 | animationOptions = {time: .25} 78 | ) => 79 | 80 | for layer, i in @stack 81 | 82 | if animate is true 83 | if i is 0 then layer.animate 84 | y: top 85 | options: animationOptions 86 | 87 | else layer.animate 88 | y: @stack[i - 1].maxY + padding 89 | options: animationOptions 90 | else 91 | if i is 0 then layer.y = top 92 | else layer.y = @stack[i - 1].maxY + padding 93 | 94 | @updateContent() 95 | 96 | # move stack when layer height changes 97 | moveStack: (layer) => 98 | index = _.indexOf(@stack, layer) 99 | for layer, i in @stack 100 | if i > 0 and i > index 101 | layer.y = @stack[i - 1].maxY + @padding.stack 102 | 103 | 104 | # build with page as bound object 105 | build: (func) -> do _.bind(func, @) 106 | 107 | # refresh page 108 | refresh: -> null 109 | 110 | @define "stack", 111 | get: -> return @_stack 112 | set: (layers) -> 113 | layer.destroy() for layer in @stack 114 | @addToStack(layers) 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/StatusBar.coffee: -------------------------------------------------------------------------------- 1 | # .d88888b dP dP 888888ba 2 | # 88. "' 88 88 88 `8b 3 | # `Y88888b. d8888P .d8888b. d8888P dP dP .d8888b. a88aaaa8P' .d8888b. 88d888b. 4 | # `8b 88 88' `88 88 88 88 Y8ooooo. 88 `8b. 88' `88 88' `88 5 | # d8' .8P 88 88. .88 88 88. .88 88 88 .88 88. .88 88 6 | # Y88888P dP `88888P8 dP `88888P' `88888P' 88888888P `88888P8 dP 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Icon } = require 'md-components/Icon' 11 | { Theme } = require 'md-components/Theme' 12 | 13 | exports.StatusBar = class StatusBar extends Layer 14 | constructor: (options = {}) -> 15 | 16 | super _.defaults options, 17 | name: '.' 18 | width: Screen.width, height: 24 19 | backgroundColor: Theme.statusBar.backgroundColor 20 | 21 | @items = new Layer 22 | name: '.', parent: @ 23 | width: 100 24 | height: 15 25 | x: Align.right(-8) 26 | y: 5 27 | backgroundColor: null 28 | style: 29 | lineHeight: 0 30 | 31 | @on "change:color", => @setSVG() 32 | @color = '#FFF' 33 | 34 | setSVG: -> 35 | @items.html = """ 36 | 44 | 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 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 12:30 84 | 85 | 86 | 87 | 88 | """ -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Switch.coffee: -------------------------------------------------------------------------------- 1 | 2 | # .d88888b oo dP dP 3 | # 88. "' 88 88 4 | # `Y88888b. dP dP dP dP d8888P .d8888b. 88d888b. 5 | # `8b 88 88 88 88 88 88' `"" 88' `88 6 | # d8' .8P 88.88b.88' 88 88 88. ... 88 88 7 | # Y88888P 8888P Y8P dP dP `88888P' dP dP 8 | 9 | Type = require 'md-components/Type' 10 | { Ripple } = require 'md-components/Ripple' 11 | { Icon } = require 'md-components/Icon' 12 | { Theme } = require 'md-components/Theme' 13 | 14 | exports.Switch = class Switch extends Layer 15 | constructor: (options = {}) -> 16 | 17 | @_isOn = false 18 | 19 | super _.defaults options, 20 | name: 'Switch' 21 | width: 34, height: 14, borderRadius: 7 22 | color: new Color(Theme.primary).desaturate(100).alpha(.84) 23 | backgroundColor: 'rgba(0,0,0,.54)' 24 | animationOptions: {time: .15} 25 | 26 | @mask = new Layer 27 | name: 'Mask', parent: @ 28 | x: -12, y: Align.center 29 | width: 44, height: 44 30 | borderRadius: 20 31 | backgroundColor: null 32 | clip: true 33 | opacity: 1 34 | animationOptions: {time: .15} 35 | 36 | @ripple = new Ripple( @mask, external = true ) 37 | 38 | @knob = new Layer 39 | name: 'Knob', parent: @mask 40 | x: Align.center, y: Align.center 41 | width: 20, height: 20, borderRadius: 10 42 | backgroundColor: 'rgba(250, 250, 250, 1)' 43 | shadowY: 2, shadowBlur: 3 44 | animationOptions: {time: .15} 45 | 46 | @onTap -> @isOn = !@isOn 47 | 48 | @define "isOn", 49 | get: -> return @_isOn 50 | set: (bool) -> 51 | return if bool is @_isOn 52 | 53 | @_isOn = bool 54 | @emit("change:isOn", @_isOn, @) 55 | @update() 56 | 57 | update: -> 58 | if @_isOn 59 | @mask.animate {x: Align.right(12)} 60 | @color = Theme.primary 61 | @knob.animate {backgroundColor: Theme.primary} 62 | @animate {backgroundColor: Theme.colors.primary.light} 63 | else 64 | @mask.animate {x: -12} 65 | @color = new Color(Theme.primary).desaturate(100).alpha(.84) 66 | @knob.animate {backgroundColor: 'rgba(250, 250, 250, 1)'} 67 | @animate {backgroundColor: 'rgba(0,0,0,.54)'} 68 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/TextArea.coffee: -------------------------------------------------------------------------------- 1 | Type = require 'md-components/Type' 2 | { Theme } = require 'md-components/Theme' 3 | { TextField } = require 'md-components/TextField' 4 | 5 | 6 | # d888888P dP .d888888 7 | # 88 88 d8' 88 8 | # 88 .d8888b. dP. .dP d8888P 88aaaaa88a 88d888b. .d8888b. .d8888b. 9 | # 88 88ooood8 `8bd8' 88 88 88 88' `88 88ooood8 88' `88 10 | # 88 88. ... .d88b. 88 88 88 88 88. ... 88. .88 11 | # dP `88888P' dP' `dP dP 88 88 dP `88888P' `88888P8 12 | # 13 | # 14 | 15 | exports.TextArea = class TextArea extends TextField 16 | constructor: (options = {}) -> 17 | 18 | @_rows = options.rows ? 4 19 | 20 | super _.defaults options, 21 | name: 'Text Area' 22 | width: 300 23 | borderRadius: 4 24 | borderWidth: 2, borderColor: options.tint 25 | padding: {top: 28, bottom: 16, right: 16, left: 16} 26 | clip: true 27 | inputType: 'textarea' 28 | 29 | # Label Text 30 | 31 | @labelTextLayer.props = 32 | x: 16, y: 16 33 | 34 | @helperTextLayer.visible = false 35 | 36 | # Input Line 37 | 38 | @inputLine.destroy() 39 | 40 | # Textarea Element 41 | 42 | @setInputAttribute('rows', @_rows) 43 | @setInputAttribute('resize', @_rows) 44 | 45 | @height = @_input.clientHeight 46 | 47 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Theme.coffee: -------------------------------------------------------------------------------- 1 | # d888888P dP 2 | # 88 88 3 | # 88 88d888b. .d8888b. 88d8b.d8b. .d8888b. 4 | # 88 88' `88 88ooood8 88'`88'`88 88ooood8 5 | # 88 88 88 88. ... 88 88 88 88. ... 6 | # dP dP dP `88888P' dP dP dP `88888P' 7 | 8 | 9 | # When loaded, this module will attempt to create a new theme based on 10 | # the Design Mode template. 11 | 12 | Screen.backgroundColor = '#000' 13 | 14 | exports.modifyColor = modifyColor = (color, h, s, l) -> 15 | clip = _.replace(_.replace(color.toHslString().slice(4, -1), '%', ''), '%', '') .split(', ') 16 | 17 | newColor = new Color( 18 | h: _.parseInt(clip[0]) + h, 19 | s: (_.parseInt(clip[1]) + s)/100, 20 | l: (_.parseInt(clip[2]) + l)/100, 21 | a: 1) 22 | 23 | return newColor 24 | 25 | primaryColor = new Color('#0F6CC8') 26 | primaryTextColor = new Color('#FFFFFF') 27 | 28 | secondaryColor = new Color('#1B9DFF') 29 | secondaryTextColor = new Color('#FFFFFF') 30 | 31 | menuColor = new Color ('#CCCCCC') 32 | menuTextColor = new Color('#000000') 33 | 34 | pageColor = new Color('#FFFFFF') 35 | pageTextColor = new Color('#333333') 36 | 37 | exports.colors = colors = 38 | primary: 39 | main: primaryColor 40 | light: modifyColor(primaryColor, 13, -5, 15) 41 | dark: modifyColor(primaryColor, -1, -7, -12) 42 | text: primaryTextColor 43 | 44 | secondary: 45 | main: secondaryColor 46 | light: modifyColor(secondaryColor, 13, -5, 15) 47 | dark: modifyColor(secondaryColor, -1, -7, -12) 48 | text: secondaryTextColor 49 | menu: 50 | main: menuColor 51 | light: modifyColor(menuColor, 13, -5, 15) 52 | dark: modifyColor(menuColor, -1, -7, -12) 53 | text: menuTextColor 54 | page: 55 | main: pageColor 56 | light: modifyColor(pageColor, 13, -5, 15) 57 | dark: modifyColor(pageColor, -1, -7, -12) 58 | text: pageTextColor 59 | 60 | exports.Theme = 61 | tint: colors.secondary.main 62 | primary: colors.primary.main 63 | secondary: colors.secondary.main 64 | page: colors.page.main 65 | menu: colors.menu.light 66 | colors: colors 67 | 68 | user: 69 | image: undefined 70 | 71 | header: 72 | backgroundColor: colors.primary.main 73 | title: colors.primary.text 74 | icon: 75 | color: colors.primary.text 76 | tabs: 77 | backgroundColor: colors.primary.light 78 | color: colors.primary.text 79 | selector: colors.secondary.main 80 | 81 | statusBar: 82 | image: 'modules/md-images/status_bar.png' 83 | backgroundColor: colors.primary.dark 84 | 85 | bottomNav: 86 | backgroundColor: '#FFFFFF' 87 | shadowY: -2 88 | shadowBlur: 6 89 | shadowColor: 'rgba(0,0,0,.1)' 90 | 91 | navBar: 92 | backgroundColor: '#000000' 93 | 94 | keyboard: 95 | image: 'modules/md-images/keyboard.png' 96 | 97 | footer: 98 | image: 'modules/md-images/nav_bar.png' 99 | 100 | page: 101 | primary: 102 | backgroundColor: colors.page.main 103 | text: colors.page.text 104 | secondary: 105 | backgroundColor: '#F5F5F6' 106 | 107 | menuOverlay: 108 | header: 109 | backgroundColor: colors.secondary.main 110 | icon: colors.secondary.light 111 | text: colors.secondary.text 112 | subheader: 113 | color: colors.menu.text 114 | text: colors.secondary.text 115 | icon: colors.secondary.text 116 | backgroundColor: colors.menu.light 117 | text: colors.menu.text 118 | slider: 119 | knob: colors.secondary.light 120 | fill: colors.secondary.dark 121 | 122 | button: 123 | flat: 124 | backgroundColor: null 125 | color: colors.secondary.main 126 | shadowY: 0 127 | shadowColor: 'rgba(0,0,0,.18)' 128 | shadowBlur: 0 129 | 130 | raised: 131 | backgroundColor: colors.secondary.main 132 | color: colors.secondary.text 133 | shadowY: 2 134 | shadowColor: 'rgba(0,0,0,.18)' 135 | shadowBlur: 6 136 | 137 | fab: 138 | backgroundColor: colors.secondary.main 139 | color: colors.secondary.text 140 | 141 | dialog: 142 | backgroundColor:'#FAFAFA' 143 | 144 | divider: 145 | backgroundColor: 'rgba(0,0,0,.12)' 146 | 147 | text: 148 | primary: colors.primary.text 149 | secondary: colors.secondary.text 150 | 151 | table: 152 | backgroundColor: '#FFFFFF' 153 | text: colors.primary.text 154 | checkBox: 155 | backgroundColor: null 156 | borderColor: '#D3D3D3' 157 | selected: 158 | backgroundColor: colors.secondary.main 159 | text: colors.primary.text 160 | checkBox: 161 | backgroundColor: colors.secondary.dark 162 | borderColor: null 163 | snackbar: 164 | backgroundColor: 'rgba(51, 51, 51, 1)' 165 | color: 'rgba(255, 255, 255, 1)' 166 | 167 | toast: 168 | backgroundColor: 'rgba(51, 51, 51, 1)' 169 | color: 'rgba(255, 255, 255, 1)' 170 | 171 | slider: 172 | knob: colors.primary.light 173 | fill: colors.primary.dark 174 | 175 | card: 176 | header: colors.secondary.dark 177 | 178 | color_pallete?.destroy() -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Tile.coffee: -------------------------------------------------------------------------------- 1 | # d888888P oo dP 2 | # 88 88 3 | # 88 dP 88 .d8888b. 4 | # 88 88 88 88ooood8 5 | # 88 88 88 88. ... 6 | # dP dP dP `88888P' 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Icon } = require 'md-components/Icon' 11 | { Theme } = require 'md-components/Theme' 12 | 13 | exports.Tile = Tile = class Tile extends Layer 14 | constructor: (options = {}) -> 15 | 16 | @_header = options.header ? false 17 | @_footer = options.footer ? false 18 | @_action = options.action ? -> null 19 | @_headerAction = options.headerAction ? -> null 20 | @_footerAction = options.footerAction ? -> null 21 | 22 | if @_header and @_footer then throw 'Tile cannot have both a header and a footer.' 23 | 24 | @_icon = options.icon 25 | @gridList = options.gridList # ? throw 'Tile needs a grid property.' 26 | 27 | super _.defaults options, 28 | name: '.', parent: @gridList 29 | width: @gridList.tileWidth 30 | height: @gridList.tileHeight 31 | animationOptions: {time: .3} 32 | 33 | @onTouchStart (event) -> 34 | if @gridList.parent?.parent?.content and @gridList.parent?.parent?.isMoving is false 35 | Ripple(@, event.point, @header, options.RippleColor ? 'rgba(0,0,0,.1)') 36 | 37 | @onTap @_action 38 | @onTap (event) -> event.stopPropagation() 39 | 40 | if @_header or @_footer 41 | @header = new Layer 42 | name: '.', parent: @ 43 | y: if @_footer then Align.bottom() 44 | width: @width 45 | height: if options.support then 68 else 48 46 | backgroundColor: options.backgroundColor ? 'rgba(0,0,0,.5)' 47 | 48 | @header.onTouchStart (event) -> Ripple(@, event.point, @title) 49 | 50 | if @_footer then @header.onTap @_footerAction 51 | else @header.onTap @_headerAction 52 | 53 | @header.onTap (event) -> event.stopPropagation() 54 | 55 | if options.title 56 | @header.title = new Type.Regular 57 | name: '.', parent: @header 58 | x: 8, y: if options.support then 12 else Align.center() 59 | color: @color 60 | text: options.title ? 'Two Line' 61 | 62 | if options.support 63 | @header.support = new TextLayer 64 | name: '.', parent: @header 65 | x: 8, y: 35 66 | fontSize: 12 67 | fontFamily: 'Roboto' 68 | color: @color 69 | text: options.support ? 'Support text' 70 | 71 | if options.icon 72 | @header.icon = new Icon 73 | name: '.', parent: @header 74 | x: Align.right(-12), y: if options.support then 20 else Align.center() 75 | icon: options.icon 76 | color: @color 77 | 78 | @i = undefined 79 | @gridList.addTile(@) -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Toast.coffee: -------------------------------------------------------------------------------- 1 | # d888888P dP 2 | # 88 88 3 | # 88 .d8888b. .d8888b. .d8888b. d8888P 4 | # 88 88' `88 88' `88 Y8ooooo. 88 5 | # 88 88. .88 88. .88 88 88 6 | # dP `88888P' `88888P8 `88888P' dP 7 | 8 | Type = require 'md-components/Type' 9 | { Ripple } = require 'md-components/Ripple' 10 | { Theme } = require 'md-components/Theme' 11 | { Button } = require 'md-components/Button' 12 | 13 | # currently identical to snackbar 14 | 15 | class exports.Toast extends Layer 16 | constructor: (options = {}) -> 17 | 18 | { app } = require 'md-components/App' 19 | @_app = app 20 | 21 | @_title = options.title ? 'Toast' 22 | @_timeout = options.timeout ? 4 23 | @_action = options.action 24 | 25 | super _.defaults options, 26 | name: '.' 27 | y: Screen.maxY 28 | width: Screen.width 29 | clip: true 30 | backgroundColor: Theme.toast.backgroundColor 31 | animationOptions: {time: .25} 32 | visible: false 33 | 34 | titleWidth = @width - 48 35 | 36 | if @_action? 37 | @action = new Button 38 | parent: @ 39 | x: Align.right(-8), y: 4 40 | color: @_action.color ? Theme.colors.primary.light 41 | text: @_action.title.toUpperCase() 42 | action: @_action.action 43 | 44 | @action.onTap @hide 45 | titleWidth = @action.x - 8 - 24 46 | 47 | @textLabel = new Type.Body1 48 | name: 'Title', parent: @ 49 | x: 24, y: 14 50 | width: titleWidth 51 | text: @_title 52 | color: Theme.toast.color 53 | 54 | @height = @textLabel.maxY + 14 55 | @action?.y = Align.center 56 | 57 | 58 | 59 | Utils.delay @_timeout, @hide 60 | 61 | @show() 62 | 63 | show: => 64 | if @_app? 65 | if @_app.toast? 66 | @_app.toast.hide() 67 | Utils.delay 1, @show 68 | return 69 | else 70 | @_app.toast = @ 71 | @_app.actionButton?.animate {y: @_app.actionButton.y - @height, options: @animationOptions} 72 | 73 | height = @height 74 | 75 | @y = Screen.height - @_app.footer.height 76 | @height = 0 77 | @visible = true 78 | @animate 79 | y: @y - (height - 1) 80 | height: height 81 | else 82 | @visible = true 83 | @y = Screen.height 84 | @animate {y: Screen.height - @height} 85 | 86 | hide: => 87 | if @_app? 88 | @_app.toast = undefined 89 | @_app.actionButton?.animate {y: @_app.actionButton.y + @height, options: @animationOptions} 90 | 91 | @animate {height: 0, y: @y + @height} 92 | Utils.delay .5, => @destroy() -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/Type.coffee: -------------------------------------------------------------------------------- 1 | Theme = require 'md-components/Theme' 2 | 3 | # d888888P dP 4 | # 88 88 5 | # 88 dP dP 88d888b. .d8888b. .d8888b. 88d888b. .d8888b. 88d888b. 88d888b. dP dP 6 | # 88 88 88 88' `88 88' `88 88' `88 88' `88 88' `88 88' `88 88' `88 88 88 7 | # 88 88. .88 88. .88 88. .88 88. .88 88 88. .88 88. .88 88 88 88. .88 8 | # dP `8888P88 88Y888P' `88888P' `8888P88 dP `88888P8 88Y888P' dP dP `8888P88 9 | # .88 88 .88 88 .88 10 | # d8888P dP d8888P dP d8888P 11 | 12 | Utils.insertCSS( 13 | """ 14 | @font-face { 15 | font-family: "Roboto"; 16 | src: url("modules/md-fonts/Roboto-Regular.ttf"); 17 | """) 18 | 19 | class exports.Headline extends TextLayer 20 | constructor: (options) -> 21 | super _.defaults options, 22 | name: '.' 23 | fontFamily: 'Roboto' 24 | fontSize: 24 25 | fontWeight: 400 26 | lineHeight: 1.3 27 | color: 'rgba(0,0,0,.87)' 28 | 29 | class exports.Subhead extends TextLayer 30 | constructor: (options) -> 31 | super _.defaults options, 32 | name: '.' 33 | fontFamily: 'Roboto' 34 | fontSize: 16 35 | fontWeight: 400, 36 | lineHeight: 1.5, 37 | color: 'rgba(0,0,0,.54)' 38 | 39 | class exports.Title extends TextLayer 40 | constructor: (options) -> 41 | super _.defaults options, 42 | name: '.' 43 | fontFamily: 'Roboto' 44 | fontSize: 20 45 | fontWeight: 500 46 | lineHeight: 1.3 47 | color: 'rgba(0,0,0,.87)' 48 | class exports.Regular extends TextLayer 49 | constructor: (options) -> 50 | super _.defaults options, 51 | name: '.' 52 | fontFamily: 'Roboto' 53 | fontSize: 16 54 | fontWeight: 400 55 | lineHeight: 1.3 56 | color: 'rgba(0,0,0,.87)' 57 | class exports.Body2 extends TextLayer 58 | constructor: (options) -> 59 | super _.defaults options, 60 | name: '.' 61 | fontFamily: 'Roboto' 62 | fontSize: 14 63 | fontWeight: 500 64 | lineHeight: 1.3 65 | color: 'rgba(0,0,0,.87)' 66 | class exports.Menu extends TextLayer 67 | constructor: (options) -> 68 | super _.defaults options, 69 | name: '.' 70 | fontFamily: 'Roboto' 71 | fontSize: 14 72 | fontWeight: 500 73 | lineHeight: 1.7 74 | color: 'rgba(0,0,0,.87)' 75 | class exports.Body1 extends TextLayer 76 | constructor: (options) -> 77 | super _.defaults options, 78 | name: '.' 79 | fontFamily: 'Roboto' 80 | fontSize: 14 81 | fontWeight: 400 82 | lineHeight: 1.4 83 | color: 'rgba(0,0,0,.87)' 84 | class exports.Caption extends TextLayer 85 | constructor: (options) -> 86 | super _.defaults options, 87 | name: '.' 88 | fontFamily: 'Roboto' 89 | fontSize: 12 90 | fontWeight: 400 91 | lineHeight: 1.3 92 | color: 'rgba(0,0,0,.54)' 93 | class exports.Button extends TextLayer 94 | constructor: (options) -> 95 | super _.defaults options, 96 | name: '.' 97 | fontFamily: 'Roboto' 98 | fontSize: 14 99 | fontWeight: 500 100 | lineHeight: 1.3 101 | color: '#009688' 102 | letterSpacing: 0.5 103 | padding: {left: 4, right: 4, top: 8, bottom: 0}, -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-components/View.coffee: -------------------------------------------------------------------------------- 1 | # dP dP oo 2 | # 88 88 3 | # 88 .8P dP .d8888b. dP dP dP 4 | # 88 d8' 88 88ooood8 88 88 88 5 | # 88 .d8P 88 88. ... 88.88b.88' 6 | # 888888' dP `88888P' 8888P Y8P 7 | 8 | # Works without an app, but will integrate with app if set with options.app. 9 | 10 | { Theme } = require 'md-components/Theme' 11 | { Page } = require 'md-components/Page' 12 | 13 | exports.View = class View extends Page 14 | constructor: (options = {}) -> 15 | 16 | { app } = require 'md-components/App' 17 | 18 | @_icon = options.icon ? 'open-in-new' 19 | 20 | options.title ?= 'New View' 21 | options.icon = 'menu' 22 | options.action = -> app.showMenu() 23 | 24 | super options 25 | 26 | app.addView 27 | title: options.title 28 | icon: @_icon 29 | view: @ -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-Black.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-Thin.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-fonts/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-fonts/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-images/Group.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Group 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 12:30 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-images/keyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-images/keyboard.png -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-images/nav_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-images/nav_bar.png -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-images/status_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/steveruizok/framer-md/efc38d8d87ee5154f0d1ae4b30bb38416a0ac5fd/framer-md-dev.framer/modules/md-images/status_bar.png -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md-images/status_bar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | time 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 12:30 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /framer-md-dev.framer/modules/md.coffee: -------------------------------------------------------------------------------- 1 | 2 | Framer.Extras.Hints.disable() 3 | 4 | 5 | { ActionButton } = require 'md-components/ActionButton' 6 | { App } = require 'md-components/App' 7 | { BottomNav } = require 'md-components/BottomNav' 8 | { Button } = require 'md-components/Button' 9 | { Card } = require 'md-components/Card' 10 | { Checkbox } = require 'md-components/Checkbox' 11 | { Dialog } = require 'md-components/Dialog' 12 | { Divider } = require 'md-components/Divider' 13 | { Dropdown } = require 'md-components/Dropdown' 14 | { Elevation } = require 'md-components/Elevation' 15 | App = require 'md-components/App' 16 | { GridList } = require 'md-components/GridList' 17 | { Header } = require 'md-components/Header' 18 | { Icon } = require 'md-components/Icon' 19 | { MenuButton } = require 'md-components/MenuButton' 20 | { MenuOverlay } = require 'md-components/MenuOverlay' 21 | { Notification } = require 'md-components/Notification' 22 | { Page } = require 'md-components/Page' 23 | { Radiobox } = require 'md-components/Radiobox' 24 | { Ripple } = require 'md-components/Ripple' 25 | { RowItem } = require 'md-components/RowItem' 26 | { Select } = require 'md-components/Select' 27 | { Slider } = require 'md-components/Slider' 28 | { Snackbar } = require 'md-components/Snackbar' 29 | { StatusBar } = require 'md-components/StatusBar' 30 | { StackView } = require 'md-components/StackView' 31 | { Switch } = require 'md-components/Switch' 32 | { Table } = require 'md-components/Table' 33 | { TableCard } = require 'md-components/TableCard' 34 | { TextArea } = require 'md-components/TextArea' 35 | { TextField } = require 'md-components/TextField' 36 | { Theme } = require 'md-components/Theme' 37 | { Toast } = require 'md-components/Toast' 38 | Type = require 'md-components/Type' 39 | { Tile } = require 'md-components/Tile' 40 | { View } = require 'md-components/View' 41 | 42 | exports.ActionButton = ActionButton 43 | exports.App = App 44 | exports.Button = Button 45 | exports.Card = Card 46 | exports.Checkbox = Checkbox 47 | exports.Dialog = Dialog 48 | exports.Divider = Divider 49 | exports.Dropdown = Dropdown 50 | exports.Elevation = Elevation 51 | exports.App = App.App 52 | exports.app = App.app 53 | exports.GridList = GridList 54 | exports.Header = Header 55 | exports.Icon = Icon 56 | exports.MenuButton = MenuButton 57 | exports.MenuOverlay = MenuOverlay 58 | exports.Notification = Notification 59 | exports.Page = Page 60 | exports.Radiobox = Radiobox 61 | exports.Ripple = Ripple 62 | exports.RowItem = RowItem 63 | exports.Select = Select 64 | exports.Slider = Slider 65 | exports.Snackbar = Snackbar 66 | exports.StackView = StackView 67 | exports.StatusBar = StatusBar 68 | exports.Switch = Switch 69 | exports.Table = Table 70 | exports.TableCard = TableCard 71 | exports.TextArea = TextArea 72 | exports.TextField = TextField 73 | exports.Theme = Theme 74 | exports.Toast = Toast 75 | exports.Tile = Tile 76 | exports.Type = Type 77 | exports.View = View 78 | 79 | exports.Headline = Type.Headline 80 | exports.Subhead = Type.Subhead 81 | exports.Title = Type.Title 82 | exports.Regular = Type.Regular 83 | exports.Menu = Type.Menu 84 | exports.Body1 = Type.Body1 85 | exports.Body2 = Type.Body2 86 | exports.Caption = Type.Caption 87 | 88 | loading_screen?.destroy() 89 | color_pallette?.destroy() 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | --------------------------------------------------------------------------------