├── .DS_Store
├── README.md
├── docs
├── Timer.html
├── csdoc.css
├── global
│ ├── Object.html
│ └── index.html
├── index.html
└── methods.html
├── example.framer
├── .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
│ ├── manifest (SRUIZ-2.local's conflicted copy 2017-12-19).txt
│ ├── manifest (SRUIZ.local's conflicted copy 2017-12-18).txt
│ ├── preview (SRUIZ-2.local's conflicted copy 2017-12-19).png
│ ├── preview (SRUIZ.local's conflicted copy 2017-12-19).png
│ ├── preview (Stephens-iMac.local's conflicted copy 2017-12-18).png
│ ├── style.css
│ └── version
├── images
│ ├── .gitkeep
│ ├── statusbar_left.png
│ └── statusbar_right.png
├── index.html
└── modules
│ ├── Icon.coffee
│ └── moreutils.coffee
├── example_inProgress.framer
├── .gitignore
├── .idea
│ ├── cs-ui-dev.framer.iml
│ ├── modules.xml
│ ├── watcherTasks.xml
│ └── workspace.xml
├── 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
│ ├── manifest (SRUIZ-2.local's conflicted copy 2017-12-19).txt
│ ├── manifest (SRUIZ.local's conflicted copy 2017-12-18).txt
│ ├── manifest (Stephen Ruiz's conflicted copy 2018-01-18).txt
│ ├── preview (SRUIZ-2.local's conflicted copy 2017-12-19).png
│ ├── preview (SRUIZ.local's conflicted copy 2017-12-19).png
│ ├── preview (Stephens-iMac.local's conflicted copy 2017-12-18).png
│ ├── style.css
│ └── version
├── images
│ └── .gitkeep
├── index.html
└── modules
│ ├── components
│ ├── Button.coffee
│ ├── CarouselComponent.coffee
│ ├── Checkbox.coffee
│ ├── Colors.coffee
│ ├── DocComponent.coffee
│ ├── Footer.coffee
│ ├── Header.coffee
│ ├── Icon.coffee
│ ├── Link.coffee
│ ├── PageTransitionComponent.coffee
│ ├── Radiobox.coffee
│ ├── Segment.coffee
│ ├── Select.coffee
│ ├── Separator.coffee
│ ├── SortableComponent.coffee
│ ├── Stepper.coffee
│ ├── Template.coffee
│ ├── TextInput.coffee
│ ├── Theme.coffee
│ ├── Toggle.coffee
│ ├── Tooltip.coffee
│ ├── Typography.coffee
│ └── View.coffee
│ ├── framework.coffee
│ ├── moreutils.coffee
│ ├── myTheme-components
│ ├── Circle.coffee
│ └── fonts
│ │ └── MuktaMahee-Regular.ttf
│ └── myTheme.coffee
├── icon_small.png
├── img
├── constrain_bottom.gif
├── constrain_height.gif
├── constrain_height_aspectratio.gif
├── constrain_height_aspectratio_t.gif
├── constrain_left.gif
├── constrain_left_aspectratio.gif
├── constrain_right.gif
├── constrain_top.gif
├── constrain_width.gif
└── constrain_width_top.gif
├── module.json
└── moreutils.coffee
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/.DS_Store
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # framer-moreutils
2 |
3 | Super handy helper functions for your Framer projects.
4 |
5 | **[Pin](#Utils.pin(layer,-[targetLayer,-directions,-distance]))** Fix a layer's position relative to another layer
6 |
7 | **[Unpin](#Utils.unpin(layer,-[targetLayer,-direction]))**: Remove a layer's pin relationship
8 |
9 | **PinOrigin**: Set a layer's relative position to another layer, based on its originX and originY properties.
10 |
11 | **[Constrain](#Utils.constrain(layer,-constraints...))**: Set a layer's constraints, relative to its parent
12 |
13 | **Align**: Set all layers in an array to the same property value
14 |
15 | **Distribute**: Evenly distribute properties to layers in an array
16 |
17 | **Fit**: Set a layer's property to the max property among a group of layers
18 |
19 | **Contain**: Set a layer's spatial properties to contain its children.
20 |
21 | **Grid**: Set layers into a grid of rows and columns
22 |
23 | **MakeGrid**: Create a grid of copies from a layer
24 |
25 | **ChainAnimations**: Set an array of Animations to each start when the previous ends
26 |
27 | **PointInPolygon**: Check whether a point is within any straight-sided polygon
28 |
29 | **LayerAtPoint**: Get the top-most layer at a given point
30 |
31 | **LayersAtPoint**: Get all layers at a given point
32 |
33 | **GetLayerFromElement**: Get which (if any) Layer owns a given element
34 |
35 | **Bind**: Bind a function to a target
36 |
37 | **Define**: Create a new layer property that emits an event when it changes
38 |
39 | **DefineValid**: Create a new layer property with validation
40 |
41 | **SetAttributes**: Set the attributes of an DOM element
42 |
43 | **toMarkdown**: Set styles in a TextLayer, using (limited) Markdown syntax
44 |
45 | **CORSproxy**: Convert a URL into one that won't throw a cross-origin error
46 |
47 | **copyTextToClipboard**: Copy a string into the user's clipboard
48 |
49 | **timer**: Create a timer instance with a simple start/pause/resume/reset/restart methods
50 |
51 | **linkProperties**: When the specified property on one layer' changes, the second Layer will match it
52 |
53 | **px**: Get the correct pixel string for the given context scale
54 |
55 | **getOrdinal**: Will return the correct ordinal ('st', 'nd', 'rd', 'th) for a number
56 |
57 | **fetch**: Make an asynchronous call to a URL and return a Response
58 |
59 | **fetchJSON**: Make an asynchronous call to a URL and return data as a JSON object
60 |
61 | **randomText**: Get lorem text at the specified length, optionally in sentences
62 |
63 |
64 | # Installation
65 |
66 | ## Manual Install
67 | 1. Download this repository
68 | 2. With your project open in Framer, drag the 'moreutils.coffee' file the code editor
69 |
70 | ## Install via Framer Modules.
71 |
72 | [](https://open.framermodules.com/moreutils>)
73 |
74 | # Usage
75 |
76 | Framer uses an object called `Utils` to store common utility functions, such as `Utils.delay`. When this module is installed, it adds several new methods to this `Utils` object, such as `Utils.align`.
77 |
78 | Once the module has been installed, you can use these methods in your code the same way you would a standard Utils method. For example, `Utils.align(myLayers, 'x', '100')`.
79 |
80 | Each method is documented in the section below.
81 |
82 | # Methods
83 |
84 | In the documentation below, arguments between brackets are optional. For example, **Utils.chainAnimations** takes two arguments: an array of layers and a boolean (true or false) for whether or not the chain should loop. The second argument is set to `true` by default, so your calls to only have to provide this element when you want to the chain *not* to loop — or if you're feeling verbose. Either way, because the method will work without the second argument, we document it as **Utils.chainAnimations(layers, [animate])**, with brackets to show that the animate argument is optional.
85 |
86 | ## Utils.pin(layerA, layerB, directions...)
87 |
88 | Fixes **layerA**'s position relative to **layerB**. If layerB ever moves or changes, layerA will move with it in order to preserve this position. For the **directions** argument, you may use one or more directions: `'left'`, `'right'`, `'top'` or `'bottom'`).
89 |
90 | If multiple pins conflict, such as a pin to the `'top', 'bottom'`, only the last pin will get used. This method accepts up to two **directions** arguments.
91 |
92 | ```coffeescript
93 | Utils.pin(layerA, layerB, 'left')
94 | Utils.pin(layerA, layerB, 'left', 'top')
95 | ```
96 | ## Utils.unpin(layerA, [layerB, direction])
97 |
98 | Removes **layerA**'s pin relationships. If the optional argument with **layerB** is provided, only those relationships with **layerB** will be removed; likewise, if **layerA** has multiple pins to **layerB**, the **directions** argument can be used to remove specific pins.
99 |
100 | ```coffeescript
101 | Utils.pin(layerA, layerB, 'left', 'top')
102 | Utils.pin(layerA, layerC, 'left')
103 |
104 | Utils.unpin(layerA)
105 | # removes all of layerA's pins, both to layerB and layerC
106 |
107 | Utils.unpin(layerA, layerB)
108 | # removes only layerA's pins to layerB
109 | # layerA is still pinned to layerC
110 |
111 | Utils.unpin(layerA, layerB, 'left')
112 | # removes only layerA's left pin to layerB
113 | # layerA is still pinned to layerB's top
114 | ```
115 | ## Utils.constrain(layer, constraints...)
116 |
117 | Set a **layer**'s constraints, relative to its parent. This works the same as setting constraints in Design mode, where a **layer** may be constrained by one or more **constraints**. These are its parent's edges (`left`, `top`, `right`, `bottom`) or its parent's dimensions (`height`, `width`) and it may be set to preserve its `aspectRatio` as well. This method accepts as many **constraints** arguments as needed.
118 |
119 | When the parent layer changes its dimensions, the constrained layer may also transform, depending on the **constraints** set. Need a visual? Check out [this interactive example](https://framer.cloud/hCMbD).
120 |
121 | ```coffeescript
122 | Utils.constrain(layerA, 'height')
123 | Utils.constrain(layerA, 'height', 'left', 'aspectRatio')
124 | ```
125 |
126 | #### Utils.pinOrigin(layerA, layerB, [undo])
127 |
128 | #### Utils.align([layers], property, target, animate)
129 |
130 | #### Utils.distribute(layers, property, start, end, animate)
131 |
132 | #### Utils.grid(layers, [cols, rowMargin, colMargin])
133 |
134 | #### Utils.makeGrid(layer, cols, [rows, rowMargin, colMargin])
135 |
136 | #### Utils.fit(layer, layers, property, [padding])
137 |
138 | #### Utils.contain(layer, fit, paddingRight, paddingBottom)
139 |
140 | _Note: `Utils.contain` must be called after the children layer(s) size changes, any changes to children(s) sizes after calling `contain` won't be reflected._
141 |
142 | #### Utils.chainAnimations(animations, [looping])
143 |
144 | #### Utils.bind(target, function)
145 |
146 | #### Utils.pointInPolygon: (point, vertices)
147 |
148 | #### Utils.getLayerAtPoint: (point, vertices)
149 |
150 | #### Utils.getLayersAtPoint: (point, [layers])
151 |
152 | #### Utils.getLayerFromElement: (element, [layers])
153 |
154 | #### Utils.define: (layer, property, [value, callback])
155 |
156 | #### Utils.defineValid: (layer, property, value, validation, error, [callback])
157 |
158 | #### Utils.setAttributes: (element, properties)
159 |
--------------------------------------------------------------------------------
/docs/Timer.html:
--------------------------------------------------------------------------------
1 |
Class Timer | CSDoc Namespace Inheritance Timer → Object Source moreutils.coffee, line 718 This class has no description.
Timer
This method has no description.
Timer
This method has no description.
Timer
This method has no description.
Timer
This method has no description.
Timer
This method has no description.
Timer
This method has no description.
--------------------------------------------------------------------------------
/docs/csdoc.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | height: 100%;
4 | background-color: #eee;
5 | }
6 | #wrap {
7 | min-height: 100%;
8 | height: auto;
9 | margin: 0 auto -60px;
10 | padding: 0 0 60px;
11 | }
12 | #footer {
13 | height: 60px;
14 | background-color: #f5f5f5;
15 | }
16 | #wrap > .container {
17 | padding: 50px 15px 0;
18 | }
19 | .container .credit {
20 | margin: 20px 0;
21 | }
22 | #footer > .container {
23 | padding-left: 15px;
24 | padding-right: 15px;
25 | }
26 | code {
27 | font-size: 80%;
28 | }
29 | .well {
30 | background: transparent;
31 | border: none;
32 | border-radius: 0;
33 | border-top: 1px solid #eee;
34 | box-shadow: none;
35 | padding: 9px;
36 | margin: 0;
37 | }
38 | .navbar-form.navbar-right {
39 | margin: 8px 40px 8px 0;
40 | }
41 | dd > p {
42 | margin: 0;
43 | }
44 | .cs-main {
45 | background-color: #fff;
46 | padding: 0 30px;
47 | }
48 | .cs-main h3.cs-header {
49 | background-color: #eee;
50 | margin: 10px -30px 30px -30px;
51 | padding: 30px 0 10px;
52 | }
53 | .cs-main h4.cs-header {
54 | background-color: #f6f6f6;
55 | margin: 0;
56 | padding: 10px 9px;
57 | }
58 | .cs-main .cs-defined {
59 | margin: 10px 9px;
60 | }
61 | .cs-main pre {
62 | border: none;
63 | border-radius: 0;
64 | background-color: #fffaed;
65 | }
66 | .cs-main > .cs-class > .cs-methods > .cs-builtin.cs-inherited {
67 | display: none;
68 | }
69 | .cs-main > .cs-methods > .cs-methods > li.cs-builtin {
70 | display: none;
71 | }
72 | .cs-main dl.cs-arguments {
73 | margin-top: 0;
74 | }
75 | .cs-main dl.cs-arguments dt {
76 | text-align: left;
77 | }
78 | .cs-main .cs-arguments-title {
79 | font-weight: bold;
80 | margin: 15px 0 0 0;
81 | color: #ccc;
82 | }
83 | .cs-nav {
84 | padding-top: 15px;
85 | }
86 | .cs-nav h5 {
87 | padding: 15px 0 5px 10px;
88 | margin: 0;
89 | font-size: 12px;
90 | text-transform: uppercase;
91 | color: #aaa;
92 | }
93 | .cs-nav h5 > a {
94 | color: #aaa;
95 | }
96 | .cs-nav ul > li > a {
97 | padding: 5px 10px;
98 | }
99 | @media (max-width:767px) {
100 | .cs-main h3 {
101 | padding-left: 40px;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/docs/global/Object.html:
--------------------------------------------------------------------------------
1 | Class Object | CSDoc Namespace global Inheritance Object Subclasses Timer This class has no description.
Object
Create instance of the class.
--------------------------------------------------------------------------------
/docs/global/index.html:
--------------------------------------------------------------------------------
1 | Namespace global | CSDoc built-in
This class has no description.
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 | Namespace | CSDoc
--------------------------------------------------------------------------------
/docs/methods.html:
--------------------------------------------------------------------------------
1 | Methods | CSDoc Pin a layer to another layer. When the second layer moves, the first one will too.
2 |
3 |
Utils.pin(layerA, layerB, 'left')
4 |
Arguments
layer The layer to pin.
target The layer to pin to.
directions Which sides of the layer to pin to.
Remove all of a layer's pins, or pins from a certain target layer and/or direction.
5 |
6 |
Utils.unpin(layerA)
7 |
Arguments
layer The layer to unpin.
target optional The layer to unpin from.
directions optional The directions to unpin.
Pin layer to another layer, based on the first layer's origin.
8 |
9 |
Utils.pinOrigin(layerA, layerB)
10 |
Arguments
layer The layer to pin.
target optional The layer to pin to.
undo optional Remove, rather than create, this pin.
Pin layer to another layer, based on the first layer's originX.
11 |
12 |
Utils.pinOriginX(layerA, layerB)
13 |
Arguments
layer The layer to pin.
target optional The layer to pin to.
undo optional Remove, rather than create, this pin.
Pin layer to another layer, based on the first layer's originY.
14 |
15 |
Utils.pinOriginY(layerA, layerB)
16 |
Arguments
layer The layer to pin.
target optional The layer to pin to.
undo optional Remove, rather than create, this pin.
Set a layer's contraints to its parent
17 |
18 |
Valid options are: 'left', 'top', 'right', 'bottom', 'height', 'width', and 'aspectRatio'.
19 |
20 |
Utils.constrain(layer, 'left', 'top', 'apectRatio')
21 |
Arguments
layer The layer to constrain.
options The constraint options to use.
Immediately execute a function that is bound to the target.
22 |
23 |
Utils.bind(myLayer, -> this.name = "My Layer")
24 |
Arguments
object The object to bind the callback to.
callback The callback to run.
Define a property on a Layer that will emit a change event when that property changes. Also, optionally give the property an initial value and a callback to run when the property changes.
25 |
26 |
Utils.define(myLayer, "toggled")
27 | Utils.define(myLayer, "toggled", false)
28 | Utils.define(myLayer, "toggled", false, myLayer.showToggled)
29 | Utils.define(myLayer, "toggled", false, null, _.isBoolean, "Layer.toggled must be true or false.")
30 |
Arguments
layer The layer on which to define the property.
property The name of the property.
value optional The initial value of the property.
callback optional The callback to run when this property changes. Executed with two arguments: the property's new value and the Layer itself.
validation optional A function to validate the property's new value.
error optional An error to throw if the validation function returned false.
Set all layers in an array to the same property or properties.
31 |
32 |
Utils.align [layerA, layerB],
33 | x: 200
34 |
35 | Utils.align [layerA, layerB],
36 | x: 200
37 | true
38 | time: .5
39 |
Arguments
layers The array of layers to align.
animate optional Whether to animate to the new property.
animationOptions optional The animation options to use.
options The properties to set.
Distribute an array of layers between two values.
40 |
41 |
Utils.align [layerA, layerB], 'x'
42 |
43 | Utils.align [layerA, layerB], 'x', 32, 200
44 |
45 | Utils.align [layerA, layerB], 'x', 32, 200, true, {time: .5}
46 |
47 |
48 |
Also works with 'horizontal' and 'vertical', (alias to 'midX' and 'midY').
49 |
50 |
Utils.align [layerA, layerB], 'horizontal'
51 |
Arguments
layers The array of layers to distribute.
property The property to distribute.
start optional The value to start from. By default, the lowest value of the given property among the layers array.
end optional The value to distribute to. By default, the highest value of the given property among the layers array.
animate optional Whether to animate to the new property.
animationOptions optional The animation options to use.
Offset an array of layers vertically.
52 |
53 |
Utils.align [layerA, layerB],
54 | x: 200
55 |
56 | Utils.align [layerA, layerB],
57 | x: 200
58 | true
59 | time: .5
60 |
Arguments
layers The array of layers to offset.
distance The distance between each layer.
animate optional Whether to animate layers to the new position.
animationOptions optional The animation options to use.
Offset an array of layers horizontally.
61 |
62 |
Utils.align [layerA, layerB],
63 | x: 200
64 |
65 | Utils.align [layerA, layerB],
66 | x: 200
67 | true
68 | time: .5
69 |
Arguments
distance The distance between each layer.
animate optional Whether to animate layers to the new position.
animationOptions optional The animation options to use.
array The array of layers to offset.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
This method has no description.
--------------------------------------------------------------------------------
/example.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 |
--------------------------------------------------------------------------------
/example.framer/framer/.bookmark:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/.bookmark
--------------------------------------------------------------------------------
/example.framer/framer/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "orientation" : 0,
3 | "updateDelay" : 0.29999999999999999,
4 | "designModeSelected" : 0,
5 | "cachedDeviceHeight" : 667,
6 | "contentScale" : 1,
7 | "cachedDeviceWidth" : 375,
8 | "fullScreen" : false,
9 | "deviceType" : "apple-iphone-8-space-gray",
10 | "sharedPrototype" : 0,
11 | "propertyPanelToggleStates" : {
12 |
13 | },
14 | "projectId" : "90F5112C-2205-4493-8741-4BB0F8E9E3FB",
15 | "deviceOrientation" : 0,
16 | "selectedHand" : "",
17 | "showBezel" : true,
18 | "foldedCodeRanges" : [
19 | "{77, 105}",
20 | "{183, 2571}",
21 | "{2788, 769}",
22 | "{3558, 1874}",
23 | "{5433, 479}",
24 | "{5913, 266}",
25 | "{6420, 2025}",
26 | "{8446, 4409}",
27 | "{12856, 2967}",
28 | "{15824, 4331}",
29 | "{20156, 4564}",
30 | "{24721, 4870}",
31 | "{29592, 1202}",
32 | "{30795, 743}"
33 | ],
34 | "deviceScale" : "fit"
35 | }
--------------------------------------------------------------------------------
/example.framer/framer/design.vekter:
--------------------------------------------------------------------------------
1 | {
2 | "root" : {
3 | "__class" : "CanvasNode",
4 | "children" : [
5 |
6 | ],
7 | "id" : "QP~O_K3j",
8 | "parentid" : null
9 | },
10 | "version" : 20
11 | }
--------------------------------------------------------------------------------
/example.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":"apple-iphone-8-space-gray","contentScale":1,"hideBezel":false,"orientation":0};
7 | }
8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":"fit","selectedHand":"","deviceType":"apple-iphone-8-space-gray","contentScale":1,"hideBezel":false,"orientation":0};
9 | }
10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"example.framer"};
11 |
12 | Framer.Device = new Framer.DeviceView();
13 | Framer.Device.setupContext();
--------------------------------------------------------------------------------
/example.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 |
--------------------------------------------------------------------------------
/example.framer/framer/framer.vekter.js:
--------------------------------------------------------------------------------
1 | (function(scope) {if (scope["__vekterVariables"]) { scope["__vekterVariables"].map(function(variable) { delete scope[variable] } ) };Object.assign(scope, {});scope["__vekterVariables"] = [""];if (typeof Framer.CurrentContext.layout === 'function') {Framer.CurrentContext.layout()};})(window);
--------------------------------------------------------------------------------
/example.framer/framer/images/cursor-active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/images/cursor-active.png
--------------------------------------------------------------------------------
/example.framer/framer/images/cursor-active@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/images/cursor-active@2x.png
--------------------------------------------------------------------------------
/example.framer/framer/images/cursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/images/cursor.png
--------------------------------------------------------------------------------
/example.framer/framer/images/cursor@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/images/cursor@2x.png
--------------------------------------------------------------------------------
/example.framer/framer/images/icon-120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/images/icon-120.png
--------------------------------------------------------------------------------
/example.framer/framer/images/icon-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/images/icon-152.png
--------------------------------------------------------------------------------
/example.framer/framer/images/icon-180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/images/icon-180.png
--------------------------------------------------------------------------------
/example.framer/framer/images/icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/images/icon-192.png
--------------------------------------------------------------------------------
/example.framer/framer/images/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/images/icon-76.png
--------------------------------------------------------------------------------
/example.framer/framer/manifest (SRUIZ-2.local's conflicted copy 2017-12-19).txt:
--------------------------------------------------------------------------------
1 | app.coffee
2 | audiofiles/audiotrack1.m4a
3 | framer/coffee-script.js
4 | framer/config.json
5 | framer/framer.generated.js
6 | framer/framer.init.js
7 | framer/framer.js
8 | framer/framer.modules.js
9 | framer/framer.vekter.js
10 | framer/images/cursor-active.png
11 | framer/images/cursor-active@2x.png
12 | framer/images/cursor.png
13 | framer/images/cursor@2x.png
14 | framer/images/icon-120.png
15 | framer/images/icon-152.png
16 | framer/images/icon-180.png
17 | framer/images/icon-192.png
18 | framer/images/icon-76.png
19 | framer/manifest (SRUIZ.local's conflicted copy 2017-12-18).txt
20 | framer/manifest.txt
21 | framer/preview (Stephens-iMac.local's conflicted copy 2017-12-18).png
22 | framer/preview.png
23 | framer/style.css
24 | framer/version
25 | images/statusbar_left.png
26 | images/statusbar_right.png
27 | index.html
28 | modules/Icon.coffee
29 | modules/icons.json
30 | modules/myModule.coffee
31 | modules/SVGComponent.coffee
--------------------------------------------------------------------------------
/example.framer/framer/manifest (SRUIZ.local's conflicted copy 2017-12-18).txt:
--------------------------------------------------------------------------------
1 | app.coffee
2 | index.html
3 | images/statusbar_left.png
4 | images/statusbar_right.png
5 | framer/preview.png
6 | framer/manifest.txt
7 | framer/images/cursor.png
8 | framer/images/cursor-active@2x.png
9 | framer/images/icon-120.png
10 | framer/images/cursor@2x.png
11 | framer/images/icon-192.png
12 | framer/images/icon-76.png
13 | framer/images/cursor-active.png
14 | framer/images/icon-152.png
15 | framer/images/icon-180.png
16 | framer/config.json
17 | framer/framer.vekter.js
18 | framer/framer.modules.js
19 | framer/version
20 | framer/style.css
21 | framer/framer.generated.js
22 | framer/coffee-script.js
23 | framer/preview (Stephens-iMac.local's conflicted copy 2017-12-18).png
24 | framer/framer.init.js
25 | framer/framer.js
26 | audiofiles/audiotrack1.m4a
27 | modules/SVGComponent.coffee
28 | modules/icons.json
29 | modules/myModule.coffee
30 | modules/Icon.coffee
--------------------------------------------------------------------------------
/example.framer/framer/preview (SRUIZ-2.local's conflicted copy 2017-12-19).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/preview (SRUIZ-2.local's conflicted copy 2017-12-19).png
--------------------------------------------------------------------------------
/example.framer/framer/preview (SRUIZ.local's conflicted copy 2017-12-19).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/preview (SRUIZ.local's conflicted copy 2017-12-19).png
--------------------------------------------------------------------------------
/example.framer/framer/preview (Stephens-iMac.local's conflicted copy 2017-12-18).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/framer/preview (Stephens-iMac.local's conflicted copy 2017-12-18).png
--------------------------------------------------------------------------------
/example.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 | }
--------------------------------------------------------------------------------
/example.framer/framer/version:
--------------------------------------------------------------------------------
1 | 12
--------------------------------------------------------------------------------
/example.framer/images/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/images/.gitkeep
--------------------------------------------------------------------------------
/example.framer/images/statusbar_left.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/images/statusbar_left.png
--------------------------------------------------------------------------------
/example.framer/images/statusbar_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example.framer/images/statusbar_right.png
--------------------------------------------------------------------------------
/example.framer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/example_inProgress.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 |
--------------------------------------------------------------------------------
/example_inProgress.framer/.idea/cs-ui-dev.framer.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/example_inProgress.framer/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example_inProgress.framer/.idea/watcherTasks.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/example_inProgress.framer/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | print
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | true
32 | DEFINITION_ORDER
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
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 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | 1515582269914
106 |
107 |
108 | 1515582269914
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/.bookmark:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/.bookmark
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "orientation" : 0,
3 | "updateDelay" : 0.29999999999999999,
4 | "designModeSelected" : 0,
5 | "cachedDeviceHeight" : 667,
6 | "contentScale" : 1,
7 | "cachedDeviceWidth" : 375,
8 | "fullScreen" : false,
9 | "deviceType" : "apple-iphone-8-space-gray",
10 | "sharedPrototype" : true,
11 | "propertyPanelToggleStates" : {
12 |
13 | },
14 | "projectId" : "F5051C27-0A65-4E22-A973-370972389414",
15 | "deviceOrientation" : 0,
16 | "selectedHand" : "",
17 | "showBezel" : true,
18 | "foldedCodeRanges" : [
19 | "{22, 308}",
20 | "{372, 4698}",
21 | "{5071, 1320}",
22 | "{6392, 2312}",
23 | "{8705, 3352}",
24 | "{12058, 1567}",
25 | "{13626, 1782}",
26 | "{15409, 1183}"
27 | ],
28 | "deviceScale" : "fit"
29 | }
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/design.vekter:
--------------------------------------------------------------------------------
1 | {
2 | "root" : {
3 | "__class" : "CanvasNode",
4 | "children" : [
5 |
6 | ],
7 | "id" : "QP~O_K3j",
8 | "parentid" : null
9 | },
10 | "version" : 20
11 | }
--------------------------------------------------------------------------------
/example_inProgress.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":"apple-iphone-8-space-gray","contentScale":1,"hideBezel":false,"orientation":0};
7 | }
8 | if (window.Framer) {window.Framer.Defaults.DeviceComponent = {"deviceScale":"fit","selectedHand":"","deviceType":"apple-iphone-8-space-gray","contentScale":1,"hideBezel":false,"orientation":0};
9 | }
10 | window.FramerStudioInfo = {"deviceImagesUrl":"\/_server\/resources\/DeviceImages","documentTitle":"example_inProgress.framer"};
11 |
12 | Framer.Device = new Framer.DeviceView();
13 | Framer.Device.setupContext();
--------------------------------------------------------------------------------
/example_inProgress.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 |
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/framer.vekter.js:
--------------------------------------------------------------------------------
1 | (function(scope) {if (scope["__vekterVariables"]) { scope["__vekterVariables"].map(function(variable) { delete scope[variable] } ) };Object.assign(scope, {});scope["__vekterVariables"] = [""];if (typeof Framer.CurrentContext.layout === 'function') {Framer.CurrentContext.layout()};})(window);
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/images/cursor-active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/images/cursor-active.png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/images/cursor-active@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/images/cursor-active@2x.png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/images/cursor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/images/cursor.png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/images/cursor@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/images/cursor@2x.png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/images/icon-120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/images/icon-120.png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/images/icon-152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/images/icon-152.png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/images/icon-180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/images/icon-180.png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/images/icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/images/icon-192.png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/images/icon-76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/images/icon-76.png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/manifest (SRUIZ-2.local's conflicted copy 2017-12-19).txt:
--------------------------------------------------------------------------------
1 | app.coffee
2 | audiofiles/audiotrack1.m4a
3 | framer/coffee-script.js
4 | framer/config.json
5 | framer/framer.generated.js
6 | framer/framer.init.js
7 | framer/framer.js
8 | framer/framer.modules.js
9 | framer/framer.vekter.js
10 | framer/images/cursor-active.png
11 | framer/images/cursor-active@2x.png
12 | framer/images/cursor.png
13 | framer/images/cursor@2x.png
14 | framer/images/icon-120.png
15 | framer/images/icon-152.png
16 | framer/images/icon-180.png
17 | framer/images/icon-192.png
18 | framer/images/icon-76.png
19 | framer/manifest (SRUIZ.local's conflicted copy 2017-12-18).txt
20 | framer/manifest.txt
21 | framer/preview (Stephens-iMac.local's conflicted copy 2017-12-18).png
22 | framer/preview.png
23 | framer/style.css
24 | framer/version
25 | images/statusbar_left.png
26 | images/statusbar_right.png
27 | index.html
28 | modules/Icon.coffee
29 | modules/icons.json
30 | modules/myModule.coffee
31 | modules/SVGComponent.coffee
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/manifest (SRUIZ.local's conflicted copy 2017-12-18).txt:
--------------------------------------------------------------------------------
1 | app.coffee
2 | index.html
3 | images/statusbar_left.png
4 | images/statusbar_right.png
5 | framer/preview.png
6 | framer/manifest.txt
7 | framer/images/cursor.png
8 | framer/images/cursor-active@2x.png
9 | framer/images/icon-120.png
10 | framer/images/cursor@2x.png
11 | framer/images/icon-192.png
12 | framer/images/icon-76.png
13 | framer/images/cursor-active.png
14 | framer/images/icon-152.png
15 | framer/images/icon-180.png
16 | framer/config.json
17 | framer/framer.vekter.js
18 | framer/framer.modules.js
19 | framer/version
20 | framer/style.css
21 | framer/framer.generated.js
22 | framer/coffee-script.js
23 | framer/preview (Stephens-iMac.local's conflicted copy 2017-12-18).png
24 | framer/framer.init.js
25 | framer/framer.js
26 | audiofiles/audiotrack1.m4a
27 | modules/SVGComponent.coffee
28 | modules/icons.json
29 | modules/myModule.coffee
30 | modules/Icon.coffee
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/manifest (Stephen Ruiz's conflicted copy 2018-01-18).txt:
--------------------------------------------------------------------------------
1 | app.coffee
2 | index.html
3 | images/Default.webp
4 | images/Default.svg
5 | images/Global/Cards/Progress/Other/Todo.svg
6 | images/Global/Cards/Progress/Other/Unavailable.svg
7 | images/Global/Cards/Progress/Other/Done.svg
8 | framer/preview.png
9 | framer/manifest.txt
10 | framer/images/cursor.png
11 | framer/images/cursor-active@2x.png
12 | framer/images/icon-120.png
13 | framer/images/cursor@2x.png
14 | framer/images/icon-192.png
15 | framer/images/icon-76.png
16 | framer/images/cursor-active.png
17 | framer/images/icon-152.png
18 | framer/images/icon-180.png
19 | framer/config.json
20 | framer/manifest (SRUIZ-2.local's conflicted copy 2017-12-19).txt
21 | framer/framer.vekter.js
22 | framer/framer.modules.js
23 | framer/version
24 | framer/style.css
25 | framer/manifest (SRUIZ.local's conflicted copy 2017-12-18).txt
26 | framer/framer.generated.js
27 | framer/coffee-script.js
28 | framer/preview (Stephens-iMac.local's conflicted copy 2017-12-18).png
29 | framer/preview (SRUIZ.local's conflicted copy 2017-12-19).png
30 | framer/framer.init.js
31 | framer/preview (SRUIZ-2.local's conflicted copy 2017-12-19).png
32 | framer/framer.js
33 | icons/Careers/disciplined.svg
34 | icons/Careers/failfixfast.svg
35 | icons/Careers/obsess_inactive.svg
36 | icons/Careers/proud.svg
37 | icons/Careers/deliver_inactive.svg
38 | icons/Careers/focused.svg
39 | icons/Careers/fight_inactive.svg
40 | icons/Careers/deliver.svg
41 | icons/Careers/lead_inactive.svg
42 | icons/Careers/failfixfast_inactive.svg
43 | icons/Careers/proud_inactive.svg
44 | icons/Careers/lead.svg
45 | icons/Careers/fight.svg
46 | icons/Careers/focused_inactive.svg
47 | icons/Careers/obsess.svg
48 | icons/Careers/disciplined_inactive.svg
49 | icons/Coaching/savings.svg
50 | icons/Coaching/shapeup_inactive.svg
51 | icons/Coaching/protect_inactive.svg
52 | icons/Coaching/savings_inactive.svg
53 | icons/Coaching/build.svg
54 | icons/Coaching/Time.svg
55 | icons/Coaching/flag.svg
56 | icons/Coaching/mortgages.svg
57 | icons/Coaching/maximise_inactive.svg
58 | icons/Coaching/carfinance_inactive.svg
59 | icons/Coaching/repair.svg
60 | icons/Coaching/maximise.svg
61 | icons/Coaching/mortgages_inactive.svg
62 | icons/Coaching/play.svg
63 | icons/Coaching/protect.svg
64 | icons/Coaching/shapeup.svg
65 | icons/Coaching/carfinance.svg
66 | icons/Coaching/build_inactive.svg
67 | icons/Coaching/repair_inactive.svg
68 | icons/Coaching/play_inactive.svg
69 | modules/gotcha/module.json
70 | modules/gotcha/gotcha.coffee
71 | modules/cs.coffee
72 | modules/MoreUtils.coffee
73 | modules/cs-components/Separator.coffee
74 | modules/cs-components/View.coffee
75 | modules/cs-components/Card.coffee
76 | modules/cs-components/Footer.coffee
77 | modules/cs-components/Carousel.coffee
78 | modules/cs-components/Link.coffee
79 | modules/cs-components/Icon.coffee
80 | modules/cs-components/Typography.coffee
81 | modules/cs-components/Header.coffee
82 | modules/cs-components/fonts/AktivGrotesk_W_Lt.woff
83 | modules/cs-components/fonts/AktivGrotesk_W_Rg.woff
84 | modules/cs-components/fonts/AktivGrotesk_W_Hair.woff
85 | modules/cs-components/fonts/AktivGrotesk_W_Md.woff
86 | modules/cs-components/Button.coffee
87 | modules/cs-components/Colors.coffee
88 | .idea/workspace.xml
89 | .idea/modules.xml
90 | .idea/watcherTasks.xml
91 | .idea/cs-ui-dev.framer.iml
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/preview (SRUIZ-2.local's conflicted copy 2017-12-19).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/preview (SRUIZ-2.local's conflicted copy 2017-12-19).png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/preview (SRUIZ.local's conflicted copy 2017-12-19).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/preview (SRUIZ.local's conflicted copy 2017-12-19).png
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/preview (Stephens-iMac.local's conflicted copy 2017-12-18).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/framer/preview (Stephens-iMac.local's conflicted copy 2017-12-18).png
--------------------------------------------------------------------------------
/example_inProgress.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 | }
--------------------------------------------------------------------------------
/example_inProgress.framer/framer/version:
--------------------------------------------------------------------------------
1 | 12
--------------------------------------------------------------------------------
/example_inProgress.framer/images/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/images/.gitkeep
--------------------------------------------------------------------------------
/example_inProgress.framer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Button.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 | MODEL = 'button'
4 |
5 | class exports.Button extends Layer
6 | constructor: (options = {}) ->
7 | theme = Theme.theme
8 | @__constructor = true
9 | @__instancing = true
10 |
11 | # light primary
12 | if !options.dark and !options.secondary
13 | @palette = 'light_primary'
14 | else if !options.dark and options.secondary
15 | @palette = 'light_secondary'
16 | else if options.dark and !options.secondary
17 | @palette = 'dark_primary'
18 | else if options.dark and options.secondary
19 | @palette = 'dark_secondary'
20 |
21 | # ---------------
22 | # Options
23 |
24 | _.defaults options,
25 | x: 0
26 | y: 0
27 | height: theme[MODEL][@palette]['default'].height ? 48
28 | text: 'Get Started'
29 | animationOptions:
30 | time: .2
31 | colorModel: 'husl'
32 |
33 | dark: false
34 | secondary: false
35 | disabled: false
36 | icon: undefined
37 | select: => null
38 | model: MODEL
39 | loadTime: 0
40 |
41 | @customTheme = if options.backgroundColor? and options.color? then @_getCustomTheme(options.color, options.backgroundColor) else undefined
42 |
43 | @customOptions =
44 | color: options.color
45 | backgroundColor: options.backgroundColor
46 |
47 | parent = options.parent
48 | delete options.parent
49 |
50 | super options
51 |
52 | _.assign @,
53 | model: options.model
54 |
55 | # ---------------
56 | # Layers
57 |
58 | palette = theme[@model][@palette]['default']
59 |
60 | # content container
61 |
62 | @content = new Layer
63 | name: "Content"
64 | parent: @
65 | width: 999
66 | height: @height
67 | backgroundColor: null
68 |
69 | # text layer
70 |
71 | @textLayer = new Label
72 | name: 'TextLayer'
73 | parent: @content
74 | y: Align.center()
75 | textAlign: 'center'
76 | fontWeight: palette.fontWeight
77 | color: palette.color
78 | text: options.text ? ''
79 |
80 | Utils.linkProperties @, @textLayer, "color"
81 |
82 | # loading icon
83 |
84 | @loadingIcon = new Icon
85 | name: 'Loading Icon'
86 | parent: @content
87 | icon: "loading"
88 | color: palette.color
89 | y: Align.center()
90 | visible: false
91 |
92 | Utils.linkProperties @, @loadingIcon, "color"
93 |
94 | if options.icon? # show our icon...
95 |
96 | @iconLayer = new Icon
97 | name: 'Icon'
98 | parent: @content
99 | y: Align.center()
100 | width: 24
101 | height: 24
102 | color: palette.color
103 | icon: options.icon
104 |
105 | Utils.linkProperties @, @iconLayer, "color"
106 |
107 | if @textLayer.text.length > 0
108 | _.assign @textLayer,
109 | x: @iconLayer.maxX + 8
110 | padding: {right: 4}
111 |
112 | @content.width = _.maxBy(@content.children, 'maxX').maxX
113 | @loadingIcon.x = Align.center()
114 |
115 | if options.width
116 | @content.x = Align.center()
117 | else
118 | @content.x = 20
119 | @width = @content.width + 40
120 |
121 | @on "change:width", =>
122 | @content.x = Align.center()
123 |
124 | else # if there's no icon...
125 |
126 | if options.width
127 | @content.x = 0
128 | @content.width = @width
129 | @textLayer.x = Align.center()
130 | @loadingIcon.x = Align.center()
131 |
132 | else
133 | @content.x = 22
134 | @content.width = @textLayer.width
135 | @width = @content.width + 44
136 | @loadingIcon.x = Align.center()
137 |
138 | @on "change:width", =>
139 | @content.x = 0
140 | @content.width = @width
141 | @textLayer.x = Align.center()
142 | @loadingIcon.x = Align.center()
143 |
144 | # Fix position, now that we have our size
145 |
146 | @props =
147 | parent: parent
148 | x: options.x ? 0
149 | y: options.y ? 0
150 |
151 | @_setTheme('default')
152 |
153 | # ---------------
154 | # Definitions
155 |
156 | delete @__constructor
157 |
158 | # Definitions: Property Initial value Callback Validation Error
159 | Utils.define @, 'theme', "default", @_setTheme, _.isString, "Button.theme must be a string."
160 | Utils.define @, 'dark', options.dark, undefined, _.isBoolean, "Button.dark must be a boolean (true or false).",
161 | Utils.define @, 'secondary', options.secondary, undefined, _.isBoolean, "Button.secondary must be a boolean (true or false).",
162 | Utils.define @, 'select', options.select, undefined, _.isFunction, "Button.select must be a function."
163 | Utils.define @, 'disabled', options.disabled, @_showDisabled, _.isBoolean, "Button.disabled must be a boolean (true or false)."
164 | Utils.define @, 'hovered', false, @_showHovered, _.isBoolean, "Button.hovered must be a boolean (true or false)."
165 | Utils.define @, 'loadTime', options.loadTime, undefined, _.isNumber, "Button.loadTime must be a number."
166 | Utils.define @, 'loading', options.loading, @_showLoading, _.isBoolean, "Button.loading must be a boolean (true or false)."
167 |
168 | delete @__instancing
169 |
170 | # ---------------
171 | # Events
172 |
173 | @onMouseOver => @hovered = true
174 | @onMouseOut => @hovered = false
175 |
176 |
177 | if Utils.isMobile()
178 | @onTap @_doSelect
179 |
180 | else
181 | @onTouchStart (event) => @_showTouching(true, null, event)
182 | @onTouchEnd (event) => @_showTouching(false, null, event)
183 |
184 | @onTap @_showTapped
185 | @onPan @_panOffTouch
186 |
187 | # ---------------
188 | # Cleanup
189 |
190 | if not options.showSublayers then child.name = '.' for child in @children
191 |
192 | # ---------------
193 | # Private Methods
194 |
195 | _getCustomTheme: (color, backgroundColor) ->
196 | color = new Color(color)
197 | bg = new Color(backgroundColor)
198 |
199 | customTheme =
200 | default:
201 | color: color
202 | borderColor: bg.darken(10)
203 | backgroundColor: bg
204 | shadowColor: 'rgba(0,0,0,.16)'
205 | disabled:
206 | color: color.alpha(.15)
207 | borderColor: color.alpha(.15)
208 | backgroundColor: bg.alpha(0)
209 | shadowColor: 'rgba(0,0,0,0)'
210 | touched:
211 | color: color
212 | borderColor: bg.darken(20)
213 | backgroundColor: bg.darken(20)
214 | shadowColor: 'rgba(0,0,0,0)'
215 | hovered:
216 | color: color
217 | borderColor: bg.darken(20)
218 | backgroundColor: bg.darken(10)
219 | shadowColor: 'rgba(0,0,0,.16)'
220 |
221 | return customTheme
222 |
223 |
224 | _setTheme: (value) =>
225 | @animateStop()
226 | props = @customTheme?[value] ? _.defaults(
227 | _.clone(@customOptions),
228 | theme[@model][@palette][value]
229 | )
230 |
231 | if @__instancing then @props = props
232 | else @animate props
233 |
234 |
235 | _showLoading: (bool) =>
236 | if bool is true
237 | # show loading
238 | for layer in [@iconLayer, @textLayer]
239 | layer?.animate
240 | opacity: 0
241 | options: {time: .15}
242 |
243 | _.assign @loadingIcon,
244 | visible: true
245 | opacity: 0
246 |
247 | @loadingIcon.animate
248 | opacity: 1
249 | options: {time: .15, delay: .15}
250 |
251 | @loadingIcon.animate
252 | rotation: 360
253 | options:
254 | curve: "linear"
255 | time: 1
256 | looping: true
257 | return
258 |
259 | # show not loading
260 | @loadingIcon.once Events.AnimationEnd,
261 | _.assign @loadingIcon,
262 | visible: false
263 | opacity: 0
264 | rotation: 0
265 |
266 | @loadingIcon.animateStop()
267 |
268 | @loadingIcon.animate
269 | opacity: 0
270 | options: {time: .15}
271 |
272 | for layer in [@iconLayer, @textLayer]
273 | layer?.animate
274 | opacity: 1
275 | options: {time: .15, delay: .15}
276 |
277 | _showHovered: (bool) =>
278 | return if @disabled
279 |
280 | if bool
281 | # show hovered
282 | @theme = 'hovered'
283 | return
284 |
285 | # show not hovered
286 | @theme = 'default'
287 |
288 |
289 | _showDisabled: (bool) =>
290 | if bool
291 | # show disabled
292 | @theme = 'disabled'
293 | @ignoreEvents = true
294 | return
295 |
296 | # show not disabled
297 | @theme = 'default'
298 | @ignoreEvents = false
299 |
300 |
301 | _showTapped: =>
302 | return if @disabled
303 | return if @_isTouching is true
304 |
305 | @theme = "touched"
306 | Utils.delay .1, => @theme = "default"
307 |
308 |
309 | _showTouching: (isTouching, silent = false, event) =>
310 | return if @disabled
311 |
312 | if isTouching
313 | # show touching
314 | @_isTouching = true
315 | @theme = "touched"
316 | return
317 |
318 | # show not touching
319 | return if not @_isTouching
320 | @_isTouching = false
321 | @theme = "default"
322 |
323 | unless silent then @_doSelect(event)
324 |
325 |
326 | _doSelect: (event) =>
327 | return if @disabled
328 |
329 | if @loadTime > 0
330 | @loading = true
331 | Utils.delay @loadTime, =>
332 | @select(event, @)
333 | @emit "select", @
334 | @loading = false
335 | return
336 |
337 | try @select(event, @)
338 | @emit "select", @
339 |
340 |
341 | _panOffTouch: (event) =>
342 | return if @_isTouching is false
343 | return if @disabled
344 | return if @theme is "default"
345 |
346 | if Math.abs(event.offset.x) > @width/2 or
347 | Math.abs(event.offset.y) > @height/2
348 | @theme = "default"
349 |
350 | # ---------------
351 | # Public Methods
352 |
353 | onSelect: (callback) => @select = callback
354 |
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/CarouselComponent.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | # Carousel
5 |
6 | class exports.CarouselComponent extends Layer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 |
10 | @__constructor = true
11 |
12 | _.assign @,
13 | _pages: []
14 | _startPage: undefined
15 | _currentPage: undefined
16 | _prevPage: undefined
17 | _shape: undefined
18 | _pageProps: undefined
19 | _opacityScale: undefined
20 | _padding: undefined
21 | _scaleScale: undefined
22 | _traveling: undefined
23 |
24 | _.defaults options,
25 | name: 'CarouselComponent'
26 | x: Align.center()
27 | animationOptions: {time: .5}
28 | backgroundColor: null
29 |
30 | pages: []
31 | startPage: 2
32 | shape: 'line'
33 | opacityScale: .25
34 | scaleScale: .25
35 | padding: 0
36 |
37 | super options
38 |
39 | delete @__constructor
40 |
41 | @on "change:shape", @_setShape
42 |
43 | @on "change:currentPage", (page) ->
44 | @snapToPage(page)
45 |
46 | @onSwipeLeftEnd ->
47 | @rotatePages('right')
48 | @emit "interaction"
49 |
50 | @onSwipeRightEnd ->
51 | @rotatePages('left')
52 | @emit "interaction"
53 |
54 | # @onPan (event) ->
55 | # if Math.abs(event.offset.x) > 32
56 | # app?.current.disableScroll()
57 | # else
58 | # app?.current.enableScroll()
59 | #
60 | # @onPanEnd -> app?.current.enableScroll()
61 |
62 | # start
63 |
64 | @shape = options.shape
65 | @_startPage = options.startPage
66 |
67 | for page in options.pages
68 | @addPage(page)
69 |
70 | Utils.delay .1, =>
71 | if not @currentPage? and @pages[0]?
72 | @snapToPage(@pages[0], false)
73 |
74 | _rotatePageIndices: (steps = 0, animate = true, direction) ->
75 | if steps > 0
76 | @pages.push(@pages.shift())
77 | @_rotatePageIndices(steps - 1, animate, 'left')
78 | return
79 |
80 | if steps < 0
81 | @pages.unshift(@pages.pop())
82 | @_rotatePageIndices(steps + 1, animate, 'right')
83 | return
84 |
85 | @_updateLayerPositions(animate, direction)
86 |
87 | _updateLayerPositions: (animate = true, direction) ->
88 | page = undefined
89 | carousel = @
90 | index = undefined
91 | distance = undefined
92 | previous = undefined
93 | width = _.sumBy(@pages, 'width')
94 | length = @pages.length
95 | p = Math.PI * 2
96 |
97 | aLength = if length % 2 is 1 then length - 1 else length
98 |
99 | for page, index in @pages
100 |
101 | page.animateStop()
102 |
103 | difference = index - Math.floor(length / 2)
104 |
105 | if difference is 0
106 | @currentPage = page
107 |
108 | distance = Utils.modulate(
109 | Math.abs(difference), [0, Math.floor(length / 2)], [0, 1], true
110 | )
111 |
112 | angle = Utils.modulate(index, [0, aLength], [p * .75, p * -.25])
113 |
114 | opacity = 1 - (Math.abs(difference) * @opacityScale)
115 |
116 | scale = _.clamp(1 - (Math.abs(difference) * @scaleScale), 0, Infinity)
117 |
118 | do (page, carousel, index, difference,
119 | distance, angle, opacity, scale, animate, direction) =>
120 |
121 | if direction is 'right' and index is 0
122 | hidden = true
123 |
124 | if direction is 'left' and index is @pages.length - 1
125 | hidden = true
126 |
127 | Utils.delay 0, => @displayPage(
128 | page, carousel, index, difference,
129 | distance, angle, opacity, scale, animate, hidden
130 | )
131 |
132 | page.index = (1 - distance) * 100 + ((index % 2) * .5)
133 |
134 | _setShape: ->
135 | switch @shape
136 | when 'line'
137 | @displayPage = (
138 | page,
139 | carousel = @,
140 | index,
141 | difference,
142 | distance,
143 | angle,
144 | opacity,
145 | scale,
146 | animate = true,
147 | hidden = false) ->
148 |
149 | props =
150 | opacity: opacity
151 | scale: scale
152 | midX: @width / 2 + (difference * (page.width + @padding))
153 | originY: @originY
154 | options: @animationOptions
155 |
156 | if animate
157 | if hidden
158 | page.visible = false
159 | do (page) =>
160 | page.once Events.AnimationStop, =>
161 | if page is @currentPage
162 | @emit "rotateEnd", @currentPage
163 | page.visible = true
164 | page.animate props
165 | return
166 |
167 | page.props = props
168 | if page is @currentPage then @emit "rotateEnd", @currentPage
169 |
170 | when 'circle'
171 | @displayPage = (
172 | page,
173 | carousel = @,
174 | index,
175 | difference,
176 | distance,
177 | angle,
178 | opacity,
179 | scale,
180 | animate = true) ->
181 |
182 | props =
183 | opacity: opacity
184 | scale: scale
185 | midX: (@width / 2) + ((@width + (@padding * @pages.length) * 1.25)) * Math.cos(angle)
186 | originY: @originY
187 | options: @animationOptions
188 |
189 | if animate
190 | if page is @currentPage
191 | page.once Events.AnimationEnd, =>
192 | @emit "rotateEnd", @currentPage
193 | page.animate props
194 | return
195 |
196 | page.props = props
197 | if page is @currentPage then @emit "rotateEnd", @currentPage
198 |
199 | displayPage: (
200 | page,
201 | carousel = @,
202 | index,
203 | difference,
204 | distance,
205 | angle,
206 | opacity,
207 | scale,
208 | previous,
209 | width = _.sumBy(@pages, 'width'),
210 | length = @pages.length,
211 | animate = true
212 | ) ->
213 |
214 | page.opacity = opacity
215 | page.scale = scale
216 |
217 | snapToPage: (layer, animate = true) ->
218 | steps = @currentIndex - @pages.indexOf(layer)
219 | return if steps is 0
220 |
221 | if steps > 0 then direction = 'left' else 'right'
222 |
223 | @_rotatePageIndices(steps, animate, direction)
224 |
225 | addPage: (layer) ->
226 | if not layer?
227 | layer =
228 | new Layer
229 | size: @size
230 | backgroundColor: '#AAA'
231 |
232 | return if _.includes(@pages, layer)
233 |
234 | _.assign layer,
235 | parent: @
236 |
237 | @pages.push(layer)
238 |
239 | @height = _.maxBy(@pages, 'height')?.height
240 |
241 | return layer
242 |
243 | removePage: (layer) ->
244 | return if not _.includes(@pages, layer)
245 |
246 | _.pull(@pages, layer)
247 |
248 | rotatePages: (direction = 'right', animate = true) ->
249 | switch direction
250 | when 'left'
251 | steps = -1
252 | when 'right'
253 | steps = 1
254 | else
255 | throw 'Direction must be either left or right.'
256 |
257 | @_rotatePageIndices(steps, animate, direction)
258 |
259 | @define 'pages',
260 | get: -> return @_pages
261 |
262 | @define 'shape',
263 | get: -> return @_shape
264 | set: (string) ->
265 | return if @__constructor
266 |
267 | throw 'Shape must be either line or circle.' if not _.isString(string)
268 | return if string is @_shape
269 |
270 | @_shape = string
271 |
272 | @_setShape()
273 |
274 | @define 'opacityScale',
275 | get: -> return @_opacityScale
276 | set: (num) ->
277 | return if num is @_opacityScale
278 |
279 | @_opacityScale = num
280 |
281 | @define 'scaleScale',
282 | get: -> return @_scaleScale
283 | set: (num) ->
284 | return if num is @_scaleScale
285 |
286 | @_scaleScale = num
287 |
288 | @define 'padding',
289 | get: -> return @_padding
290 | set: (num) ->
291 | return if num is @_padding
292 |
293 | @_padding = num
294 |
295 | @define 'currentPage',
296 | get: -> return @_currentPage
297 | set: (page) ->
298 | return if @__constructor
299 | return if page is @_currentPage
300 | return if not _.includes(@pages, page)
301 |
302 | @_prevPage = @_currentPage
303 | @_currentPage = page
304 |
305 | @emit "change:currentPage", page, @
306 |
307 | @define 'currentIndex',
308 | get: -> return @pages.indexOf(@currentPage)
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Checkbox.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = 'checkbox'
5 |
6 | class exports.Checkbox extends Layer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 | @__constructor = true
10 | @__instancing = true
11 |
12 | # ---------------
13 | # Options
14 |
15 | _.defaults options,
16 | name: 'Checkbox'
17 | height: 32
18 | width: 32
19 | animationOptions:
20 | time: .2
21 | colorModel: 'husl'
22 |
23 | checked: false
24 | disabled: false
25 |
26 | _.assign options,
27 | backgroundColor: null
28 |
29 | @customOptions = {
30 | color: options.color
31 | }
32 |
33 | super options
34 |
35 | @props =
36 | x: @x - 4
37 | y: @y - 4
38 |
39 | # ---------------
40 | # Layers
41 |
42 | @iconLayer = new Icon
43 | name: "Icon"
44 | parent: @
45 | point: Align.center
46 | icon: 'checkbox-blank-outline'
47 | color: options.color
48 |
49 | Utils.linkProperties @, @iconLayer, "color"
50 |
51 | # ---------------
52 | # Events
53 |
54 | @onTap => @checked = !@checked
55 | @onMouseOver => @hovered = true
56 | @onMouseOut => @hovered = false
57 |
58 | # ---------------
59 | # Definitions
60 |
61 | delete @__constructor
62 |
63 | Utils.define @, 'theme', 'default', @_setTheme
64 | Utils.define @, 'checked', options.checked, @_showChecked, _.isBoolean, 'Checkbox.checked must be a boolean (true or false)'
65 | Utils.define @, 'hovered', false, @_showHovered, _.isBoolean, "Checkbox.hovered must be a boolean (true or false)."
66 | Utils.define @, 'error', options.disabled, @_showError, _.isBoolean, "Checkbox.error must be a boolean (true or false)."
67 | Utils.define @, 'disabled', options.disabled, @_showDisabled, _.isBoolean, "Checkbox.disabled must be a boolean (true or false)."
68 |
69 | delete @__instancing
70 |
71 | # ---------------
72 | # Cleanup
73 |
74 | child.name = '.' for child in @children unless options.showSublayers
75 |
76 | # ---------------
77 | # Private Methods
78 |
79 | _getCustomTheme: (color, backgroundColor) ->
80 | return {
81 | default:
82 | color: black
83 | borderColor: new Color(backgroundColor).darken(10)
84 | backgroundColor: backgroundColor
85 | shadowColor: 'rgba(0,0,0,.16)'
86 | disabled:
87 | color: new Color(color).alpha(.15)
88 | borderColor: new Color(color).alpha(.15)
89 | backgroundColor: new Color(backgroundColor).alpha(0)
90 | shadowColor: 'rgba(0,0,0,0)'
91 | hovered:
92 | color: black
93 | borderColor: new Color(backgroundColor).darken(20)
94 | backgroundColor: new Color(backgroundColor).darken(10)
95 | shadowColor: 'rgba(0,0,0,.16)'
96 | }
97 |
98 | _setTheme: (value) =>
99 | @animateStop()
100 | props = @customTheme?[value] ? _.defaults(
101 | _.clone(@customOptions),
102 | theme[MODEL][value]
103 | )
104 |
105 | if @__instancing then @props = props
106 | else @animate props
107 |
108 | _showChecked: (bool) =>
109 | if not bool
110 | @iconLayer.icon = 'checkbox-blank-outline'
111 | return
112 |
113 | @iconLayer.icon = 'checkbox-marked'
114 | return
115 |
116 | _showError: (bool) =>
117 | return if @disabled
118 | @theme = if bool then "error" else "default"
119 |
120 | _showHovered: (bool) =>
121 | return if @disabled
122 | @theme = if bool then "hovered" else "default"
123 |
124 | _showDisabled: (bool) =>
125 | if bool
126 | # show disabled
127 | @theme = 'disabled'
128 | @ignoreEvents = true
129 | return
130 |
131 | # show not disabled
132 | @theme = 'default'
133 | @ignoreEvents = false
134 |
135 | # ---------------
136 | # Public Methods
137 |
138 |
139 | # ---------------
140 | # Special Definitions
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Colors.coffee:
--------------------------------------------------------------------------------
1 | # set up colors
2 |
3 | defaultColors =
4 | black: '#252729'
5 | grey: '#c1c1c2'
6 | yellow: '#ffd16d'
7 | white: '#FFF'
8 | red: '#d96161'
9 | beige: '#eae5e0'
10 | blue: '#5399c3'
11 | green: '#599FA0'
12 |
13 |
14 | updateColors = (newColors = {}, soloColors = {}) ->
15 |
16 | for k, v of soloColors
17 | window[k] = new Color(v)
18 |
19 | colors = _.merge(_.clone(defaultColors), newColors)
20 |
21 | # Set up shades
22 |
23 | mods =
24 | '80': (c) -> c.darken(30)
25 | '70': (c) -> c.darken(20)
26 | '60': (c) -> c.darken(10)
27 | '50': (c) -> c.darken(0)
28 | '40': (c) -> c.lighten(10)
29 | '30': (c) -> c.lighten(20)
30 | '20': (c) -> c.lighten(30)
31 |
32 | # add shades
33 |
34 | for color, value of colors
35 | for mod, func of mods
36 | newColor = func(new Color(value))
37 | colors[color + mod] = newColor
38 |
39 | # add backgrounds
40 |
41 | _.assign colors,
42 | bg1: '#fcfcf9'
43 | bg3: '#f8f8f5'
44 | bg5: '#f4f4f1'
45 |
46 | # add values to window
47 |
48 | for color, value of colors
49 | colors[color] = new Color(value)
50 | window[color] = new Color(value)
51 |
52 | exports.colors = _.merge(colors, soloColors)
53 |
54 |
55 | exports.colors = undefined
56 | exports.updateColors = updateColors
57 | updateColors()
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/DocComponent.coffee:
--------------------------------------------------------------------------------
1 | class exports.DocComponent extends Layer
2 | constructor: (options = {}) ->
3 |
4 | # ---------------
5 | # Options
6 |
7 | _.defaults options,
8 | name: "Documentation"
9 | backgroundColor: null
10 | color: black
11 | x: 16
12 | width: Screen.width - 32
13 | text: [
14 | "new Component"
15 | "status: {status}"
16 | ]
17 | template: {}
18 |
19 | super options
20 |
21 | # ---------------
22 | # Layers
23 |
24 | if typeof options.text is 'string' then options.text = [options.text]
25 |
26 | @codeBlock = new Code
27 | name: 'Label'
28 | parent: @
29 | x: 0
30 | y: 0
31 | text: options.text.join('\n\t')
32 | color: @color
33 |
34 | Utils.toMarkdown(@codeBlock)
35 |
36 | template = {}
37 | formatter = {}
38 |
39 | _.entries(options.template).forEach (pair) =>
40 | key = pair[0]
41 | options = pair[1]
42 | layer = options[0]
43 | property = options[1]
44 | format = options[2]
45 |
46 | template[key] = layer[property]
47 | formatter[key] = format
48 |
49 | layer.onChange property, (value) =>
50 | @codeBlock.template = {"#{key}": value}
51 | @height = _.maxBy(@children, 'maxY')?.maxY
52 |
53 | @codeBlock.templateFormatter = formatter
54 | @codeBlock.template = template
55 |
56 | @copyIcon = new Icon
57 | name: 'Copy Icon'
58 | parent: @
59 | y: 0
60 | x: Align.right(-8)
61 | icon: 'content-copy'
62 | color: grey
63 |
64 | @copyLabel = new Label
65 | name: 'Copy Label'
66 | parent: @
67 | y: @copyIcon.maxY
68 | x: Align.right()
69 | text: 'COPY'
70 | color: grey
71 |
72 | @copyIcon.midX = @copyLabel.midX
73 |
74 | # ---------------
75 | # Cleanup
76 |
77 | child.name = '.' for child in @children unless options.showSublayers
78 |
79 | # ---------------
80 | # Definitions
81 |
82 | # ---------------
83 | # Events
84 |
85 | @copyIcon.onTap =>
86 | Utils.copyTextToClipboard(@codeBlock.text)
87 |
88 | @codeBlock.animate
89 | color: blue
90 | options: { time: .1 }
91 |
92 | Utils.delay .1, =>
93 | @codeBlock.animate
94 | color: @color
95 | options: { time: .5 }
96 |
97 | @height = _.maxBy(@children, 'maxY')?.maxY
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Footer.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | class exports.Footer extends Layer
5 | constructor: (options = {}) ->
6 | theme = Theme.theme
7 | @__constructor = true
8 | @__instancing = true
9 |
10 | # ---------------
11 | # Options
12 |
13 | _.defaults options,
14 | name: 'Footer'
15 | height: 44
16 | width: Screen.width
17 | clip: true
18 | shadowY: -1
19 | shadowColor: 'rgba(0,0,0,.16)'
20 | backgroundColor: if Utils.isChrome() then '#FFF' else 'rgba(255,255,255,.65)'
21 | backgroundBlur: 30
22 |
23 | _.assign @,
24 | tint: '#007AFF'
25 | offTint: '#C3C3C1'
26 | app: options.app
27 |
28 | super options
29 |
30 | # ---------------
31 | # Layers
32 |
33 | # content
34 |
35 | @content = new Layer
36 | name: 'Content'
37 | parent: @
38 | backgroundColor: null
39 | height: 28
40 | width: @width
41 | x: Align.center()
42 | y: Align.center()
43 | style:
44 | lineHeight: 0
45 |
46 | # icons
47 |
48 | @icons = ['back', 'forward', 'share', 'bookmark', 'tabs'].map (iconName) =>
49 | new SVGLayer
50 | name: iconName
51 | parent: @content
52 | size: 28
53 | y: Align.center()
54 | backgroundColor: null
55 | fill: @tint
56 | svg: " "
57 |
58 | @icons[1].fill = @offTint
59 |
60 | Utils.distribute(@icons, 'midX', 24, @width - 29)
61 |
62 | @backIcon = @icons[0]
63 |
64 | # ---------------
65 | # Definitions
66 |
67 | delete @__constructor
68 |
69 | Utils.define @, 'hasPrevious', false, @_setArrow
70 |
71 | delete @__instancing
72 |
73 | # ---------------
74 | # Events
75 |
76 | @onTap (event) -> event.stopPropagation()
77 |
78 | @backIcon.onTap @_showPrevious
79 |
80 | # ---------------
81 | # Cleanup
82 |
83 | if not options.showSublayers then child.name = '.' for child in @children
84 |
85 | # ---------------
86 | # Private Methods
87 |
88 | _collapse: =>
89 | options = {time: .2}
90 |
91 | @animate
92 | y: Screen.height
93 | options: options
94 |
95 | _expand: =>
96 | options = {time: .2}
97 |
98 | @animate
99 | y: Align.bottom()
100 | options: options
101 |
102 | _setArrow: =>
103 | color = if @hasPrevious then @tint else @offTint
104 | @backIcon.fill = color
105 |
106 | _showPrevious: =>
107 | return if not @hasPrevious
108 | @app.showPrevious()
109 |
110 | # ---------------
111 | # Public Methods
112 |
113 |
114 | # ---------------
115 | # Special Definitions
116 |
117 | iconSVGs =
118 | back: "M11.2198252,14.0179296 L18.4047812,21.3118426 C18.71163,21.6233446 18.7116442,22.123468 18.4048131,22.4349874 C18.1038965,22.740502 17.6122869,22.7442293 17.3067723,22.4433127 C17.3039918,22.4405741 17.301232,22.4378145 17.2984931,22.4350342 L10.1132808,15.1412665 L10.1102627,15.1443304 L9,14.0176583 L9.00319775,14.0144121 L9,14.011166 L10.1062726,12.8874904 L10.109773,12.8910439 L17.325584,5.56572841 C17.6275906,5.25913872 18.1209553,5.25542335 18.427545,5.55742991 C18.4302959,5.56013966 18.4330266,5.56286982 18.4357369,5.56562016 C18.7436533,5.87808756 18.7437023,6.37987304 18.4358467,6.69240048 L11.2198252,14.0179296 Z"
119 | forward: "M16.4468811,14.0179296 L9.23085958,6.69240048 C8.92300403,6.37987304 8.92305296,5.87808756 9.23096945,5.56562016 C9.23367974,5.56286982 9.23641043,5.56013966 9.2391613,5.55742991 C9.545751,5.25542335 10.0391157,5.25913872 10.3411223,5.56572841 L17.5569333,12.8910439 L17.5604337,12.8874904 L18.6667063,14.011166 L18.6635086,14.0144121 L18.6667063,14.0176583 L17.5564436,15.1443304 L17.5534255,15.1412665 L10.3682132,22.4350342 C10.3654743,22.4378145 10.3627145,22.4405741 10.359934,22.4433127 C10.0544194,22.7442293 9.56280982,22.740502 9.26189321,22.4349874 C8.95506208,22.123468 8.95507627,21.6233446 9.26192507,21.3118426 L16.4468811,14.0179296 Z"
120 | share: "M14.6666667,2.21999063 L14.6666667,17.1520468 L13.6666667,17.1520468 L13.6666667,2.2345679 L10.2126922,5.68854234 L9.33333333,4.83950617 L14.1728395,5.3e-15 L19,4.83950617 L18.1509638,5.68854234 L14.6666667,2.21999063 Z M22.6666667,9.15204678 L16.6666667,9.15204678 L16.6666667,8.15204678 L23.6666667,8.15204678 L23.6666667,27.1520468 L4.66666667,27.1520468 L4.66666667,8.15204678 L11.6666667,8.15204678 L11.6666667,9.15204678 L5.66666667,9.15204678 L5.66666667,26.1520468 L22.6666667,26.1520468 L22.6666667,9.15204678 Z"
121 | bookmark: "M20.3234128,2 C17.6948076,2 15.5002199,3.10675363 14.1671666,5.06420221 C12.8346133,3.10675363 10.6395255,2 8.01092038,2 C4.94679784,2 1.66666667,3.6398758 1.66666667,6.08093521 L1.66666667,24.4281398 C1.66666667,24.621184 1.77167087,24.7982246 1.94067762,24.8897456 C2.1101844,24.9802663 2.31619264,24.9712642 2.47469898,24.86524 C2.5152006,24.8382338 6.56036237,22.168622 9.82249283,22.168622 C11.9360773,22.168622 13.1896275,23.2843777 13.6566462,25.580904 C13.6596463,25.5964075 13.6691467,25.6094105 13.6736468,25.6244139 C13.6821472,25.6529205 13.6926476,25.6794265 13.7056481,25.7059326 C13.7206487,25.7359395 13.7371494,25.7629457 13.7571502,25.7889516 C13.7736508,25.8109567 13.7911515,25.8314614 13.8111523,25.8504657 C13.8351533,25.8739711 13.8611543,25.8934756 13.8896555,25.9114797 C13.9121564,25.925983 13.9341573,25.9404864 13.9596583,25.9509888 C13.9921596,25.9654921 14.0256609,25.9734939 14.0611623,25.9814958 C14.0796631,25.9854967 14.0956637,25.995499 14.1151645,25.9974994 C14.1321652,25.9989998 14.1491659,26 14.1666666,26 L14.1666666,26 L14.1671666,26 L14.1676666,26 L14.1681666,26 C14.1851673,26 14.202168,25.9984997 14.2196687,25.9974994 C14.2386694,25.995499 14.2546701,25.9859968 14.2731708,25.9814958 C14.3081722,25.9734939 14.3421736,25.9659922 14.3746749,25.9509888 C14.3996759,25.9399862 14.4216768,25.925983 14.4446777,25.9114797 C14.4731788,25.8934756 14.4991798,25.8739711 14.5231808,25.8504657 C14.5431816,25.8314614 14.5601823,25.8109567 14.5766829,25.7889516 C14.5966837,25.7629457 14.6131844,25.7359395 14.627685,25.7059326 C14.6406855,25.6794265 14.6511859,25.6529205 14.6596863,25.6244139 C14.6641864,25.6094105 14.6736868,25.5964075 14.6766869,25.580904 C15.1437056,23.2843777 16.3977558,22.168622 18.5108403,22.168622 C21.7734708,22.168622 25.8181325,24.8377336 25.8586341,24.86524 C26.0176405,24.9707641 26.2231487,24.9802663 26.3926555,24.8897456 C26.5616622,24.7982246 26.6666664,24.621184 26.6666664,24.4281398 L26.6666664,6.08093521 C26.6676665,3.6398758 23.3880353,2 20.3234128,2 L20.3234128,2 Z M9.8213181,20.9737117 C7.12198095,20.9737117 4.08874667,22.5146282 2.66666667,23.3333333 L2.66666667,6.01568004 C2.66666667,4.43745923 5.20860952,3 7.99946667,3 C10.5238095,3 12.5820038,4.1439987 13.6666667,6.14450424 L13.6666667,22.7339775 C12.8017524,21.5740623 11.504381,20.9737117 9.8213181,20.9737117 L9.8213181,20.9737117 Z M25.6666667,23.3333333 C24.2445867,22.5146082 21.2113524,20.973654 18.5120152,20.973654 C16.8289524,20.973654 15.531581,21.5740193 14.6666667,22.7339628 L14.6666667,6.14458116 C15.7513295,4.14402668 17.8100267,3 20.3338667,3 C23.1247238,3 25.6661638,4.43749439 25.6661638,6.01575381 L25.6661638,23.3333333 L25.6666667,23.3333333 Z"
122 | tabs: "M2.66666667,8.33333333 L2.66666667,25.6666667 L20,25.6666667 L20,8.33333333 L2.66666667,8.33333333 Z M1.66666667,7.33333333 L21,7.33333333 L21,26.6666667 L1.66666667,26.6666667 L1.66666667,7.33333333 Z M8.33333333,2.66666667 L8.33333333,6.33333333 L7.33333333,6.33333333 L7.33333333,1.66666667 L26.6666667,1.66666667 L26.6666667,21 L22,21 L22,20 L25.6666667,20 L25.6666667,2.66666667 L8.33333333,2.66666667 Z"
123 |
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Header.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | class exports.Header extends Layer
5 | constructor: (options = {}) ->
6 | theme = Theme.theme
7 | @__constructor = true
8 | @__instancing = true
9 |
10 | # ---------------
11 | # Options
12 |
13 | _.assign options,
14 | width: Screen.width
15 | height: 72
16 | shadowY: 1
17 | shadowBlur: 6
18 | shadowColor: 'rgba(0,0,0,.16)'
19 |
20 | _.defaults options,
21 | name: 'Header'
22 | backgroundColor: "rgba(255, 255, 255, 1)"
23 | title: ' '
24 | showLayers: true
25 |
26 | _.assign @,
27 | safari: options.safari
28 | app: options.app
29 |
30 | super options
31 |
32 | # ---------------
33 | # Layers
34 |
35 | if options.safari
36 | _.assign @,
37 | height: 64
38 | backgroundColor: if Utils.isChrome() then '#FFF' else 'rgba(255,255,255,.65)'
39 | backgroundBlur: 30
40 | shadowBlur: 0
41 |
42 | @statusBar = new Layer
43 | name: unless options.showLayers then '.' else 'Status Bar'
44 | parent: @
45 | height: 20
46 | width: @width
47 | backgroundColor: 'null'
48 |
49 | Utils.build @statusBar, ->
50 | @leftContent = new Layer
51 | name: unless options.showLayers then '.' else 'left'
52 | parent: @
53 | x: 8
54 | y: Align.center(3)
55 | width: 57
56 | height: 15
57 | html: leftContent
58 | backgroundColor: null
59 | style:
60 | lineHeight: '0px'
61 |
62 | @rightContent = new Layer
63 | name: unless options.showLayers then '.' else 'right'
64 | parent: @
65 | x: Align.right(-8)
66 | y: Align.center(3)
67 | width: 72
68 | height: 15
69 | html: rightContent
70 | backgroundColor: null
71 | style:
72 | lineHeight: '0px'
73 |
74 | @timeLayer = new TextLayer
75 | name: unless options.showLayers then '.' else 'time'
76 | parent: @
77 | width: @width
78 | y: Align.center(1)
79 | fontSize: 12
80 | fontWeight: 500
81 | fontFamily: "Helvetica Neue"
82 | letterSpacing: 0.3
83 | textAlign: "center"
84 | text: new Date().toLocaleTimeString([], {hour: 'numeric', minute: '2-digit'})
85 | color: '#000'
86 |
87 | if @app.chrome is "safari"
88 |
89 | @addressContainer = new Layer
90 | name: unless options.showLayers then '.' else 'Address'
91 | parent: @
92 | width: @width - 20
93 | height: 29
94 | x: Align.center()
95 | y: Align.center(10)
96 | borderRadius: 8
97 | backgroundColor: 'rgba(0,0,0,.09)'
98 | clip: true
99 |
100 | @refreshIcon = new Icon
101 | name: unless options.showLayers then '.' else 'Menu Icon'
102 | parent: @addressContainer
103 | y: Align.center(1)
104 | x: Align.right(-6)
105 | icon: 'refresh'
106 | rotation: -45
107 | color: '#333'
108 | height: 18
109 | width: 18
110 |
111 | @refreshIcon.onTap -> window.location.reload()
112 |
113 | @loadingLayer = new Layer
114 | name: '.'
115 | parent: @addressContainer
116 | x: 0
117 | y: Align.bottom()
118 | height: 2
119 | width: 1
120 | backgroundColor: "#007AFF"
121 | visible: false
122 |
123 | @urlLayer = new TextLayer
124 | name: unless options.showLayers then '.' else 'Title'
125 | parent: @addressContainer
126 | y: Align.center()
127 | width: @addressContainer.width
128 | textAlign: 'center'
129 | text: ' '
130 | fontSize: 15
131 | fontFamily: "Helvetica Neue"
132 | fontWeight: 400
133 | color: '#000'
134 |
135 | # store props for expand
136 |
137 | @_expandProps =
138 | height: @height
139 | addressContainer:
140 | y: @addressContainer.y
141 | backgroundColor: @addressContainer.backgroundColor
142 |
143 | else
144 |
145 | @titleLayer = new Body1
146 | name: unless options.showLayers then '.' else 'Title'
147 | parent: @
148 | y: Align.center(10)
149 | width: Screen.width
150 | textAlign: 'center'
151 | text: ' '
152 |
153 | @backIcon = new Icon
154 | name: unless options.showLayers then '.' else 'Back Icon'
155 | parent: @
156 | y: Align.center(12)
157 | x: 8
158 | icon: 'ios-back'
159 | visible: false
160 |
161 | @backText = new Body1
162 | name: unless options.showLayers then '.' else 'Back Text'
163 | parent: @
164 | y: Align.center(10)
165 | x: @backIcon.maxX
166 | visible: false
167 | text: 'Back'
168 |
169 | # @menuIcon = new Icon
170 | # name: unless options.showLayers then '.' else 'Menu Icon'
171 | # parent: @
172 | # y: Align.center(10)
173 | # x: Align.right(if options.safari then -16 else -8)
174 | # icon: 'dots-vertical'
175 | # rotation: 90
176 |
177 | @hitArea = new Layer
178 | name: unless options.showLayers then '.' else 'Hit Area'
179 | parent: @
180 | height: @height - 20
181 | width: @width / 3
182 | x: 0
183 | y: 20
184 | backgroundColor: null
185 |
186 | # events
187 |
188 | @hitArea.onTouchEnd @_showPrevious
189 |
190 | # update time
191 | @_setTime()
192 |
193 | # ... and update time every sixty seconds
194 | Utils.delay (60 - new Date().getSeconds()), =>
195 | @_setTime()
196 | Utils.interval 60, @_setTime
197 |
198 | # ---------------
199 | # Definitions
200 |
201 | delete @__constructor
202 |
203 | Utils.define @, 'title', options.title, @_setTitle
204 |
205 | delete @__instancing
206 |
207 | # ---------------
208 | # Events
209 |
210 | @on "change:color", =>
211 | Utils.align @children,
212 | color: @color
213 |
214 | # ---------------
215 | # Cleanup
216 |
217 | if not options.showSublayers then child.name = '.' for child in @children
218 |
219 | # ---------------
220 | # Private Methods
221 |
222 | _showLoading: (bool, time) =>
223 | if bool
224 | # loading is true
225 | _.assign @loadingLayer,
226 | width: 1
227 | visible: true
228 |
229 | @loadingLayer.animate
230 | width: @addressContainer.width
231 | options:
232 | time: time ? 2
233 | curve: "linear"
234 | return
235 |
236 | # loading is false
237 | _.assign @loadingLayer,
238 | width: 1
239 | visible: false
240 |
241 |
242 | _setTime: =>
243 | d = new Date()
244 | @statusBar.timeLayer.text = d.toLocaleTimeString(['en-US'], {hour: 'numeric', minute: '2-digit'})
245 |
246 |
247 | _showPrevious: =>
248 | return if not @backIcon.visible
249 | @app.showPrevious()
250 |
251 |
252 | _setTitle: (value) =>
253 |
254 | if @app.chrome is "safari"
255 | value = _.truncate(value, {length: 28})
256 | @urlLayer.text = value
257 | return
258 |
259 | value = _.truncate(value, {length: 22})
260 | @titleLayer.text = value
261 |
262 |
263 | _collapse: =>
264 | if @app.chrome isnt "safari"
265 | return
266 |
267 | options = {time: .25}
268 |
269 | @animate
270 | height: 40
271 | options: options
272 |
273 | @addressContainer.animate
274 | y: 15
275 | backgroundColor: 'rgba(0,0,0,0)'
276 | options: options
277 |
278 | @refreshIcon.animate
279 | opacity: 0
280 | options: options
281 |
282 | @urlLayer.animate
283 | scale: .75
284 | options: options
285 |
286 |
287 | _expand: =>
288 | if @app.chrome isnt "safari"
289 | return
290 |
291 | options = {time: .25}
292 |
293 | @animate
294 | height: @_expandProps.height
295 | options: options
296 |
297 | @addressContainer.animate
298 | y: @_expandProps.addressContainer.y
299 | backgroundColor: @_expandProps.addressContainer.backgroundColor
300 | options: options
301 |
302 | @refreshIcon.animate
303 | opacity: 1
304 | options: options
305 |
306 | @urlLayer.animate
307 | scale: 1
308 | options: options
309 |
310 | # ---------------
311 | # Public Methods
312 |
313 |
314 | updateTitle: (title) =>
315 | if @app.chrome is "safari"
316 | return
317 |
318 | @titleLayer.animateStop()
319 |
320 | do (title) =>
321 | @titleLayer.once Events.AnimationEnd, =>
322 | @title = title
323 |
324 | @titleLayer.animate
325 | opacity: 1
326 | options:
327 | time: .3
328 | delay: .15
329 |
330 | @titleLayer.animate
331 | opacity: 0
332 | options:
333 | time: .2
334 |
335 | # ---------------
336 | # Special Definitions
337 |
338 |
339 | leftContent = """
340 |
341 |
342 |
343 | FW
344 |
345 |
346 |
347 |
348 |
349 | """
350 |
351 | rightContent = """
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 | 100%
363 |
364 |
365 |
366 |
367 |
368 |
369 | """
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Icon.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | class exports.Icon extends Layer
5 | constructor: (options = {}) ->
6 | theme = Theme.theme
7 | @__constructor = true
8 | @__instancing = true
9 |
10 | # ---------------
11 | # Options
12 |
13 | _.defaults options,
14 | name: 'Icon'
15 | size: 24
16 | icon: 'star'
17 | backgroundColor: null
18 | clip: true
19 | lineHeight: 0
20 | animationOptions:
21 | time: .25
22 | colorModel: 'husl'
23 |
24 | super options
25 |
26 | # ---------------
27 | # Layers
28 |
29 | svgNS = "http://www.w3.org/2000/svg"
30 | @ctx = document.createElementNS(svgNS, 'svg')
31 | @svgIcon = document.createElementNS(svgNS, 'path')
32 |
33 | @ctx.appendChild(@svgIcon)
34 | @_element.appendChild(@ctx)
35 |
36 | # ---------------
37 | # Events
38 |
39 | @on "change:color", @_refresh
40 | @on "change:size", @_setSize
41 |
42 | @color = options.color
43 |
44 | # ---------------
45 | # Definitions
46 |
47 | delete @__constructor
48 |
49 | Utils.define @, "icon", options.icon, @_refresh, _.isString, 'Icon.icon must be a string.'
50 |
51 | delete @__instancing
52 |
53 | # ---------------
54 | # Cleanup
55 |
56 | @_setSize()
57 |
58 | child.name = '.' for child in @children unless options.showSublayers
59 |
60 | # ---------------
61 | # Private Methods
62 |
63 | _setSize: =>
64 | Utils.setAttributes @ctx,
65 | width: '100%'
66 | height: '100%'
67 | viewBox: "0 0 512 512"
68 |
69 | _refresh: ->
70 | return if not @color? or not @icon?
71 |
72 | @_setSize()
73 |
74 | icon = @icon
75 | if @icon is 'random' then @icon = _.sample(_.keys(theme.icons))
76 |
77 | Utils.setAttributes @svgIcon,
78 | d: theme.icons[icon]
79 | fill: @color
80 | transform: "scale(1, -1), translate(0, -448)"
81 |
82 |
83 | # ---------------
84 | # Public Methods
85 |
86 | addIcon: (name, svg) ->
87 | iconObj = {}
88 | iconObj[name] = svg
89 | theme.icons = _.merge(theme.icons, iconObj)
90 | @icon = name
91 |
92 | # ---------------
93 | # Special Definitions
94 |
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Link.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = 'link'
5 |
6 | class exports.Link extends TextLayer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 | @__constructor = true
10 | @__instancing = true
11 |
12 | # ---------------
13 | # Options
14 |
15 | _.defaults options,
16 | x: 0
17 | y: 0
18 | padding: {top:12, bottom: 12}
19 | disabled: false
20 | icon: undefined
21 | select: => null
22 | animationOptions:
23 | time: .15
24 | colorModel: 'husl'
25 |
26 | @customTheme = if options.color then @_getCustomTheme(options.color) else undefined
27 |
28 | @customOptions =
29 | color: options.color
30 |
31 | super options
32 |
33 |
34 | # ---------------
35 | # Layers
36 |
37 | @_setTheme('default')
38 |
39 |
40 | # ---------------
41 | # Definitions
42 |
43 | delete @__constructor
44 |
45 | Utils.define @, 'theme', 'default', @_setTheme, _.isString, "Link.theme must be a string."
46 | Utils.define @, 'disabled', options.disabled, @_showDisabled, _.isBoolean, "Link.disabled must be a boolean (true or false)."
47 | Utils.define @, 'hovered', false, @_showHovered, _.isBoolean, "Link.hovered must be a boolean (true or false)."
48 | Utils.define @, 'select', options.select, undefined, _.isFunction, "Link.select must be a function."
49 |
50 | delete @__instancing
51 |
52 |
53 | # ---------------
54 | # Events
55 |
56 | # Need a better solution here...
57 | #
58 | # @onMouseOver => @hovered = true
59 | # @onMouseOut => @hovered = false
60 |
61 | if Utils.isMobile()
62 | @onTap @_doSelect
63 |
64 | else
65 |
66 | @onTouchStart (event) => @_showTouching(true, null, event)
67 | @onTouchEnd (event) => @_showTouching(false, null, event)
68 |
69 | @onTap @_showTapped
70 | @onPan @_panOffTouch
71 |
72 | for child in @children
73 | if !options.showNames
74 | child.name = '.'
75 |
76 | # ---------------
77 | # Private Methods
78 |
79 | _getCustomTheme: (color) ->
80 | color = new Color(color)
81 | customTheme =
82 | default:
83 | color: color
84 | disabled:
85 | color: color.alpha(.15)
86 | touched:
87 | color: color.lighten(30)
88 | hovered:
89 | color: color.lighten(20)
90 |
91 | return customTheme
92 |
93 | _setTheme: (value) =>
94 | @animateStop()
95 | props = @customTheme?[value] ? _.defaults _.clone(@customOptions), theme[MODEL][value]
96 | if @__instancing then @props = props else @animate props
97 |
98 | _showHovered: (bool) =>
99 | return if @disabled
100 |
101 | if bool
102 | # show hovered
103 | @theme = 'hovered'
104 | return
105 |
106 | # show not hovered
107 | @theme = 'default'
108 |
109 | _showDisabled: (bool) =>
110 | if bool
111 | # show disabled
112 | @theme = 'disabled'
113 | @ignoreEvents = true
114 | return
115 |
116 | # show not disabled
117 | @theme = 'default'
118 | @ignoreEvents = false
119 |
120 | _doSelect: (event) =>
121 | return if @disabled
122 |
123 | try @select(event, @)
124 | @emit "select", @
125 |
126 | _panOffTouch: (event) =>
127 | return if @_isTouching is false
128 | return if @disabled
129 | return if @theme is "default"
130 |
131 | if Math.abs(event.offset.x) > @width/2 or
132 | Math.abs(event.offset.y) > @height/2
133 | @theme = "default"
134 |
135 | _showTapped: =>
136 | return if @disabled
137 | return if @_isTouching is true
138 |
139 | @theme = "touched"
140 | Utils.delay .1, => @theme = "default"
141 |
142 |
143 | _showTouching: (isTouching, silent = false, event) =>
144 | return if @disabled
145 | @animateStop()
146 |
147 | if isTouching
148 | # show touching
149 | @_isTouching = true
150 | @theme = "touched"
151 | return
152 |
153 | # show not touching
154 | @_isTouching = false
155 | @theme = "default"
156 |
157 | unless silent then @_doSelect(event)
158 |
159 | # ---------------
160 | # Public Methods
161 |
162 | onSelect: (callback) => @select = callback
163 |
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/PageTransitionComponent.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 |
5 | class PageTransitionComponent extends PageComponent
6 | constructor: (options = {}) ->
7 | theme = Theme.theme
8 |
9 | _.defaults options,
10 | direction: 'bottom'
11 | originY: 0
12 |
13 | super options
14 |
15 |
16 | # -----------------
17 | # Settings
18 |
19 | _.assign @,
20 | edge: options.direction
21 | velocityThreshold: 2.5
22 |
23 | _.assign @content.draggable,
24 | momentum: true
25 | momentumOptions:
26 | friction: 6
27 | tolerance: 100
28 |
29 | # Desktop options
30 | # enabled when the device is not a touch device
31 |
32 | # @mouseWheelEnabled = Utils.isTouch()
33 | # if @mouseWheelEnabled
34 | # _.assign @content.draggable,
35 | # enabled: false
36 | #
37 | # breaks mobile
38 |
39 | # remove default listeners
40 | @content.off(Events.DragSessionEnd, @_scrollEnd)
41 |
42 | # -----------------
43 | # definitions
44 |
45 | Utils.define @, 'transitioning', false
46 |
47 | # -----------------
48 | # Events
49 |
50 | @onScrollEnd @_checkGestureEnd
51 |
52 | @content.on "change:y", @_setChildLayerFactors
53 |
54 | # timer for checking interstitial deadpoints
55 |
56 | @timer = undefined
57 |
58 | @time = 0
59 |
60 | @timer = Utils.interval .016, =>
61 | @time += .016
62 | if @time >= .15
63 | @content.animateStop()
64 | @time = 0
65 | @_checkScrollEnd()
66 |
67 |
68 | # A custom function for handling flick gestures, where a scroll's velocity
69 | # is high enough to suggest a page change intent. Since pages can be taller
70 | # than the window, this dynamically sets originY depending on the direction
71 | _checkGestureEnd: (event) =>
72 | return if @mouseWheelEnabled
73 |
74 |
75 | # if we have an event, a gesture just ended. New question is:
76 | # was that gesture fast enough to suggest a page change intent?
77 |
78 | # If it's fast for a page turn, it's a page change intent
79 | if Math.abs(event.velocity.y) > @velocityThreshold
80 | if event.offsetDirection is "up" and @nextPage('down')?
81 | @originY = 0
82 | @snapToNextPage("down")
83 |
84 | else if @nextPage('up')?
85 | @originY = 0
86 | @snapToNextPage("up")
87 | # @originY = 0 # should this snap to the top on swipe up?
88 |
89 | return
90 |
91 |
92 | # Every .2 seconds, run this function to check whether a scroll
93 | # ended in a transition (between two pages)
94 | _checkScrollEnd: (event) =>
95 | transitioning = _.some(@content.children, 'transitioning')
96 | # if we're still in the page, or if the content is still scrolling
97 | # do nothing and behave like a scroll
98 | return if @isMoving or not transitioning or @content.draggable.isDragging
99 |
100 | # if we're between pages and the content isnt moving...
101 |
102 | # if the current page is just a little out of bounds,
103 | # snap either to the top or bottom of the current page,
104 | # depending on which edge is out of bounds
105 |
106 | yCloseEnough = @scrollY < @currentPage.y < (@scrollY + @height * .2)
107 | maxYCloseEnough = (@scrollY + @height * .8) < @currentPage.maxY < @scrollMaxY
108 |
109 | # snap to the top of the current page
110 | if yCloseEnough
111 | @originY = 0
112 | @snapToPage(@currentPage)
113 | return true
114 |
115 | # snap to the bottom of the current page
116 | if maxYCloseEnough
117 | @originY = 1
118 | @snapToPage(@currentPage)
119 | return true
120 |
121 | # If we're too far to stay, move back a page or down a page,
122 | # depending on where the current page's edges are
123 |
124 | yInside = @scrollY < @currentPage.y < @scrollMaxY
125 | maxYInside = @scrollY < @currentPage.maxY < @scrollMaxY
126 |
127 | if yInside and not yCloseEnough
128 | @originY = 1
129 | @snapToNextPage("up")
130 | else if maxYInside and not maxYCloseEnough
131 | @originY = 0
132 | @snapToNextPage("down")
133 |
134 |
135 |
136 | # if nothing's close enough... do nothing
137 | # (but something should be close enough)
138 | return false
139 |
140 |
141 | # Set a factor for each child layer:
142 | # 0, layer is out of the window (higher up in the scroll)
143 | # 0-1, layer's progress into the current window
144 | # 1-2, layer's progress within the current window
145 | # 2-3, layer's progress out of the current window
146 | # 3, layer is out of the window (lower down in the scroll)
147 |
148 | # This factor can be used to set listeners (layer.on "change:factor")
149 | # that control how a layer (and any other layers) appear as a
150 | # given layer is scrolled
151 |
152 | _setChildLayerFactors: =>
153 | # reset interval time
154 | @time = 0
155 |
156 | @scrollMidY = @scrollY + (@height/2)
157 | @scrollMaxY = @scrollY + @height
158 |
159 | # set child factors
160 | for layer in @content.children
161 |
162 | # edge relationships
163 | yBelow = layer.y > @scrollMaxY
164 | yAbove = layer.y < @scrollY
165 | yInside = @scrollY <= layer.y < @scrollMaxY
166 | maxYAbove = layer.maxY < @scrollY
167 | maxYInside = @scrollY < layer.maxY < @scrollMaxY
168 | maxYBelow = layer.maxY > @scrollMaxY
169 |
170 | # if layer.name is 'special'
171 | # print 'y: ' + layer.y + ' maxY: ' + layer.maxY
172 | # print 'y + scrollY: ' + (layer.y + @scrollY)
173 | # print 'scrollY: ' + @scrollY + ' scrollMaxY: ' + @scrollMaxY
174 | # print layer.factor
175 |
176 | # entering
177 | if yInside and maxYBelow
178 | layer.transitioning = true
179 | layer.factor = Utils.modulate(
180 | layer.y,
181 | [@scrollMidY, @scrollY]
182 | [0, 1]
183 | )
184 | # inside
185 | else if yAbove and maxYBelow
186 | layer.transitioning = false
187 | layer.factor = Utils.modulate(
188 | @scrollY,
189 | [layer.y, layer.maxY - @height]
190 | [1, 2]
191 | )
192 | # exiting
193 | else if maxYInside and yAbove
194 | layer.transitioning = true
195 | layer.factor = Utils.modulate(
196 | layer.maxY,
197 | [@scrollMaxY, @scrollMidY]
198 | [2, 3]
199 | )
200 | else if maxYAbove
201 | layer.transitioning = false
202 | layer.factor = 3
203 | else if yBelow
204 | layer.factor = 0
205 | layer.transitioning = false
206 |
207 | # add a TransitionPage to this component
208 | newPage: (options = {}) =>
209 | _.defaults options,
210 | width: @width
211 | height: @height * 2
212 |
213 | page = new TransitionPage(options)
214 |
215 | @addPage(page, options.direction ? @edge)
216 |
217 | return page
218 |
219 |
220 | # Transition Page
221 |
222 | class TransitionPage extends Layer
223 | constructor: (options = {}) ->
224 |
225 | _.defaults options,
226 | grid: false
227 |
228 | super options
229 |
230 | @transitionStates = {}
231 |
232 | # layers
233 |
234 | if options.grid
235 | Utils.delay .5, =>
236 | lines = Math.floor(@height / 100)
237 | for i in _.range(lines)
238 |
239 | y = i * (@height / lines)
240 |
241 | label = new TextLayer
242 | name: '.'
243 | parent: @
244 | fontSize: 12
245 | padding: {left: 8, right: 8}
246 | textAlign: 'center'
247 | color: '#000'
248 | text: (@y + y).toFixed()
249 |
250 |
251 | line = new Layer
252 | name: '.'
253 | parent: @
254 | height: 1
255 | x: label.maxX
256 | width: @width - label.width
257 | backgroundColor: '#000'
258 |
259 | label.midY = y
260 | line.midY = y
261 |
262 | # definition
263 |
264 | Utils.define @, 'factor', 0, @setFactor
265 |
266 | # events
267 |
268 |
269 | setFactor: (factor) =>
270 | for layerName, props of @transitionStates
271 | layer = Layer.select(layerName)
272 | start = Math.floor(factor % 3)
273 | end = start + 1
274 | newProps = {}
275 |
276 | for prop, array of props
277 | if factor <= 0
278 | newProps[prop] = array[0]
279 | continue
280 | if factor >= 3
281 | newProps[prop] = array[3]
282 | continue
283 |
284 | newProps[prop] = Utils.modulate(
285 | factor,
286 | [start, end],
287 | [array[start], array[end]],
288 | true
289 | )
290 |
291 | layer.props = newProps
292 |
293 |
294 |
295 |
296 | # setFactorProps = (props = {}, startF, endF) ->
297 | # do (props) =>
298 | # @on "change:factor", (factor) ->
299 | # # have manual factor values been provided?
300 | # if startF? and endF?
301 | # for k, v of props
302 | # @[k] = Utils.modulate (factor), [startF, endF], [v[0], v[1]], true
303 | # return
304 |
305 | # # get the correct factorProps.points to modulate between
306 | # start = Math.floor(factor % 3)
307 | # end = start + 1
308 |
309 | # # modulate just between 0 and 1, regardless of factor
310 | # modf = factor % 1
311 |
312 | # for k, v of props
313 | # @[k] = Utils.modulate (modf), [0, 1], [v[start], v[end]], true
314 |
315 |
316 | exports.TransitionPage = TransitionPage
317 | exports.PageTransitionComponent = PageTransitionComponent
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Radiobox.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = 'checkbox'
5 |
6 | class exports.Radiobox extends Layer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 | @__constructor = true
10 | @__instancing = true
11 |
12 | # ---------------
13 | # Options
14 |
15 | _.defaults options,
16 | name: 'Radiobox'
17 | height: 32
18 | width: 32
19 | animationOptions:
20 | time: .2
21 |
22 | checked: false
23 | disabled: false
24 | group: undefined
25 | label: undefined
26 |
27 | _.assign options,
28 | backgroundColor: null
29 |
30 | @group = options.group ? throw 'Radiobox requires a group property (an array).'
31 |
32 | @customOptions = {
33 | color: options.color
34 | }
35 |
36 | options.labelLayer = options.label
37 | delete options.label
38 |
39 | super options
40 |
41 | @props =
42 | x: @x - 4
43 | y: @y - 4
44 |
45 | # ---------------
46 | # Layers
47 |
48 | @iconLayer = new Icon
49 | parent: @
50 | point: Align.center
51 | icon: 'radiobox-blank'
52 | color: options.color
53 |
54 | Utils.linkProperties @, @iconLayer, "color"
55 |
56 |
57 | # ---------------
58 | # Events
59 |
60 | @onTap => @checked = true
61 | @onMouseOver => @hovered = true
62 | @onMouseOut => @hovered = false
63 |
64 |
65 | # ---------------
66 | # Definitions
67 |
68 | delete @__constructor
69 |
70 | isLayer = (value) -> return value.on?
71 |
72 | Utils.define @, 'theme', 'default', @_setTheme
73 | Utils.define @, 'checked', options.checked, @_showChecked, _.isBoolean, 'Radiobox.checked must be a boolean (true or false)'
74 | Utils.define @, 'hovered', false, @_showHovered, _.isBoolean, "Radiobox.hovered must be a boolean (true or false)."
75 | Utils.define @, 'error', options.disabled, @_showError, _.isBoolean, "Radiobox.error must be a boolean (true or false)."
76 | Utils.define @, 'disabled', options.disabled, @_showDisabled, _.isBoolean, "Radiobox.disabled must be a boolean (true or false)."
77 | Utils.define @, 'labelLayer', options.labelLayer, @_setLabelLayer, isLayer, "Radiobox.labelLayer must be a Layer type."
78 |
79 | delete @__instancing
80 |
81 | # ---------------
82 | # Cleanup
83 |
84 | child.name = '.' for child in @children unless options.showSublayers
85 |
86 |
87 | # ---------------
88 | # Private Methods
89 |
90 | _setTheme: (value) =>
91 | @animateStop()
92 | props = @customTheme?[value] ? _.defaults(
93 | _.clone(@customOptions),
94 | theme[MODEL][value]
95 | )
96 |
97 | if @__instancing then @props = props
98 | else @animate props
99 |
100 | _showChecked: (bool) =>
101 | if not bool
102 | @iconLayer.icon = 'radiobox-blank'
103 | return
104 |
105 | @group.active = _.indexOf(@group, @)
106 |
107 | for rb in _.without(@group, @)
108 | rb.checked = false
109 |
110 | @iconLayer.icon = 'radiobox-marked'
111 | return
112 |
113 | _showError: (bool) =>
114 | return if @disabled
115 | @theme = if bool then "error" else "default"
116 |
117 | _showHovered: (bool) =>
118 | return if @disabled
119 | @theme = if bool then "hovered" else "default"
120 |
121 | _setLabelLayer: (layer) =>
122 | return if not layer
123 | layer.onTap => @checked = true
124 |
125 | _showDisabled: (bool) =>
126 | if bool
127 | # show disabled
128 | @theme = 'disabled'
129 | @ignoreEvents = true
130 | return
131 |
132 | # show not disabled
133 | @theme = 'default'
134 | @ignoreEvents = false
135 |
136 | # ---------------
137 | # Public Methods
138 |
139 |
140 | # ---------------
141 | # Special Definitions
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Segment.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = 'segment'
5 |
6 | class exports.Segment extends Layer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 | @__constructor = true
10 | @__instancing = true
11 |
12 | # ---------------
13 | # Options
14 |
15 | _.defaults options,
16 | name: 'Segment'
17 | height: 48
18 | borderRadius: 2
19 | clip: true
20 | animationOptions:
21 | time: .2
22 |
23 | options: ['Left', 'Center', 'Right']
24 | icon: false
25 | dark: false
26 | active: 0
27 |
28 | @customTheme = if options.backgroundColor and options.color then @_getCustomTheme(options.color, options.backgroundColor) else undefined
29 | @customOptions = {}
30 |
31 | @options = options.options
32 | @icon = options.icon
33 |
34 | @__instancing = true
35 | @__constructor = true
36 |
37 | super options
38 |
39 | # ---------------
40 | # Layers
41 |
42 | _.assign @,
43 | options: options.options
44 | buttons: []
45 | icon: options.icon
46 | backgroundColor: null
47 |
48 | @buttons = @options.map (option, i) =>
49 | button = new Button
50 | name: '.'
51 | parent: @
52 | x: 0
53 | y: 0
54 | width: if options.width? then options.width / @options.length
55 | dark: options.dark
56 | secondary: options.secondary
57 | text: if @icon then '' else option
58 | icon: if @icon then option
59 |
60 | radius = switch i
61 | when 0 then "#{Utils.px(button.borderRadius)} 0px 0px #{Utils.px(button.borderRadius)}"
62 | when @options.length - 1 then "0px #{Utils.px(button.borderRadius)} #{Utils.px(button.borderRadius)} 0px"
63 | else "0px 0px 0px 0px"
64 |
65 | button._element.childNodes[0].style['border-radius'] = radius
66 |
67 | return button
68 |
69 | # set positions
70 |
71 | for layer in @buttons
72 | layer.x = (last?.maxX ? 1) - 1
73 | last = layer
74 |
75 | layer.model = 'segment'
76 | layer.customTheme = @customTheme
77 |
78 | do (layer) =>
79 | layer.onSelect => @active = _.indexOf(@children, layer)
80 |
81 | _.assign @,
82 | backgroundColor: null
83 | height: _.maxBy(@children, 'maxY')?.maxY
84 | width: last.maxX
85 |
86 |
87 | # ---------------
88 | # Events
89 |
90 |
91 | # ---------------
92 | # Definitions
93 |
94 | delete @__constructor
95 | button.__instancing = true for button in @buttons
96 |
97 | Utils.define @, 'activeLayer', undefined, @_showActive
98 |
99 | delete button.__instancing for button in @buttons
100 | delete @__instancing
101 |
102 | @active = options.active
103 |
104 | # ---------------
105 | # Cleanup
106 |
107 | child.name = '.' for child in @children unless options.showSublayers
108 |
109 |
110 | # ---------------
111 | # Private Methods
112 |
113 | _getCustomTheme: (color, backgroundColor) ->
114 |
115 | customTheme =
116 | active:
117 | default:
118 | color: color
119 | borderColor: new Color(backgroundColor).darken(10)
120 | backgroundColor: backgroundColor
121 | shadowColor: 'rgba(0,0,0,0)'
122 | disabled:
123 | color: new Color(color).alpha(.15)
124 | borderColor: new Color(color).alpha(.15)
125 | backgroundColor: new Color(backgroundColor).alpha(0)
126 | shadowColor: 'rgba(0,0,0,0)'
127 | touched:
128 | color: color
129 | borderColor: new Color(backgroundColor).darken(20)
130 | backgroundColor: new Color(backgroundColor).darken(20)
131 | shadowColor: 'rgba(0,0,0,0)'
132 | hovered:
133 | color: color
134 | borderColor: new Color(backgroundColor).darken(20)
135 | backgroundColor: new Color(backgroundColor).darken(10)
136 | shadowColor: 'rgba(0,0,0,0)'
137 | default:
138 | default:
139 | color: black
140 | borderColor: white.darken(10)
141 | backgroundColor: white
142 | shadowColor: 'rgba(0,0,0,0)'
143 | disabled:
144 | color: new Color(black).lighten(20)
145 | borderColor: grey40
146 | backgroundColor: grey30
147 | shadowColor: 'rgba(0,0,0,0)'
148 | touched:
149 | color: black
150 | borderColor: grey40
151 | backgroundColor: white
152 | shadowColor: 'rgba(0,0,0,0)'
153 | hovered:
154 | color: black
155 | borderColor: grey40
156 | backgroundColor: grey30
157 | shadowColor: 'rgba(0,0,0,0)'
158 |
159 | return customTheme
160 |
161 | _showActive: (button) =>
162 | return if not button
163 |
164 | button.bringToFront()
165 | button.animateStop()
166 | button.palette = "active"
167 | button.customTheme = @customTheme?.active
168 | button.theme = "default"
169 | button.animate @customTheme?.active.default ? theme[MODEL].active.default
170 |
171 | for sib in button.siblings
172 | sib.animateStop()
173 | sib.palette = "default"
174 | sib.customTheme = @customTheme?.default
175 | sib.theme = "default"
176 | sib.animate( @customTheme?.default.default ? theme[MODEL].default.default)
177 |
178 |
179 | # ---------------
180 | # Public Methods
181 |
182 |
183 | # ---------------
184 | # Special Definitions
185 |
186 | @define "value",
187 | get: -> return @options[@active]
188 |
189 | @define "active",
190 | get: -> return @_active
191 | set: (num) ->
192 | return if @__constructor
193 | return if num is @_active
194 |
195 | if not _.isNumber(num)
196 | throw "Segment.active must be a number (the index of the active layer)."
197 |
198 | if not @children[num]
199 | throw "Segment.active is out of range (no layer found at Toggle.children[#{num}])."
200 |
201 | @_active = num
202 |
203 | @activeLayer = @children[num]
204 |
205 | @emit "change:active", num, @options[num], @children[num]
206 |
207 |
208 |
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Select.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = "select"
5 | OPTION_MODEL = "option"
6 |
7 | class exports.Select extends Layer
8 | constructor: (options = {}) ->
9 | theme = Theme.theme
10 | @__constructor = true
11 | @__instancing = true
12 |
13 | # ---------------
14 | # Options
15 |
16 | _.defaults options,
17 | name: 'Select'
18 | height: theme[MODEL]['default'].height ? 48
19 | clip: false
20 | animationOptions:
21 | time: .2
22 | colorModel: 'husl'
23 |
24 | options: ['Rafael', 'Michelangelo', 'Donatello', 'Leonardo']
25 | selectedIndex: -1
26 | disabled: false
27 |
28 | @customTheme = undefined
29 | @customOptions = {}
30 |
31 | super options
32 |
33 | _.assign @,
34 | options: options.options
35 | optionElements: []
36 | optionLayers: []
37 |
38 | # ---------------
39 | # Layers
40 |
41 | # SelectedContent
42 |
43 | @textLayer = new Body1
44 | name: '.'
45 | parent: @
46 | width: @width
47 | x: theme[MODEL].default.padding ? 12
48 | y: Align.center()
49 | backgroundColor: theme[MODEL].default.backgroundColor ? white
50 | fontFamily: theme[MODEL].default.fontFamily ? "Helvetica"
51 | fontSize: options.fontSize ? theme[MODEL].default.fontSize ? 13
52 | textAlign: options.textAlign ? theme[MODEL].default.textAlign ? "left"
53 | textTransform: options.textTransform ? theme[MODEL].default.textTransform ? "none"
54 |
55 | # Input
56 |
57 | @_input = document.createElement 'select'
58 | @_element.appendChild @_input
59 |
60 | _.assign @_input.style,
61 | width: Utils.px(@width)
62 | height: Utils.px(@height)
63 | '-webkit-appearance': 'none'
64 |
65 | last = 0
66 |
67 | # option layer container
68 | @optionContainer = new Layer
69 | name: '.'
70 | parent: @
71 | width: @width
72 | y: @height
73 | visible: false
74 | clip: true
75 | animationOptions:
76 | time: .2
77 |
78 | @optionContainer.props = @customTheme?["default"] ? _.defaults(
79 | _.clone(@customOptions),
80 | theme[MODEL]["default"]
81 | )
82 |
83 | # create option layers
84 | @optionLayers = _.map options.options, (option, i) =>
85 | opLayer = new Option
86 | name: '.'
87 | handler: @
88 | parent: @optionContainer
89 | y: last
90 | element: @optionElements[i]
91 | index: i
92 | value: option
93 |
94 | last += opLayer.height - 1
95 |
96 | return opLayer
97 |
98 | _.assign @optionContainer,
99 | minHeight: 1
100 | maxHeight: last
101 |
102 | # create icon layer
103 | @iconLayer = new Icon
104 | name: '.'
105 | parent: @
106 | x: Align.right(-8)
107 | y: Align.center
108 | icon: theme[MODEL].default.icon ? 'menu-down'
109 |
110 | # must be set before theme changes
111 |
112 | Utils.linkProperties @, @textLayer, "color"
113 | Utils.linkProperties @, @iconLayer, "color"
114 |
115 | @_setTheme('default')
116 |
117 | # ---------------
118 | # Definitions
119 |
120 | delete @__constructor
121 |
122 | Utils.define @, 'opened', false, @_setOpened, _.isBoolean, "Select.opened must be a boolean (true or false)."
123 | Utils.define @, 'theme', 'default', @_setTheme, _.isString, 'Select.theme must be a string.'
124 | Utils.define @, 'hovered', false, @_showHovered, _.isBoolean, 'Select.hovered must be a boolean.'
125 | Utils.define @, 'focused', false, @_showFocused, _.isBoolean, 'Select.focused must be a boolean.'
126 | Utils.define @, 'disabled', options.disabled, @_showDisabled, _.isBoolean, 'Select.disabled must be a boolean.'
127 | Utils.define @, 'selectedIndex', options.selectedIndex, @_setSelected, _.isNumber, "Select.selectedIndex must be a number."
128 |
129 | delete @__instancing
130 |
131 | # ---------------
132 | # Events
133 |
134 | @onMouseOver => @hovered = true
135 | @onMouseOut => @hovered = false
136 | @_input.oninput = @_setValue
137 | @_input.onblur = => @focused = false; @opened = false
138 | @_input.onfocus = => @focused = true; @opened = true
139 |
140 | @onPan (event) =>
141 | if Math.abs(event.offset.y) > 4
142 | @_input.blur()
143 |
144 | # ---------------
145 | # Cleanup
146 |
147 | child.name = '.' for child in @children unless options.showSublayers
148 |
149 | # ---------------
150 | # Private Methods
151 |
152 | _setOpened: (bool) =>
153 | if bool
154 | # opened is true
155 | _.assign @optionContainer,
156 | parent: @app
157 | y: @screenFrame.y + @height + 2
158 | x: @screenFrame.x
159 | visible: true
160 |
161 | @optionContainer.placeBehind(@app.header)
162 |
163 | @optionContainer.animate
164 | height: @optionContainer.maxHeight
165 | return
166 |
167 | # opened is false
168 |
169 | @optionContainer.once Events.AnimationEnd, =>
170 | _.assign @optionContainer,
171 | parent: @
172 | y: 0
173 | x: 0
174 | visible: false
175 |
176 | @optionContainer.animate
177 | height: @optionContainer.minHeight
178 |
179 | _setSelected: (selectedIndex) =>
180 | if -1 > selectedIndex > @optionLayers.length
181 | throw 'Selected.selectedIndex must be more than -1 or less than its number of options.'
182 |
183 | @_setValue(@optionLayers[selectedIndex]?.value ? "")
184 |
185 | _setValue: (value) =>
186 | @textLayer.text = value
187 | @emit "change:value", value, @
188 |
189 | # generic
190 |
191 | _getCustomTheme: (color, backgroundColor) ->
192 | color = new Color(color)
193 | bg = new Color(backgroundColor)
194 |
195 | return {
196 | default:
197 | color: color
198 | borderColor: bg.darken(10)
199 | backgroundColor: bg
200 | shadowColor: 'rgba(0,0,0,.16)'
201 | disabled:
202 | color: color.alpha(.15)
203 | borderColor: color.alpha(.15)
204 | backgroundColor: bg.alpha(0)
205 | shadowColor: 'rgba(0,0,0,0)'
206 | touched:
207 | color: color
208 | borderColor: bg.darken(20)
209 | backgroundColor: bg.darken(20)
210 | shadowColor: 'rgba(0,0,0,0)'
211 | hovered:
212 | color: color
213 | borderColor: bg.darken(20)
214 | backgroundColor: bg.darken(10)
215 | shadowColor: 'rgba(0,0,0,.16)'
216 | }
217 |
218 | _setTheme: (value) =>
219 | @animateStop()
220 | props = @customTheme?[value] ? _.defaults(
221 | _.clone(@customOptions),
222 | theme[MODEL][value]
223 | )
224 |
225 | if @__instancing then @props = props else @animate props
226 |
227 | _showHovered: (bool) =>
228 | return if @disabled or @focused
229 |
230 | if bool # hovered is true
231 | @theme = "hovered"
232 | return
233 |
234 | # hovered is false
235 | @theme = "default"
236 |
237 | _showFocused: (bool) =>
238 | return if @disabled
239 |
240 | if bool # focused is true
241 | @theme = "focused"
242 | return
243 |
244 | # focused is false
245 | @theme = "default"
246 |
247 | _showDisabled: (bool) =>
248 | if bool # disabled is true
249 | @theme = "disabled"
250 | @ignoreEvents = true
251 | @_input.disabled = true
252 | return
253 |
254 | # focused is false
255 | @theme = "default"
256 | @ignoreEvents = false
257 | @_input.disabled = false
258 |
259 | # ---------------
260 | # Public Methods
261 |
262 |
263 | # ---------------
264 | # Special Definitions
265 |
266 | @define "value",
267 | get: -> return @textLayer.text
268 |
269 |
270 | class Option extends Layer
271 | constructor: (options = {}) ->
272 |
273 | _.defaults options, _.merge(
274 | theme[OPTION_MODEL].default, {
275 | name: '.'
276 | animationOptions:
277 | time: .2
278 | }
279 | )
280 |
281 | super options
282 |
283 | _.assign @,
284 | handler: options.handler
285 | element: options.element
286 | index: options.index
287 | value: options.value
288 |
289 | # ---------------
290 | # Layers
291 |
292 | @textLayer = new Body1
293 | x: 0
294 | y: 0
295 | text: @value
296 | padding: theme[MODEL].default.padding ? 12
297 | fontFamily: theme[MODEL].default.fontFamily ? "Helvetica"
298 | fontSize: options.fontSize ? theme[MODEL].default.fontSize ? 13
299 | textAlign: options.textAlign ? theme[MODEL].default.textAlign ? "left"
300 | textTransform: options.textTransform ? theme[MODEL].default.textTransform ? "none"
301 |
302 | _.assign @,
303 | height: @textLayer.maxY
304 | width: @parent.width
305 |
306 | @textLayer.parent = @
307 |
308 | # ---------------
309 | # Definitions
310 |
311 | Utils.define @, 'theme', 'default', @_setTheme, _.isString, 'Select.theme must be a string.'
312 | Utils.define @, 'hovered', false, @_showHovered, _.isBoolean, 'Select.hovered must be a boolean.'
313 |
314 | # ---------------
315 | # Events
316 |
317 | @onMouseOver => @hovered = true
318 | @onMouseOut => @hovered = false
319 |
320 | @onTap (event) =>
321 | event.stopPropagation()
322 | return if Math.abs(event.offset.x > 12) or Math.abs(event.offset.y > 12)
323 | @handler.selectedIndex = @index
324 |
325 | # ---------------
326 | # Private Methods
327 |
328 | _setTheme: (value) =>
329 | @animateStop()
330 | props = theme[OPTION_MODEL][value]
331 |
332 | if @__instancing then @props = props else @animate props
333 |
334 | _showHovered: (bool) =>
335 | if bool # hovered is true
336 | @theme = "hovered"
337 | return
338 |
339 | # hovered is false
340 | @theme = "default"
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Separator.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | class exports.Separator extends Layer
5 | constructor: (options = {}) ->
6 | theme = Theme.theme
7 | @__constructor = true
8 | @__instancing = true
9 |
10 | # ---------------
11 | # Options
12 |
13 | _.defaults options,
14 | name: 'Separator'
15 | width: Screen.width
16 | height: 16
17 | backgroundColor: '#eee'
18 | clip: true
19 | shadowY: -1
20 | shadowColor: 'rgba(0,0,0,.41)'
21 |
22 | super options
23 |
24 | delete @__constructor
25 | delete @__instancing
26 |
27 | # ---------------
28 | # Cleanup
29 |
30 | child.name = '.' for child in @children unless options.showSublayers
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/SortableComponent.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | class exports.SortableComponent extends Layer
5 | constructor: (options = {}) ->
6 | theme = Theme.theme
7 | @__constructor = true
8 | @__instancing = true
9 |
10 | # ---------------
11 | # Options
12 |
13 | _.defaults options,
14 | name: 'Sortable Component'
15 | defaultState:
16 | scale: 1
17 | shadowY: 0
18 | shadowBlur: 0
19 | draggingState:
20 | scale: 1.07
21 | shadowY: 2
22 | shadowBlur: 16
23 | animationOptions:
24 | time: .31
25 | clip: false
26 | closeGaps: true
27 |
28 | super options
29 |
30 | _.assign @,
31 | positions: []
32 | closeGaps: options.closeGaps
33 | defaultState: options.defaultState
34 | draggingState: options.draggingState
35 |
36 | # ---------------
37 | # Layers
38 |
39 | # ---------------
40 | # Events
41 |
42 | @on "change:children", @_updateChildren
43 | @_context.on "layer:destroy", @_checkForLostChildren
44 |
45 | # ---------------
46 | # Definitions
47 |
48 | delete @__constructor
49 | delete @__instancing
50 |
51 | # ---------------
52 | # Private Methods
53 |
54 | _checkForLostChildren: (layer) =>
55 | if layer.parent is @
56 | @emit "change:children", {added: [], removed: [layer]}
57 |
58 |
59 | _updateChildren: (layers) =>
60 | # scrub up layers that were removed as children
61 | @_removeEvents(layer) for layer in layers.removed
62 |
63 | if @closeGaps and layers.removed.length > 0 and @positions.length > 0
64 | _.last(@children).once Events.AnimationEnd, @_makePositions
65 |
66 | for child, i in @children
67 | child._takePosition(@positions[i])
68 | return
69 |
70 | Utils.delay 0, @_makePositions
71 |
72 |
73 | _makePositions: =>
74 | # make positions based on current child arrangements
75 | @positions = _.map @children, (layer, i) =>
76 |
77 | position =
78 | index: i
79 | layer: layer
80 | midY: layer.midY
81 |
82 | layer.position = position
83 |
84 | @_setEvents(layer)
85 |
86 | return position
87 |
88 |
89 | _setEvents: (layer) =>
90 | # skip if this layer already has suffered the treatment
91 | return if layer._hasSortableEvents
92 |
93 | # assign layer states
94 | layer.states =
95 | default: @defaultState
96 | dragging: @draggingState
97 |
98 | # switch to default state
99 | layer.stateSwitch('default')
100 |
101 | # pass on own animation options as defaults
102 | _.defaults layer.animationOptions, @animationOptions
103 |
104 | # enable draggable
105 | _.assign layer.draggable,
106 | enabled: true
107 | momentum: false
108 | horizontal: false
109 | propagateEvents: false
110 |
111 | # give layer a "take position" property
112 | layer._takePosition = ( position, animate = true ) ->
113 |
114 | @position = position
115 | position.layer = @
116 | if animate
117 | @animate { midY: position.midY }
118 |
119 | # pass events
120 | layer.on Events.DragStart, @_startSearch
121 | layer.on Events.Drag, @_duringSearch
122 | layer.on Events.DragEnd, @_endSearch
123 |
124 | # make a note that this layer has already been treated
125 | layer._hasSortableEvents = true
126 |
127 |
128 | # clear events when a layer is lost as a child
129 | _removeEvents: (layer) ->
130 | delete layer._takePosition
131 | delete layer._hasSortableEvents
132 |
133 | layer.off Events.TouchStart, @_startSearch
134 | layer.off Events.Drag, @_duringSearch
135 | layer.off Events.DragEnd, @_endSearch
136 |
137 |
138 | # when the user starts dragging...
139 | _startSearch: (event) ->
140 | return if @handle? and not Utils.pointInLayer(event.point, @handle)
141 |
142 | @_sortableStarted = true
143 | @bringToFront()
144 | @animate "dragging"
145 |
146 |
147 | # while the user is dragging...
148 | _duringSearch: ->
149 | if not @_sortableStarted
150 | @midY = @position.midY
151 | return
152 |
153 | above = @parent.positions[ @position.index + 1 ]
154 | below = @parent.positions[ @position.index - 1 ]
155 |
156 | if below?.midY < @midY < above?.midY
157 | return
158 |
159 | if @midY > above?.midY
160 | above.layer._takePosition( @position, true )
161 | @_takePosition( above, false )
162 |
163 | else if @midY < below?.midY
164 | below.layer._takePosition( @position, true )
165 | @_takePosition( below, false )
166 |
167 |
168 | # ... and when the user ends the drag
169 | _endSearch: ->
170 | return if not @_sortableStarted
171 |
172 | delete @_sortableStarted
173 | @_takePosition(@position)
174 | @animate 'default'
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Stepper.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = 'segment'
5 |
6 | class exports.Stepper extends Layer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 | @__constructor = true
10 | @__instancing = true
11 |
12 | # ---------------
13 | # Options
14 |
15 | _.defaults options,
16 | name: 'Stepper'
17 | height: 48
18 | borderRadius: 4
19 | shadowY: 2
20 | shadowBlur: 6
21 | shadowColor: 'rgba(0,0,0,.16)'
22 | clip: true
23 | animationOptions:
24 | time: .2
25 |
26 | options: ["minus", "plus"]
27 | icon: true
28 | min: 0
29 | max: 10
30 | value: 5
31 | width: 180
32 |
33 | @customTheme = if options.backgroundColor and options.color then @_getCustomTheme(options.color, options.backgroundColor) else undefined
34 | @customOptions = {}
35 |
36 | @options = options.options
37 | @icon = options.icon
38 |
39 | @__constructor = true
40 |
41 | super options
42 |
43 | # ---------------
44 | # Layers
45 |
46 | _.assign @,
47 | min: options.min
48 | max: options.max
49 | options: options.options
50 | buttons: []
51 | icon: options.icon
52 |
53 | @textLayer = new Label
54 | parent: @
55 | y: Align.center()
56 | padding: {left: 24, right: 24}
57 | textAlign: 'center'
58 | width: @width
59 | text: options.value
60 |
61 | # Buttons
62 |
63 | @buttons = @options[0..1].map (option, i) =>
64 | button = new Button
65 | name: 'Button ' + i
66 | parent: @
67 | x: 0
68 | y: 0
69 | color: options.color
70 | text: if @icon then '' else option
71 | icon: if @icon then option
72 | backgroundColor: options.backgroundColor
73 |
74 | customTheme = @customTheme
75 |
76 | button.palette = 'active'
77 | button.model = 'segment'
78 |
79 | radius = switch i
80 | when 0 then "#{Utils.px(button.borderRadius)} 0px 0px #{Utils.px(button.borderRadius)}"
81 | when 1 then "0px #{Utils.px(button.borderRadius)} #{Utils.px(button.borderRadius)} 0px"
82 | else "0px 0px 0px 0px"
83 |
84 | button._element.childNodes[0].style['border-radius'] = radius
85 |
86 | return button
87 |
88 | # set positions
89 |
90 | maxW = _.maxBy(@buttons, 'width').width
91 |
92 | if @width < (maxW * 3)
93 | @width = maxW * 3
94 | @textLayer.width = @width
95 |
96 | _.assign @buttons[0],
97 | select: => @value--
98 | x: 0
99 | width: maxW
100 |
101 | _.assign @buttons[1],
102 | select: => @value++
103 | x: Align.right()
104 | width: maxW
105 |
106 | _.assign @,
107 | backgroundColor: white
108 | height: _.maxBy(@children, 'maxY')?.maxY
109 |
110 | delete @__constructor
111 |
112 | # ---------------
113 | # Events
114 |
115 | @on "change:value", @_showValue
116 |
117 | # ---------------
118 | # Definitions
119 |
120 | delete @__constructor
121 | button.__instancing = true for button in @buttons
122 |
123 | # Property Initial value Callback Validation Error
124 | Utils.define @, 'value', options.value, @_showValue, _.isNumber, 'Stepper.value must be a number.'
125 |
126 | delete button.__instancing for button in @buttons
127 | delete @__instancing
128 |
129 | # ---------------
130 | # Cleanup
131 |
132 | child.name = '.' for child in @children unless options.showSublayers
133 |
134 | # ---------------
135 | # Private Methods
136 |
137 | _getCustomTheme: (color, backgroundColor) ->
138 | return {
139 | default:
140 | color: color
141 | borderColor: new Color(backgroundColor).darken(10)
142 | backgroundColor: backgroundColor
143 | shadowColor: 'rgba(0,0,0,0)'
144 | disabled:
145 | color: new Color(color).alpha(.15)
146 | borderColor: new Color(color).alpha(.15)
147 | backgroundColor: new Color(backgroundColor).alpha(0)
148 | shadowColor: 'rgba(0,0,0,0)'
149 | touched:
150 | color: color
151 | borderColor: new Color(backgroundColor).darken(20)
152 | backgroundColor: new Color(backgroundColor).darken(20)
153 | shadowColor: 'rgba(0,0,0,0)'
154 | hovered:
155 | color: color
156 | borderColor: new Color(backgroundColor).darken(20)
157 | backgroundColor: new Color(backgroundColor).darken(10)
158 | shadowColor: 'rgba(0,0,0,0)'
159 | }
160 |
161 | _showValue: (num) =>
162 | switch num
163 | when @min
164 | @buttons[0].disabled = true
165 | @buttons[1].disabled = false
166 | when @max
167 | @buttons[0].disabled = false
168 | @buttons[1].disabled = true
169 | else
170 | @buttons[0].disabled = false
171 | @buttons[1].disabled = false
172 |
173 | @textLayer.text = num
174 |
175 | # ---------------
176 | # Public Methods
177 |
178 |
179 | # ---------------
180 | # Special Definitions
181 |
182 | @define 'value',
183 | get: -> return @_value
184 | set: (num) ->
185 | return if @__constructor
186 |
187 | if not _.isNumber(num)
188 | throw 'Stepper.value must be a number.'
189 |
190 | num = _.clamp(num, @min, @max)
191 |
192 | return if num is @_value
193 |
194 | @_value = num
195 |
196 | @emit "change:value", num, @
197 |
198 |
199 |
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Template.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = "component"
5 |
6 | class exports.NewComponent extends Layer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 | @__constructor = true
10 | @__instancing = true
11 |
12 | # ---------------
13 | # Options
14 |
15 | _.defaults options,
16 | name: 'New Component'
17 | animationOptions:
18 | time: .2
19 | colorModel: 'husl'
20 |
21 | @customTheme = undefined
22 | @customOptions = {}
23 |
24 | super options
25 |
26 | # ---------------
27 | # Layers
28 |
29 | # ---------------
30 | # Cleanup
31 |
32 | child.name = '.' for child in @children unless options.showSublayers
33 |
34 | # ---------------
35 | # Events
36 |
37 | # ---------------
38 | # Definitions
39 |
40 | delete @__constructor
41 |
42 | # Property Initial value Callback Validation Error
43 | Utils.define @, 'theme', 'default', @_setTheme
44 | Utils.define @, 'selected', options.selected, @showSelected, _.isBoolean, 'Selected must be a boolean (true or false).'
45 |
46 |
47 | delete @__instancing
48 |
49 |
50 | # ---------------
51 | # Private Methods
52 |
53 | _getCustomTheme: (color, backgroundColor) ->
54 | color = new Color(color)
55 | bg = new Color(backgroundColor)
56 |
57 | return {
58 | default:
59 | color: color
60 | borderColor: bg.darken(10)
61 | backgroundColor: bg
62 | shadowColor: 'rgba(0,0,0,.16)'
63 | disabled:
64 | color: color.alpha(.15)
65 | borderColor: color.alpha(.15)
66 | backgroundColor: bg.alpha(0)
67 | shadowColor: 'rgba(0,0,0,0)'
68 | touched:
69 | color: color
70 | borderColor: bg.darken(20)
71 | backgroundColor: bg.darken(20)
72 | shadowColor: 'rgba(0,0,0,0)'
73 | hovered:
74 | color: color
75 | borderColor: bg.darken(20)
76 | backgroundColor: bg.darken(10)
77 | shadowColor: 'rgba(0,0,0,.16)'
78 | }
79 |
80 |
81 | _setTheme: (value) =>
82 | @animateStop()
83 | props = @customTheme?[value] ? _.defaults(
84 | _.clone(@customOptions),
85 | theme[MODEL][value]
86 | )
87 |
88 | if @__instancing then @props = props
89 | else @animate props
90 |
91 | # ---------------
92 | # Public Methods
93 |
94 |
95 | # ---------------
96 | # Special Definitions
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/TextInput.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = 'textInput'
5 |
6 | class exports.TextInput extends Layer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 | @__constructor = true
10 | @__instancing = true
11 |
12 | # TODO
13 | # * Scroll to Input when on a mobile device (with screen keyboard)
14 |
15 | # ---------------
16 | # Options
17 |
18 | _.defaults options,
19 | name: 'TextInput'
20 | width: 260
21 | placeholder: "Placeholder"
22 | disabled: false
23 | clip: true
24 | value: ''
25 | animationOptions:
26 | time: .15
27 |
28 | if options.label then throw "Make a Label instance separately!"
29 | delete options.label
30 |
31 | _.assign options,
32 | height: theme[MODEL].default.height ? 48
33 |
34 | @customOptions =
35 | color: options.color
36 | backgroundColor: options.backgroundColor
37 |
38 | super options
39 |
40 | _.assign @,
41 | placeholder: options.placeholder
42 |
43 | # ---------------
44 | # Layers
45 |
46 | @textLayer = new Body2
47 | name: '.'
48 | parent: @
49 | color: @color
50 | y: Align.center()
51 | width: @width
52 | padding: theme[MODEL].default.padding ? 12
53 | backgroundColor: theme[MODEL].default.backgroundColor ? white
54 | fontFamily: theme[MODEL].default.fontFamily ? "Helvetica"
55 | fontSize: options.fontSize ? theme[MODEL].default.fontSize ? 13
56 | textAlign: options.textAlign ? theme[MODEL].default.textAlign ? "left"
57 | textTransform: options.textTransform ? theme[MODEL].default.textTransform ? "none"
58 | text: @placeholder
59 |
60 | Utils.linkProperties @, @textLayer, "color"
61 |
62 | # Input
63 |
64 | @_input = document.createElement 'input'
65 | @_element.appendChild @_input
66 |
67 | _.assign @_input,
68 | # placeholder: options.placeholder
69 | value: options.value ? null
70 | className: @name
71 |
72 | for attr in ["autocorrect", "autocomplete", "autocapitalize", "spellcheck"]
73 | @_input.setAttribute attr, "off"
74 |
75 | _.assign @_input.style,
76 | width: Utils.px(@width - 24)
77 | height: Utils.px(@height)
78 | padding: "0 #{Utils.px(theme[MODEL].default.padding ? 12)}"
79 | backgroundColor: theme[MODEL].default.backgroundColor ? white
80 | textAlign: options.textAlign ? theme[MODEL].default.textAlign ? "left"
81 | textTransform: options.textTransform ? theme[MODEL].default.textTransform ? "none"
82 | fontFamily: options.fontFamily ? theme.typography.Body2.fontFamily ? "Helvetica"
83 | fontSize: Utils.px(options.fontSize ? theme.typography.Body2.fontSize ? 13)
84 | fontWeight: options.fontWeight ? theme[MODEL].default.fontWeight ? theme.typography.Body2.fontWeight ? 500
85 |
86 | # must be set before theme changes
87 |
88 | Utils.linkProperties @, @_input.style, "color"
89 | Utils.linkProperties @, @_input.style, "backgroundColor"
90 |
91 | @_setTheme('default')
92 |
93 | # ---------------
94 | # Definitions
95 |
96 | delete @__constructor
97 |
98 | # Property Initial value Callback Validation Error
99 | Utils.define @, 'theme', 'default', @_setTheme, _.isString, 'TextInput.theme must be a string.'
100 | Utils.define @, 'hovered', false, @_showHovered, _.isBoolean, 'TextInput.hovered must be a boolean.'
101 | Utils.define @, 'focused', false, @_showFocused, _.isBoolean, 'TextInput.focused must be a boolean.'
102 | Utils.define @, 'disabled', options.disabled, @_showDisabled, _.isBoolean, 'TextInput.disabled must be a boolean.'
103 |
104 | delete @__instancing
105 |
106 | # ---------------
107 | # Events
108 |
109 | @onMouseOver => @hovered = true
110 | @onMouseOut => @hovered = false
111 | @_input.oninput = @_setValue
112 | @_input.onblur = =>
113 | @app.focused = null
114 | @focused = false
115 | @_input.onfocus = =>
116 | @app.focused = @_input
117 | @focused = true
118 |
119 | @value = options.value
120 |
121 | # ---------------
122 | # Cleanup
123 |
124 | child.name = '.' for child in @children unless options.showSublayers
125 |
126 | # ---------------
127 | # Private Functions
128 |
129 | _setValue: () =>
130 | value = @_input.value
131 | @emit "change:value", value, @
132 |
133 | _setTheme: (value) =>
134 | @animateStop()
135 | props = _.defaults _.clone(@customOptions), theme[MODEL][value]
136 | if @__instancing then @props = props else @animate props
137 |
138 | _showHovered: (bool) =>
139 | return if @disabled or @focused
140 |
141 | if bool # hovered is true
142 | @theme = "hovered"
143 | return
144 |
145 | # hovered is false
146 | @theme = "default"
147 |
148 | _showFocused: (bool) =>
149 | return if @disabled
150 |
151 | if bool # focused is true
152 | @textLayer.visible = false
153 | @theme = "focused"
154 | return
155 |
156 | # focused is false
157 | @textLayer.visible = @value is ""
158 | @theme = "default"
159 |
160 | _showDisabled: (bool) =>
161 | if bool # disabled is true
162 | @theme = "disabled"
163 | @ignoreEvents = true
164 | @_input.disabled = true
165 | return
166 |
167 | # focused is false
168 | @theme = "default"
169 | @ignoreEvents = false
170 | @_input.disabled = false
171 |
172 | # ---------------
173 | # Public Functions
174 |
175 | forceBlur: =>
176 | @_input?.blur()
177 |
178 | # ---------------
179 | # Special Definitions
180 |
181 | @define "value",
182 | get: -> return @_input.value
183 | set: (value) ->
184 | return if @__constructor
185 |
186 | @_input.value = value
187 | @textLayer.visible = @value is ""
188 | @emit "change:value", value, @
189 |
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Toggle.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = 'segment'
5 |
6 | class exports.Toggle extends Layer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 | @__constructor = true
10 | @__instancing = true
11 |
12 | # ---------------
13 | # Options
14 |
15 | _.defaults options,
16 | name: 'Toggle'
17 | height: 48
18 | clip: true
19 | animationOptions:
20 | time: .2
21 | colorModel: 'husl'
22 |
23 | options: ["Off", "On"]
24 | icon: false
25 | toggled: false
26 |
27 | @customTheme = if options.backgroundColor and options.color then @_getCustomTheme(options.color, options.backgroundColor) else undefined
28 | @customOptions = {}
29 |
30 | @options = options.options
31 | @icon = options.icon
32 |
33 | super options
34 |
35 | # ---------------
36 | # Layers
37 |
38 | _.assign @,
39 | options: options.options
40 | buttons: []
41 | icon: options.icon
42 |
43 | @buttons = @options[0..1].map (option, i) =>
44 | button = new Button
45 | name: 'Button ' + i
46 | parent: @
47 | text: if @icon then '' else option
48 | icon: if @icon then option
49 |
50 | radius = switch i
51 | when 0 then "#{Utils.px(button.borderRadius)} 0px 0px #{Utils.px(button.borderRadius)}"
52 | when @options.length - 1 then "0px #{Utils.px(button.borderRadius)} #{Utils.px(button.borderRadius)} 0px"
53 | else "0px 0px 0px 0px"
54 |
55 | button._element.childNodes[0].style['border-radius'] = radius
56 |
57 | return button
58 |
59 | # set positions
60 |
61 | maxW = _.maxBy(@buttons, 'width').width
62 |
63 | for button in @buttons
64 | button.width = maxW
65 | button.x = (last?.maxX ? 1) - 1
66 | last = button
67 |
68 | button.customTheme = @customTheme
69 | button.model = MODEL
70 |
71 | do (button) =>
72 | button.onSelect => @toggled = _.indexOf(@children, button) is 1
73 |
74 | _.assign @,
75 | backgroundColor: null
76 | height: _.maxBy(@children, 'maxY')?.maxY
77 | width: last.maxX
78 |
79 | # ---------------
80 | # Events
81 |
82 | # ---------------
83 | # Definitions
84 | #
85 | isOk = (value) -> _.isBoolean(value) or _.isUndefined(value)
86 |
87 | delete @__constructor
88 | button.__instancing = true for button in @buttons
89 |
90 | # Property Initial value Callback Validation Error
91 | Utils.define @, 'activeLayer', null, @_showActive
92 | Utils.define @, 'toggled', options.toggled, @_setToggled, isOk, 'Toggle.toggled must be a boolean (true or false) or undefined.'
93 |
94 | delete button.__instancing for button in @buttons
95 | delete @__instancing
96 |
97 | # ---------------
98 | # Cleanup
99 |
100 | child.name = '.' for child in @children unless options.showSublayers
101 |
102 | # ---------------
103 | # Private Methods
104 |
105 | _getCustomTheme: (color, backgroundColor) ->
106 | customTheme =
107 | active:
108 | default:
109 | color: color
110 | borderColor: new Color(backgroundColor).darken(10)
111 | backgroundColor: backgroundColor
112 | shadowColor: 'rgba(0,0,0,0)'
113 | disabled:
114 | color: new Color(color).alpha(.15)
115 | borderColor: new Color(color).alpha(.15)
116 | backgroundColor: new Color(backgroundColor).alpha(0)
117 | shadowColor: 'rgba(0,0,0,0)'
118 | touched:
119 | color: color
120 | borderColor: new Color(backgroundColor).darken(20)
121 | backgroundColor: new Color(backgroundColor).darken(20)
122 | shadowColor: 'rgba(0,0,0,0)'
123 | hovered:
124 | color: color
125 | borderColor: new Color(backgroundColor).darken(20)
126 | backgroundColor: new Color(backgroundColor).darken(10)
127 | shadowColor: 'rgba(0,0,0,0)'
128 | default:
129 | default:
130 | color: black
131 | borderColor: white.darken(10)
132 | backgroundColor: white
133 | shadowColor: 'rgba(0,0,0,0)'
134 | disabled:
135 | color: new Color(black).lighten(20)
136 | borderColor: grey40
137 | backgroundColor: grey30
138 | shadowColor: 'rgba(0,0,0,0)'
139 | touched:
140 | color: black
141 | borderColor: grey40
142 | backgroundColor: white
143 | shadowColor: 'rgba(0,0,0,0)'
144 | hovered:
145 | color: black
146 | borderColor: grey40
147 | backgroundColor: grey30
148 | shadowColor: 'rgba(0,0,0,0)'
149 |
150 | return customTheme
151 |
152 |
153 | _setToggled: (bool) =>
154 | if bool is null
155 | @active = -1
156 | return
157 |
158 | @active = if bool then 1 else 0
159 |
160 |
161 | _showActive: (button) =>
162 | if not button
163 | for button in @buttons
164 | button.animateStop()
165 | button.customTheme = @customTheme?.default
166 | button.theme = "default"
167 | button.animate( @customTheme?.default.default ? theme[MODEL].default.default)
168 | return
169 |
170 | button.bringToFront()
171 | button.animateStop()
172 | button.palette = "active"
173 | button.customTheme = @customTheme?.active
174 | button.theme = "default"
175 | button.animate( @customTheme?.active.default ? theme[MODEL].active.default)
176 |
177 | for sib in button.siblings
178 | sib.animateStop()
179 | sib.palette = "default"
180 | sib.customTheme = @customTheme?.default
181 | sib.theme = "default"
182 | sib.animate( @customTheme?.default.default ? theme[MODEL].default.default)
183 |
184 | # ---------------
185 | # Public Methods
186 |
187 | # ---------------
188 | # Special Definitions
189 |
190 | @define "value", ->
191 | get: -> return @toggled
192 | set: (value) -> @toggled = value
193 |
194 | @define "active",
195 | get: -> return @_active
196 | set: (num) ->
197 | return if @__constructor
198 | return if num is @_active
199 |
200 | if not _.isNumber(num)
201 | throw "Toggle.active must be a number (the index of the active layer)."
202 |
203 | if num >= 0 and not @children[num]
204 | throw "Index is out of range (no layer found at Toggle.children[#{num}])."
205 |
206 | @_active = num
207 |
208 | @activeLayer = @children[num]
209 |
210 | @emit "change:active", num, @options[num], @children[num]
211 |
212 |
213 |
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Tooltip.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | MODEL = "tooltip"
5 |
6 | class exports.Tooltip extends Layer
7 | constructor: (options = {}) ->
8 | theme = Theme.theme
9 | @__constructor = true
10 | @__instancing = true
11 |
12 | # ---------------
13 | # Options
14 |
15 | _.defaults options,
16 | name: 'Tooltip'
17 | animationOptions:
18 | time: .2
19 | colorModel: 'husl'
20 |
21 | text: 'Tooltip'
22 | position: 'below'
23 |
24 | @customTheme = undefined
25 | @customOptions = {}
26 |
27 | super options
28 |
29 | _.assign @,
30 | text: options.text
31 | position: options.position
32 |
33 | # ---------------
34 | # Layers
35 |
36 | @diamond = new Layer
37 | name: 'Diamond'
38 | parent: @
39 | size: 12
40 | rotation: 45
41 |
42 | Utils.linkProperties @, @diamond, 'backgroundColor'
43 |
44 | @textLayer = new Body2
45 | name: 'Text'
46 | color: white
47 | padding: {top: 15, bottom: 15, left: 15, right: 15}
48 | text: @text
49 |
50 | if @textLayer.width < 150
51 | _.assign @textLayer,
52 | width: 150
53 | textAlign: 'center'
54 |
55 | @size = @textLayer.size
56 | @textLayer.parent = @
57 |
58 | # ---------------
59 | # Events
60 |
61 | # ---------------
62 | # Definitions
63 |
64 | delete @__constructor
65 |
66 | # Property Initial value Callback Validation Error
67 | Utils.define @, 'theme', 'default', @_setTheme
68 | Utils.define @, 'position', options.position, @_showPosition, _.isString, "Tooltip.position must be a string."
69 |
70 | delete @__instancing
71 | # ---------------
72 | # Cleanup
73 |
74 | child.name = '.' for child in @children unless options.showSublayers
75 |
76 | # ---------------
77 | # Private Methods
78 |
79 | _getCustomTheme: (color, backgroundColor) ->
80 | color = new Color(color)
81 | bg = new Color(backgroundColor)
82 |
83 | return {
84 | default:
85 | color: color
86 | borderColor: bg.darken(10)
87 | backgroundColor: bg
88 | shadowColor: 'rgba(0,0,0,.16)'
89 | disabled:
90 | color: color.alpha(.15)
91 | borderColor: color.alpha(.15)
92 | backgroundColor: bg.alpha(0)
93 | shadowColor: 'rgba(0,0,0,0)'
94 | touched:
95 | color: color
96 | borderColor: bg.darken(20)
97 | backgroundColor: bg.darken(20)
98 | shadowColor: 'rgba(0,0,0,0)'
99 | hovered:
100 | color: color
101 | borderColor: bg.darken(20)
102 | backgroundColor: bg.darken(10)
103 | shadowColor: 'rgba(0,0,0,.16)'
104 | }
105 |
106 |
107 | _setTheme: (value) =>
108 | @animateStop()
109 | props = @customTheme?[value] ? _.defaults(
110 | _.clone(@customOptions),
111 | theme[MODEL][value]
112 | )
113 |
114 | if @__instancing then @props = props else @animate props
115 |
116 |
117 | _showPosition: (string) ->
118 | switch string
119 | when "above"
120 | @diamond.props =
121 | x: Align.center
122 | y: Align.bottom(6)
123 | rotationY: 40
124 | rotationX: 0
125 | when "below"
126 | @diamond.props =
127 | x: Align.center
128 | y: -6
129 | rotationY: 40
130 | rotationX: 0
131 | when "right"
132 | @diamond.props =
133 | x: -6
134 | y: Align.center()
135 | rotationY: 0
136 | rotationX: 40
137 | when "left"
138 | @diamond.props =
139 | x: Align.right(6)
140 | y: Align.center()
141 | rotationY: 0
142 | rotationX: 40
143 | else
144 | throw 'Tooltip.position must be either "above", "right", "below", or "left".'
145 |
146 |
147 | # ---------------
148 | # Public Methods
149 |
150 |
151 | # ---------------
152 | # Special Definitions
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/Typography.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = Theme.theme
3 |
4 | { Link } = require 'components/Link'
5 | framework = require 'framework'
6 |
7 | updateTypography = ->
8 | for className, style of theme.typography
9 | do (className, style) =>
10 |
11 | window[className] = class FrameworkComponent extends TextLayer
12 | constructor: (options = {}) ->
13 | @app = framework.app
14 |
15 | theme = Theme.theme
16 |
17 | _.defaults options, theme.typography[className]
18 | _.defaults options, theme.typography[style.style]
19 |
20 |
21 | super options
22 |
23 | window[className + 'Link'] = class FrameworkComponent extends Link
24 | constructor: (options = {}) ->
25 | @app = framework.app
26 |
27 | theme = Theme.theme
28 |
29 | _.defaults options, theme.typography[className]
30 | _.defaults options, theme.typography[style.style]
31 |
32 |
33 | super options
34 |
35 | exports.updateTypography = updateTypography
36 | updateTypography()
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/components/View.coffee:
--------------------------------------------------------------------------------
1 | Theme = require "components/Theme"
2 | theme = undefined
3 |
4 | class exports.View extends ScrollComponent
5 | constructor: (options = {}) ->
6 | theme = Theme.theme
7 | @__constructor = true
8 | @__instancing = true
9 |
10 | # ---------------
11 | # Options
12 |
13 | _.defaults options,
14 | backgroundColor: '#FFF'
15 | contentInset:
16 | bottom: 64
17 |
18 | padding: {}
19 | title: ''
20 | load: null
21 | unload: null
22 | key: null
23 | clip: false
24 | preserveContent: false
25 | oneoff: false
26 |
27 | _.assign options,
28 | width: @app.contentWidth
29 | height: @app.windowFrame.height
30 | scrollHorizontal: false
31 |
32 | super options
33 |
34 | @key = options.key
35 |
36 | # ---------------
37 | # Layers
38 |
39 | @app.views.push(@)
40 | @content.backgroundColor = @backgroundColor
41 | @sendToBack()
42 |
43 | # ---------------
44 | # Definitions
45 |
46 | delete @__constructor
47 |
48 | # Property Initial value Callback Validation Error
49 | Utils.define @, 'title', options.title, undefined, _.isString, 'View.title must be a string.'
50 | Utils.define @, 'padding', options.padding, undefined, _.isObject, 'View.padding must be an object.'
51 | Utils.define @, 'load', options.load, undefined, _.isFunction, 'View.load must be a function.'
52 | Utils.define @, 'unload', options.unload, undefined, _.isFunction, 'View.unload must be a function.'
53 | Utils.define @, 'oneoff', options.oneoff, undefined, _.isBoolean, 'View.oneoff must be a boolean (true or false).'
54 | Utils.define @, 'preserveContent', options.preserveContent, undefined, _.isBoolean, 'View.preserveContent must be a boolean (true or false).'
55 |
56 | delete @__instancing
57 |
58 | # unless padding is specifically null, set padding defaults
59 | if @padding?
60 | _.defaults @padding,
61 | left: 16,
62 | right: 16,
63 | top: 16,
64 |
65 | # ---------------
66 | # Events
67 |
68 | @content.on "change:children", @_fitChildrenToPadding
69 | @app.on "change:windowFrame", @_updateSize
70 |
71 | # ---------------
72 | # Private Functions
73 |
74 | _delayUpdateSize: =>
75 | Utils.delay 1, @_updateSize
76 |
77 |
78 | _updateSize: (windowFrame) =>
79 | # perhaps doing nothing is the best thing to do
80 | @keyLayer?.y = 8 + (@app.windowFrame.y - @y)
81 | return
82 |
83 |
84 | _fitChildrenToPadding: (children) =>
85 | return if not @padding
86 |
87 | w = @width - @padding.right - @padding.left
88 |
89 | for child in children.added
90 | if child.x < @padding.left then child.x = @padding.left
91 | if child.y < @padding.top then child.y = @padding.top
92 | if child.width > w
93 | Utils.delay 0, -> child.width = w
94 |
95 | # ---------------
96 | # Private Methods
97 |
98 | _loadView: (app, next, prev) =>
99 | try
100 | return if @_initial and @preserveContent
101 | @load(app, next, prev)
102 | @_initial = true
103 | catch
104 | throw "View ('#{@title ? @name}') must have a working `load` property (a callback). If it does have one, there's an error in it!"
105 | @app.loading = false
106 |
107 | if @key
108 | @keyLayer = new TextLayer
109 | name: "Key: #{@key}"
110 | parent: @
111 | fontSize: 12
112 | fontWeight: 600
113 | y: 8
114 | width: @width
115 | textAlign: 'center'
116 | color: '#000'
117 | text: @key
118 |
119 |
120 | _unloadView: (app, next, prev, direction) =>
121 | try @unload(app, next, prev, direction)
122 |
123 | return if @preserveContent
124 |
125 | child.destroy() for child in _.without(@children, @content)
126 | child.destroy() for child in @content.children
127 |
128 | if @oneoff and direction is 'back'
129 | @destroy()
130 | return
131 |
132 | # ---------------
133 | # Public Methods
134 |
135 |
136 | refresh: (loadingTime) =>
137 | loadingTime ?= _.random(.3, .5)
138 |
139 | @app.loading = true
140 | @_unloadView()
141 |
142 | Utils.delay loadingTime, => @app.showNext(@)
143 |
144 |
145 | onLoad: (callback) ->
146 | @load = callback
147 |
148 |
149 | onUnload: (callback) ->
150 | @unload = callback
151 |
152 | # ---------------
153 | # Special Definitions
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/framework.coffee:
--------------------------------------------------------------------------------
1 | require 'moreutils'
2 | theme = require 'components/Theme'
3 | colors = require 'components/Colors'
4 | typography = require 'components/Typography'
5 |
6 | colors.updateColors()
7 |
8 | # disable hints
9 | Framer.Extras.Hints.disable()
10 |
11 | # get rid of dumb thing that blocks events in the upper left-hand corner
12 | dumbthing = document.getElementById("FramerContextRoot-TouchEmulator")?.childNodes[0]
13 | dumbthing?.style.width = "0px"
14 |
15 | # require in everything else
16 | { Button } = require 'components/Button'
17 | { Radiobox } = require 'components/Radiobox'
18 | { Checkbox } = require 'components/Checkbox'
19 | { DocComponent } = require 'components/DocComponent'
20 | { Footer } = require 'components/Footer'
21 | { Header } = require 'components/Header'
22 | { Segment } = require 'components/Segment'
23 | { Toggle } = require 'components/Toggle'
24 | { Tooltip } = require 'components/Tooltip'
25 | { Icon } = require 'components/Icon'
26 | { Link } = require 'components/Link'
27 | { Separator } = require 'components/Separator'
28 | { Select } = require 'components/Select'
29 | { Stepper } = require 'components/Stepper'
30 | { TextInput } = require 'components/TextInput'
31 | { View } = require 'components/View'
32 | { CarouselComponent } = require 'components/CarouselComponent'
33 | { PageTransitionComponent } = require 'components/PageTransitionComponent'
34 | { SortableComponent } = require 'components/SortableComponent'
35 | { TransitionPage } = require 'components/PageTransitionComponent'
36 |
37 | # Exports for theme support
38 | _.assign exports,
39 | defaultTitle: "www.framework.com"
40 | app: undefined
41 | components: [
42 | 'Button',
43 | 'Header',
44 | 'Radiobox',
45 | 'Checkbox',
46 | 'DocComponent',
47 | 'Toggle',
48 | 'Tooltip',
49 | 'Select',
50 | 'Icon',
51 | 'Stepper',
52 | 'Segment',
53 | 'TextInput',
54 | 'Link',
55 | 'Separator',
56 | 'TransitionPage',
57 | 'View',
58 | 'CarouselComponent',
59 | 'SortableComponent'
60 | 'PageTransitionComponent'
61 | ]
62 | theme: theme
63 | typography: typography
64 | colors: colors
65 |
66 | # Add components to window
67 | exports.components.forEach (componentName) ->
68 | window[componentName] = class FrameworkComponent extends eval(componentName)
69 | constructor: (options = {}) ->
70 | @app = exports.app
71 | super options
72 |
73 |
74 | # ... and finally, the App class
75 | class window.App extends FlowComponent
76 | constructor: (options = {}) ->
77 |
78 | exports.app = @
79 |
80 | _.defaults options,
81 | backgroundColor: white
82 | title: exports.defaultTitle
83 | chrome: 'ios'
84 | contentWidth: Screen.width
85 |
86 | super options
87 |
88 | _.assign @,
89 | chrome: options.chrome
90 | _windowFrame: {}
91 | views: []
92 | contentWidth: Screen.width
93 |
94 | # Transition
95 |
96 | @_platformTransition = switch @chrome
97 | when "safari"
98 | @_safariTransition
99 | when "ios"
100 | @_iosTransition
101 | else
102 | @_defaultTransition
103 |
104 | # layers
105 |
106 | @loadingLayer = new Layer
107 | name: '.'
108 | size: Screen.size
109 | backgroundColor: if @chrome is "safari" then 'rgba(0,0,0,0)' else 'rgba(0,0,0,.14)'
110 | visible: false
111 |
112 | @loadingLayer._element.style["pointer-events"] = "all"
113 | @loadingLayer.sendToBack()
114 |
115 | # By this point, these should be different classes...
116 | unless @chrome is "safari"
117 | Utils.bind @loadingLayer, ->
118 |
119 | @loadingContainer = new Layer
120 | name: '.'
121 | parent: @
122 | x: Align.center()
123 | y: Align.center()
124 | size: 48
125 | backgroundColor: 'rgba(0,0,0,.64)'
126 | borderRadius: 8
127 | opacity: .8
128 | backgroundBlur: 30
129 |
130 | @iconLayer = new Icon
131 | parent: @loadingContainer
132 | height: 32
133 | width: 32
134 | point: Align.center()
135 | style:
136 | lineHeight: 1
137 | color: white
138 | icon: "loading"
139 |
140 | anim = new Animation @iconLayer,
141 | rotation: 360
142 | options:
143 | curve: "linear"
144 | looping: true
145 |
146 | anim.start()
147 |
148 |
149 | # header
150 |
151 | if @chrome
152 | # don't show safari bar when opening this project on mobile web
153 | # ... but this might require a lot of app.header?.etc
154 | if @chrome is 'safari' and Utils.isSafari()
155 | @chrome = null
156 |
157 | @header = new Header
158 | app: @
159 | safari: @chrome is 'safari'
160 | title: options.title
161 |
162 | if @chrome is 'safari'
163 | @footer = new Footer
164 | app: @
165 |
166 | @onSwipeUpEnd =>
167 | return unless @current.isMoving
168 |
169 | @header._collapse()
170 | @footer._collapse()
171 |
172 | @onSwipeDownEnd =>
173 | return unless @current.isMoving
174 |
175 | @header._expand()
176 | @footer._expand()
177 |
178 | @header?.on "change:height", @_setWindowFrame
179 | @footer?.on "change:height", @_setWindowFrame
180 |
181 | @_setWindowFrame()
182 |
183 | # definitions
184 | Utils.define @, 'focused', null, @_showFocused, _.isObject, "App.focused must be an html element."
185 | Utils.define @, 'loading', false, @_showLoading, _.isBoolean, "App.loading must be a boolean (true or false)."
186 |
187 | # when transition starts, update the header
188 | @onTransitionStart @_updateHeader
189 |
190 | # when transition ends, reset the previous view
191 | @onTransitionEnd @_updatePrevious
192 |
193 | Screen.on Events.EdgeSwipeLeftEnd, @showPrevious
194 |
195 | # ---------------
196 | # Private Methods
197 |
198 | _showFocused: (el) =>
199 | # possibly... an app state dealing with an on-screen keyboard
200 | return
201 |
202 | _updateHeader: (prev, next, direction) =>
203 | # header changes
204 | return if not @header
205 |
206 | hasPrevious = prev? and next isnt @_stack[0]?.layer
207 |
208 | # safari changes
209 | if @header.safari
210 | @footer.hasPrevious = hasPrevious
211 | return
212 |
213 | # ios changes
214 | @header.backIcon.visible = hasPrevious
215 | @header.backText.visible = hasPrevious
216 |
217 | if next.title
218 | @header.updateTitle(next.title)
219 |
220 | # Update the next View before transitioning
221 | _updateNext: (prev, next) =>
222 | return if not next
223 |
224 | next._loadView(@, next, prev)
225 |
226 |
227 | # Reset the previous View after transitioning
228 | _updatePrevious: (prev, next, direction) =>
229 | return unless prev? and prev instanceof View
230 |
231 | prev.sendToBack()
232 | prev._unloadView(@, next, prev, direction)
233 |
234 | _safariTransition: (nav, layerA, layerB, overlay) =>
235 | options = {time: 0.01}
236 | transition =
237 | layerA:
238 | show: {options: options, x: Align.center(), brightness: 100, y: @windowFrame.y}
239 | hide: {options: options, x: Align.center(), brightness: 101, y: @windowFrame.y}
240 | layerB:
241 | show: {options: options, x: Align.center(), brightness: 100, y: @windowFrame.y}
242 | hide: {options: options, x: Align.center(), brightness: 101, y: @windowFrame.y}
243 |
244 | _iosTransition: (nav, layerA, layerB, overlay) =>
245 | options = {curve: "spring(300, 35, 0)"}
246 | transition =
247 | layerA:
248 | show: {options: options, x: Align.center(), y: @windowFrame.y}
249 | hide: {options: options, x: 0 - layerA?.width / 2, y: @windowFrame.y}
250 | layerB:
251 | show: {options: options, x: Align.center(), y: @windowFrame.y}
252 | hide: {options: options, x: @width + layerB.width / 2, y: @windowFrame.y}
253 |
254 | _defaultTransition: (nav, layerA, layerB, overlay) =>
255 | options = {curve: "spring(300, 35, 0)"}
256 | transition =
257 | layerA:
258 | show: {options: options, x: Align.center(), y: @windowFrame.y}
259 | hide: {options: options, x: 0 - layerA?.width / 2, y: @windowFrame.y}
260 | layerB:
261 | show: {options: options, x: Align.center(), y: @windowFrame.y}
262 | hide: {options: options, x: @width + layerB.width / 2, y: @windowFrame.y}
263 |
264 | _setWindowFrame: =>
265 | @_windowFrame = {
266 | y: (@header?.height ? 0)
267 | x: @x
268 | maxX: @maxX
269 | maxY: @height - (@footer?.height ? 0)
270 | height: @height - (@footer?.height ? 0) - (@header?.height - 0)
271 | width: @width
272 | size: {
273 | height: @height - (@footer?.height ? 0) - (@header?.height - 0)
274 | width: @width
275 | }
276 | }
277 |
278 | @emit "change:windowFrame", @_windowFrame, @
279 |
280 | _showLoading: (bool) =>
281 | if bool
282 | @focused?.blur()
283 | @loadingLayer.visible = true
284 | @loadingLayer.bringToFront()
285 |
286 | # show safari loading
287 | if @chrome is "safari"
288 | @header._expand()
289 | @footer._expand()
290 | @header._showLoading(true)
291 | return
292 |
293 | # show ios loading
294 | return
295 |
296 | @loadingLayer.visible = false
297 | @loadingLayer.sendToBack()
298 |
299 | # show safari loading ended
300 | if @chrome is "safari"
301 | @header._expand()
302 | @footer._expand()
303 | @header._showLoading(false)
304 | return
305 |
306 | # ---------------
307 | # Public Methods
308 |
309 | # show next view
310 | showNext: (layer, loadingTime, options={}) ->
311 | @_initial ?= layer
312 |
313 | if @chrome is "safari" then loadingTime ?= _.random(.5, .75)
314 |
315 | @_updateNext(@current, layer)
316 |
317 | # if loading time specified...
318 | if loadingTime?
319 | @loading = true
320 | Utils.delay loadingTime, =>
321 | @loading = false
322 | @transition(layer, @_platformTransition, options)
323 | return
324 |
325 | # otherwise, show next
326 | @focused?.blur()
327 | @transition(layer, @_platformTransition, options)
328 |
329 |
330 | showPrevious: (options={}) =>
331 | return unless @previous
332 | return if @isTransitioning
333 |
334 | # Maybe people (Jorn, Steve for sure) pass in a layer accidentally
335 | options = {} if options instanceof(Framer._Layer)
336 | options = _.defaults({}, options, {count: 1, animate: true})
337 |
338 | if options.count > 1
339 | count = options.count
340 | @showPrevious(animate: false, count: 1) for n in [2..count]
341 |
342 | previous = @_stack.pop()
343 | current = @current
344 | try current._loadView()
345 |
346 | if @chrome is "safari"
347 | @loading = true
348 | loadingTime = _.random(.3, .75)
349 | Utils.delay loadingTime, =>
350 | @loading = false
351 | @_runTransition(previous?.transition, "back", options.animate, current, previous.layer)
352 | return
353 |
354 | @focused?.blur()
355 | @_runTransition(previous?.transition, "back", options.animate, current, previous.layer)
356 |
357 |
358 | @define "windowFrame",
359 | get: -> return @_windowFrame
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/myTheme-components/Circle.coffee:
--------------------------------------------------------------------------------
1 | class exports.Circle extends Layer
2 | constructor: (options = {}) ->
3 | theme = Theme.theme
4 |
5 | _.defaults options,
6 | name: 'Circle'
7 | width: 100
8 | height: 100
9 | borderRadius: 50
10 |
11 | super options
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/myTheme-components/fonts/MuktaMahee-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/example_inProgress.framer/modules/myTheme-components/fonts/MuktaMahee-Regular.ttf
--------------------------------------------------------------------------------
/example_inProgress.framer/modules/myTheme.coffee:
--------------------------------------------------------------------------------
1 | framework = require "framework"
2 | theme = framework.theme.theme
3 |
4 | # -----------------
5 | # myTheme - A Custom Theme for Framework
6 |
7 | # This is an example "theme" for Framework. With themes, you can
8 | # add new components and set style over-rides without modifying
9 | # the base files, so that you can update Framework without losing
10 | # your changes.
11 |
12 |
13 |
14 | # -----------------
15 | # Components
16 |
17 | # To bring in your own components, require each of them
18 | # and place the component's name (as a string) into
19 | # the componentNames array.
20 |
21 | { Circle } = require 'myTheme-components/Circle'
22 | # { Square } = require 'myTheme-components/Square'
23 |
24 | componentNames = [
25 | 'Circle'
26 | # 'Square'
27 | ]
28 |
29 | # -----------------
30 | # Fonts
31 |
32 | Utils.insertCSS("""
33 | @font-face {
34 | font-family: 'MuktaMahee';
35 | font-weight: 200;
36 | src: url('modules/myTheme-components/fonts/MuktaMahee-Regular.ttf');
37 | }
38 | """)
39 |
40 |
41 | # -----------------
42 | # Colors
43 |
44 | # You can make changes to the default colors here.
45 | # The colors you make will each get the "shade" treatment,
46 | # so you'll be able to use colorName10, colorName20, etc as
47 | # global variables. You can (and should!) use these colors
48 | # in your custom components.
49 |
50 | # You can change the value of the default colors (commented out
51 | # in the list below), but you can't remove them.
52 |
53 | shadeColors =
54 | # black: '#252729'
55 | # grey: '#c1c1c2'
56 | # yellow: '#ffd16d'
57 | # white: '#FFF'
58 | # red: '#d96161'
59 | # beige: '#eae5e0'
60 | # blue: '#5399c3'
61 | # green: '#599FA0'
62 |
63 | # You can also add colors without giving them the full shade treatment.
64 | # These colors will still be available as global variables in your project,
65 | # but they won't have shade50, shade40, etc.
66 |
67 | soloColors =
68 | orange: "#dcaa74"
69 | green: "#dcaa74"
70 | blue: "#547190"
71 |
72 |
73 | # don't change this line -----------------------------
74 | framework.colors.updateColors(shadeColors, soloColors)
75 | # ----------------------------------------------------
76 |
77 |
78 | # -----------------
79 | # Theme
80 |
81 | # You can make changes to the default theme here.
82 | # Check components/Theme for the defaults - but don't
83 | # change those defaults!
84 |
85 | themeStyles =
86 | # ----------
87 | # Typography
88 | #
89 | typography:
90 | Serif:
91 | fontFamily: 'Times New Roman'
92 | Sans:
93 | fontFamily: 'Mukta Mahee'
94 |
95 |
96 |
97 | # -----------------
98 | # Blood-Slick machinery
99 | #
100 | # Here's where your components get processed.
101 | # Don't change this part!
102 |
103 | framework.theme.updateTheme(themeStyles)
104 | framework.typography.updateTypography()
105 |
106 |
107 | componentNames.forEach (componentName) =>
108 | window[componentName] = class FrameworkComponent extends eval(componentName)
109 | constructor: (options = {}) ->
110 | @app = framework.app
111 | super options
112 |
113 |
--------------------------------------------------------------------------------
/icon_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/icon_small.png
--------------------------------------------------------------------------------
/img/constrain_bottom.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_bottom.gif
--------------------------------------------------------------------------------
/img/constrain_height.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_height.gif
--------------------------------------------------------------------------------
/img/constrain_height_aspectratio.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_height_aspectratio.gif
--------------------------------------------------------------------------------
/img/constrain_height_aspectratio_t.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_height_aspectratio_t.gif
--------------------------------------------------------------------------------
/img/constrain_left.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_left.gif
--------------------------------------------------------------------------------
/img/constrain_left_aspectratio.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_left_aspectratio.gif
--------------------------------------------------------------------------------
/img/constrain_right.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_right.gif
--------------------------------------------------------------------------------
/img/constrain_top.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_top.gif
--------------------------------------------------------------------------------
/img/constrain_width.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_width.gif
--------------------------------------------------------------------------------
/img/constrain_width_top.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/steveruizok/framer-moreutils/cf29f9189e645703f22f699ef9f1da4d65623e40/img/constrain_width_top.gif
--------------------------------------------------------------------------------
/module.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "moreutils",
3 | "description": "Expand Framer's Utils with some handy helper functions.",
4 | "author": "Steve Ruiz",
5 |
6 | "require": "require 'moreutils'",
7 | "install": "moreutils.coffee",
8 | "example": "example.coffee",
9 |
10 | "thumb": "icon_small.png"
11 | }
12 |
--------------------------------------------------------------------------------