Repository: tylergaw/day-player
Branch: develop
Commit: 357566230d3f
Files: 26
Total size: 29.6 KB
Directory structure:
gitextract_gh6j5y9l/
├── .eslintrc
├── .gitignore
├── .travis.yml
├── LICENSE.md
├── Makefile
├── README.md
├── manifest.json
├── package.json
├── resources/
│ ├── fillmurray.icns
│ ├── lorempixel.icns
│ ├── placecage.icns
│ ├── placeholdit.icns
│ ├── placekitten.icns
│ └── unsplashit.icns
├── scripts/
│ └── release.js
└── src/
├── components/
│ ├── Alert.js
│ ├── Label.js
│ ├── PopUpButton.js
│ └── TextField.js
├── handlers/
│ ├── fillMurray.js
│ ├── placeCage.js
│ ├── placeHoldIt.js
│ ├── placeKitten.js
│ └── unsplashIt.js
├── index.cocoascript
└── utils.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintrc
================================================
{
"ecmaFeatures": {
"modules": true,
"experimentalObjectRestSpread": true
},
"rules": {
"accessor-pairs": 0,
"comma-dangle": [1, "never"],
"comma-spacing": [1, {"before": false, "after": true}],
"comma-style": [2, "last"],
"consistent-return": 2,
"dot-location": [
2,
"property"
],
"dot-notation": 2,
"eol-last": 2,
"indent": [
2,
2,
{
"SwitchCase": 1
}
],
"keyword-spacing": 2,
"no-bitwise": 0,
"no-console": 2,
"no-const-assign": 2,
"no-debugger": 2,
"no-empty": 2,
'no-missing-import': 0,
"no-multi-spaces": 2,
"no-shadow": 0,
"no-undef": 2,
"no-unreachable": 1,
"no-unused-expressions": 2,
"no-unused-vars": [
2,
{
"args": "none",
"varsIgnorePattern": "_",
"argsIgnorePattern": "_"
}
],
"object-curly-spacing": [1, "never"],
"quotes": [
1,
"single",
"avoid-escape"
],
"semi": 2,
"space-before-blocks": 2,
"space-in-parens": [1, "never"],
"strict": [
2,
"never"
]
},
"env": {
"es6": true
},
"globals": {
Alert: true,
Label: true,
PopUpButton: true,
TextField: true,
createConfirmHandler: true,
createPluginHandler: true,
lowLevelSetImage: true,
NSAlert: true,
NSView: true,
NSMakeRect: true,
NSImage: true,
NSURL: true,
MSImageData: true,
NSTextField: true,
NSPopUpButton: true,
log: true
}
}
================================================
FILE: .gitignore
================================================
npm-debug.log
node_modules/
Day Player.sketchplugin
DayPlayer.zip
================================================
FILE: .travis.yml
================================================
language: node_js
node_js:
- 5.12.0
sudo: false
cache:
directories:
- /home/travis/.local
- node_modules
- $(npm config get cache)
before_install:
- npm config set progress false
- npm config set spin false
install:
- pip install --user -U awscli
- npm install
script:
- make lint
deploy:
- provider: script
script: make publish
on:
tags: true
env:
global:
- AWS_ACCESS_KEY_ID=AKIAIRMRYU635FO4D26A
- secure: PqKc8FFSOiIQvEMkQtPv9b55NwdMreHEF4njCnnk/pcBgUIep8Ew2JYmdp/KuSx1gyZBRys0hJqSTJ6FVZrCkI7pHD3bkKrNGq807c5yVFHtTzTUoQZ62zYEC/fnsbvKdd6sGtznABB1boiuiV1Crj0v2gtkA/kUJ431XUFqBw4=
================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)
Copyright (c) 2016 Tyler Gaw
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: Makefile
================================================
PLUGIN_PATH := ~/Library/Application\ Support/com.bohemiancoding.sketch3/Plugins/
PLUGIN_DIR := Day\ Player.sketchplugin
PLUGIN_NAME := Day Player
ZIP_NAME := DayPlayer.zip
S3_BUCKET := s3://day-player
SRC_DIR := ./src
RESOURCES_DIR := ./resources
LICENSE := LICENSE.md
MANIFEST := manifest.json
clean:
@rm -rf $(PLUGIN_DIR)
@rm -f $(ZIP_NAME)
@rm -rf $(PLUGIN_PATH)$(PLUGIN_DIR)
build:
@make clean
@mkdir $(PLUGIN_DIR)
@mkdir $(PLUGIN_DIR)/Contents
@cp $(LICENSE) $(PLUGIN_DIR)/Contents/$(LICENSE)
@cp -r $(RESOURCES_DIR) $(PLUGIN_DIR)/Contents/Resources
@cp -r $(SRC_DIR) $(PLUGIN_DIR)/Contents/Sketch
@cp -r $(MANIFEST) $(PLUGIN_DIR)/Contents/Sketch/$(MANIFEST)
install:
@make clean
@echo "Installing $(PLUGIN_NAME)..."
@make build
@mv $(PLUGIN_DIR) $(PLUGIN_PATH)
@echo "$(PLUGIN_NAME) installed"
package:
make build
@zip -rm $(ZIP_NAME) $(PLUGIN_DIR)
@echo "$(ZIP_NAME) created"
changed:
@echo "Changes detected..."
@make install
lint:
@echo "Linting with eslint..."
@./node_modules/.bin/eslint ./src/**/*.js
watch:
@echo "Watching src directory for changes..."
@./node_modules/.bin/watch 'make changed' ./src ./resources
release:
@node scripts/release.js
publish:
@make package
@aws s3 cp $(ZIP_NAME) $(S3_BUCKET)/releases/DayPlayer-$(TRAVIS_TAG).zip
================================================
FILE: README.md
================================================
[ Download the latest version (3.0.0)](http://day-player.s3-website-us-east-1.amazonaws.com/releases/DayPlayer-3.0.0.zip)
## Day Player [](https://travis-ci.org/tylergaw/day-player)
A Sketch Plugin for creating placeholder images from online services.
## Installation
- [ Download the latest version (3.0.0)](http://day-player.s3-website-us-east-1.amazonaws.com/releases/DayPlayer-3.0.0.zip)
- Unzip the file
- Double-click Day Player.sketchplugin to install
## What Does It Do?
It allows you to insert customized placeholder images into any Sketch document from a number
of different placeholder image services:
- [unsplash.it](http://unsplash.it/)
- [placehold.it](http://placehold.it/)
- [fillmurray.com](http://www.fillmurray.com/)
- [placecage.com](http://www.placecage.com/)
- [placekitten.com](http://placekitten.com/)
## How to use it
- Open a new or existing Sketch document
- Plugins > Day Player > Service...
- Update the options to your liking, OK/Enter
- The image is created on the canvas

### Appending images to an Artboard or Group
- Open a new or existing Sketch document
- Select the Artboard or Group
- Plugins > Day Player > Service...
- Update the options to your liking, OK/Enter
- The image is created within the Artboard or Group
- Image will be placed in the top left corner of the Artboard or Group
**Artboard:**

**Group:**

### Creating images with dimensions and position of existing Layers
- Open a new or existing Sketch document
- Select the desired Layer
- Plugins > Day Player > Service...
- Update the options to your liking, OK/Enter
- The image is created in the parent group of the selected layer
- Image will inherit the x, y, width, and height of the selected layer

### Advanced Service Options
All services offer width, height, and black & white / color options. Unsplash.it and Placehold.it offer further options to customize the placeholder images.
**Unsplash.it:**

**Placehold.it:**

-------
## Contributing to this project
As with most open source projects, pull requests for bug fixes, and new functionality are always welcome.
Prerequisites
- Node `5.x.x`+
Fork this repo and clone a local copy of your fork.
Install dependencies:
```
npm install
```
Create necessary application bundle from source by running:
```
make install
```
Watch the `src` and `resources` directories and recompile when changes are made by running:
```
make watch
```
`make install` and `make watch` will copy the application bundle to the default Sketch plugins location `~/Library/Application Support/com.bohemiancoding.sketch3/Plugins/` as `Day Player.sketchplugin`.
See the `Makefile` for further details on the build process.
================================================
FILE: manifest.json
================================================
{
"name": "Day Player",
"description": "A Plugin for creating images from placeholder services.",
"author": "Tyler Gaw",
"homepage": "https://github.com/tylergaw/day-player",
"version": "3.0.0",
"identifier": "com.sketchapp.tylergaw.day-player",
"compatibleVersion": 41,
"commands" : [
{
"name": "Unsplash.it",
"script": "index.cocoascript",
"handler": "unsplashIt",
"identifier": "unsplash-it"
},
{
"name": "Fill Murray",
"script": "index.cocoascript",
"handler": "fillMurray",
"identifier": "fill-murray"
},
{
"name": "Place Cage",
"script": "index.cocoascript",
"handler": "placeCage",
"identifier": "place-cage"
},
{
"name": "Placehold.it",
"script": "index.cocoascript",
"handler": "placeHoldIt",
"identifier": "place-hold-it"
},
{
"name": "Placekitten",
"script": "index.cocoascript",
"handler": "placeKitten",
"identifier": "place-kitten"
}
],
"menu": {
"title": "Day Player",
"items": [
"unsplash-it",
"place-hold-it",
"fill-murray",
"place-cage",
"place-kitten"
]
}
}
================================================
FILE: package.json
================================================
{
"name": "day-player-plugin-sketchapp",
"version": "3.0.0",
"description": "A Sketch Plugin for creating placeholder images",
"repository": {
"type": "git",
"url": "git+https://github.com/tylergaw/day-player.git"
},
"scripts": {
"test": "make lint"
},
"keywords": [
"sketch",
"placeholder",
"images"
],
"author": "Tyler Gaw",
"license": "MIT",
"bugs": {
"url": "https://github.com/tylergaw/day-player/issues"
},
"homepage": "https://github.com/tylergaw/day-player#readme",
"devDependencies": {
"eslint": "3.8.0",
"pre-commit": "1.1.3",
"prompt": "1.0.0",
"watch": "1.0.1"
}
}
================================================
FILE: scripts/release.js
================================================
/* eslint-env node */
/* eslint-disable strict, no-console */
'use strict';
const version = require('../package.json').version;
const prompt = require('prompt');
const exec = require('child_process').exec;
const dryRun = process.env.DRY_RUN || false;
const schema = {
properties: {
confirmation: {
required: true,
pattern: /^(y|n|yes|no)+$/ig,
description: `You are about to release version ${version}, is that OK? (yes|no)`
}
}
};
const pushTag = tag => {
const cmd = `git push origin ${tag}`;
exec(cmd, (error, stdout, stderr) => {
console.log('Tag pushed to origin', tag);
if (error !== null) {
console.log(stderr);
}
});
};
const createTag = n => {
const cmd = `git tag -a ${n} -m "Releasing version: ${n}"`;
if (dryRun) {
console.log('Pretending to create new tag', n);
} else {
exec(cmd, (error, stdout, stderr) => {
console.log('New git tag created', n);
pushTag(n);
if (error !== null) {
console.log(stderr);
}
});
}
};
prompt.start();
prompt.get(schema, (err, result) => {
if (err) {
throw new Error(err);
}
const res = result.confirmation.toLowerCase();
if (res === 'y' || res === 'yes') {
createTag(version);
} else {
console.log('Release aborted');
process.exit(0);
}
return true;
});
================================================
FILE: src/components/Alert.js
================================================
/**
* Alert A facade for NSAlert. Includes a number of convenience methods and a
* chainable interface.
*
* @param {Object} props Options for building the Alert and handling user input
* @return {Object} alert
*/
// eslint-disable-next-line no-unused-vars
const Alert = function(props) {
// eslint-disable-next-line no-unused-vars
const propTypes = {
message: String,
info: String,
iconUrl: String,
onConfirm: Function,
onCancel: Function
};
const alert = {
views: [],
el: NSAlert.alloc().init(),
is: function(type) {
return type === 'alert';
}
};
const buttons = props.buttons || ['OK', 'Cancel'];
alert.layout = function() {
var containerHeight = 1;
const container = NSView.alloc().initWithFrame(
NSMakeRect(25, 100, 350, containerHeight)
);
alert.views.forEach(function(view) {
const el = view.el;
const bounds = el.bounds();
bounds.origin.y = containerHeight;
containerHeight += bounds.size.height + 8;
el.setFrame(bounds);
container.addSubview(el);
});
const containerFrame = container.frame();
containerFrame.size.height = containerHeight;
container.setFrame(containerFrame);
alert.el.setAccessoryView(container);
};
alert.runModal = function() {
// Call layout before running opening the modal to account for any
// dynamic layout
alert.layout();
const onConfirm = props.onConfirm || function() {};
const onCancel = props.onCancel || function() {};
const res = parseInt(alert.el.runModal(), 10);
const resHandler = (res === 1000) ? onConfirm : onCancel;
resHandler(alert);
return alert;
};
/**
* append Adds an element or elements to the Alert
*
* @param {Object|Array} newEl Either a single element or an array of elements.
* @return {Object} alert
*/
alert.append = function(newEl) {
const newViews = Array.isArray(newEl) ? newEl.reverse() : [newEl];
newViews.forEach(function(el) {
alert.views.push(el);
});
return alert;
};
if (buttons.length) {
for (var i = 0; i < buttons.length; i += 1) {
alert.el.addButtonWithTitle(buttons[i]);
}
}
if (props.message) {
alert.el.setMessageText(props.message);
}
if (props.info) {
alert.el.setInformativeText(props.info);
}
if (props.iconUrl) {
alert.el.setIcon(NSImage.alloc().initByReferencingURL(props.iconUrl));
}
return alert;
};
================================================
FILE: src/components/Label.js
================================================
/**
* Label A facade for NSTextField without any editable styling. Includes a
* number of convenience methods and a chainable interface.
*
* @param {Object} props Options for building the Label
* @return {Object} label
*/
// eslint-disable-next-line no-unused-vars
const Label = function(props) {
// eslint-disable-next-line no-unused-vars
const propTypes = {
frame: Object,
value: String
};
/**
* createLabel Internal method for creating new NSTextField
*
* @return {Object} NSTextField
*/
const createLabel = function(frame) {
const f = frame || {
x: 4,
y: 100,
width: 350,
height: 16
};
const textField = NSTextField.alloc().initWithFrame(
NSMakeRect(f.x, f.y, f.width, f.height));
textField.setDrawsBackground(false);
textField.setEditable(false);
textField.setBezeled(false);
textField.setSelectable(true);
return textField;
};
const label = {
el: createLabel(props.frame),
is: function(type) {
return type === 'label';
}
};
/**
* setStringValue Sets the string value for the label.
*
* @param {String} value
* @return {Object} label
*/
label.setStringValue = function(value) {
label.el.setStringValue(value);
return label;
};
if (props.value) {
label.setStringValue(props.value);
}
return label;
};
================================================
FILE: src/components/PopUpButton.js
================================================
/**
* PopUpButton A facade for NSPopUpButton. Includes a number of convenience
* methods and a chainable interface.
*
* @param {Object} props Options for building the PopUpButton
* @return {Object} popUpButton
*/
// eslint-disable-next-line no-unused-vars
const PopUpButton = function(props) {
// eslint-disable-next-line no-unused-vars
const propTypes = {
items: Array
};
const popUpButton = {
// NOTE: The documented signature is initWithFrame:pullsDown: but that
// is undefined here. Think that's maybe a difference in CocoaScript?
el: NSPopUpButton.alloc().initWithFrame(
NSMakeRect(25, 100, 350, 28)
),
is: function(type) {
return type === 'select';
},
name: props.name || '',
val: function() {
return this.el.titleOfSelectedItem();
}
};
if (props.items) {
popUpButton.el.addItemsWithTitles(props.items);
}
return popUpButton;
};
================================================
FILE: src/components/TextField.js
================================================
/**
* TextField A facade for NSTextField. Includes a number of convenience
* methods and a chainable interface.
*
* @param {Object} props Options for building the TextField
* @return {Object} textField
*/
// eslint-disable-next-line no-unused-vars
const TextField = function(props) {
// eslint-disable-next-line no-unused-vars
const propTypes = {
frame: Object,
value: String
};
/**
* createTextField Internal method for creating new NSTextField
*
* @return {Object} NSTextField
*/
const createTextField = function(frame) {
const f = frame || {
x: 25,
y: 100,
width: 350,
height: 24
};
return NSTextField.alloc().initWithFrame(
NSMakeRect(f.x, f.y, f.width, f.height));
};
const textField = {
el: createTextField(props.frame),
is: function(type) {
return type === 'input';
},
name: props.name || '',
val: function() {
return this.el.stringValue();
}
};
/**
* setStringValue Sets the string value for the textField.
*
* @param {String} value
* @return {Object} textField
*/
textField.setStringValue = function(value) {
textField.el.setStringValue(value);
return textField;
};
if (props.value) {
textField.setStringValue(props.value);
}
return textField;
};
================================================
FILE: src/handlers/fillMurray.js
================================================
// eslint-disable-next-line no-unused-vars
const fillMurray = createPluginHandler(function(props) {
const GREY_TITLE = 'Black & white';
const initOpts = props.newImgFrame;
const elements = [
new Label({
value: 'Width:'
}),
new TextField({
name: 'width',
value: initOpts.width
}),
new Label({
value: 'Height:'
}),
new TextField({
name: 'height',
value: initOpts.height
}),
new Label({
value: 'Type:'
}),
new PopUpButton({
name: 'type',
items: ['Color', GREY_TITLE]
})
];
const onConfirm = createConfirmHandler({
api: props.api,
group: props.target.group,
host: 'fillmurray.com',
initOpts: initOpts,
urlBuilder: function(parts) {
const base = `${parts.protocol}${parts.host}`;
// Cast as a string because the value coming back is an object
const type = (String(parts.allParts.type) === GREY_TITLE) ? '/g' : '';
return `${base}${type}/${parts.width}/${parts.height}`;
}
});
new Alert({
message: 'Fill Murray Options',
info: 'Customize the wonderful Bill Murray image that will be created.',
iconUrl: props.api.resourceNamed('fillmurray.icns'),
onConfirm: onConfirm
}).append(elements).runModal();
});
================================================
FILE: src/handlers/placeCage.js
================================================
// eslint-disable-next-line no-unused-vars
const placeCage = createPluginHandler(function(props) {
const GREY_TITLE = 'Black & white';
const initOpts = props.newImgFrame;
const elements = [
new Label({
value: 'Width:'
}),
new TextField({
name: 'width',
value: initOpts.width
}),
new Label({
value: 'Height:'
}),
new TextField({
name: 'height',
value: initOpts.height
}),
new Label({
value: 'Type:'
}),
new PopUpButton({
name: 'type',
items: ['Color', GREY_TITLE]
})
];
const onConfirm = createConfirmHandler({
api: props.api,
group: props.target.group,
host: 'placecage.com',
initOpts: initOpts,
urlBuilder: function(parts) {
const base = `${parts.protocol}${parts.host}`;
// Cast as a string because the value coming back is an object
const type = (String(parts.allParts.type) === GREY_TITLE) ? '/g' : '';
return `${base}${type}/${parts.width}/${parts.height}`;
}
});
new Alert({
message: 'Place Cage Options',
info: 'Customize the image of the best actor of all time that will be created.',
iconUrl: props.api.resourceNamed('placecage.icns'),
onConfirm: onConfirm
}).append(elements).runModal();
});
================================================
FILE: src/handlers/placeHoldIt.js
================================================
// eslint-disable-next-line no-unused-vars
const placeHoldIt = createPluginHandler(function(props) {
const initOpts = props.newImgFrame;
const elements = [
new Label({
value: 'Width:'
}),
new TextField({
name: 'width',
value: initOpts.width
}),
new Label({
value: 'Height:'
}),
new TextField({
name: 'height',
value: initOpts.height
}),
new Label({
value: 'Text:'
}),
new TextField({
name: 'text',
value: 'placeholder'
}),
new Label({
value: 'Background color:'
}),
new TextField({
name: 'bgColor',
value: 'aeaeae'
}),
new Label({
value: 'Text color:'
}),
new TextField({
name: 'color',
value: '949494'
})
];
const onConfirm = createConfirmHandler({
api: props.api,
group: props.target.group,
host: 'placehold.it',
initOpts: initOpts,
urlBuilder: function(parts) {
var url = `${parts.protocol}${parts.host}/${parts.width}x${parts.height}/${parts.allParts.bgColor}/${parts.allParts.color}`;
const text = parts.allParts.text;
if (text.length) {
url += `?text=${encodeURIComponent(text)}`;
}
return url;
}
});
new Alert({
message: 'Placehold.it Options',
info: 'Customize the image that will be created.',
iconUrl: props.api.resourceNamed('placeholdit.icns'),
onConfirm: onConfirm
}).append(elements).runModal();
});
================================================
FILE: src/handlers/placeKitten.js
================================================
// eslint-disable-next-line no-unused-vars
const placeKitten = createPluginHandler(function(props) {
const GREY_TITLE = 'Black & white';
const initOpts = props.newImgFrame;
const elements = [
new Label({
value: 'Width:'
}),
new TextField({
name: 'width',
value: initOpts.width
}),
new Label({
value: 'Height:'
}),
new TextField({
name: 'height',
value: initOpts.height
}),
new Label({
value: 'Type:'
}),
new PopUpButton({
name: 'type',
items: ['Color', GREY_TITLE]
})
];
const onConfirm = createConfirmHandler({
api: props.api,
group: props.target.group,
host: 'placekitten.com',
initOpts: initOpts,
urlBuilder: function(parts) {
const base = `${parts.protocol}${parts.host}`;
// Cast as a string because the value coming back is an object
const type = (String(parts.allParts.type) === GREY_TITLE) ? '/g' : '';
return `${base}${type}/${parts.width}/${parts.height}`;
}
});
new Alert({
message: 'Place Kitten Options',
info: 'Customize the kewl kitten image that will be created.',
iconUrl: props.api.resourceNamed('placekitten.icns'),
onConfirm: onConfirm
}).append(elements).runModal();
});
================================================
FILE: src/handlers/unsplashIt.js
================================================
// eslint-disable-next-line no-unused-vars
const unsplashIt = createPluginHandler(function(props) {
const GREY_TITLE = 'Black & white';
const BLUR_TITLE = 'Blurry';
const initOpts = props.newImgFrame;
const elements = [
new Label({
value: 'Width:'
}),
new TextField({
name: 'width',
value: initOpts.width
}),
new Label({
value: 'Height:'
}),
new TextField({
name: 'height',
value: initOpts.height
}),
new Label({
value: 'Type:'
}),
new PopUpButton({
name: 'type',
items: ['Color', GREY_TITLE]
}),
new Label({
value: 'Sharpness:'
}),
new PopUpButton({
name: 'blur',
items: ['Focused', BLUR_TITLE]
})
];
const onConfirm = createConfirmHandler({
api: props.api,
group: props.target.group,
host: 'unsplash.it',
initOpts: initOpts,
urlBuilder: function(parts) {
const base = `${parts.protocol}${parts.host}`;
// Cast as a string because the value coming back is an object
const type = (String(parts.allParts.type) === GREY_TITLE) ? '/g' : '';
const blur = (String(parts.allParts.blur) === BLUR_TITLE) ? '&blur' : '';
return `${base}${type}/${parts.width}/${parts.height}?random${blur}`;
}
});
new Alert({
message: 'Unsplash.it Options',
info: 'Customize the image that will be created.',
iconUrl: props.api.resourceNamed('unsplashit.icns'),
onConfirm: onConfirm
}).append(elements).runModal();
});
================================================
FILE: src/index.cocoascript
================================================
@import './utils.js';
@import './components/Label.js';
@import './components/TextField.js';
@import './components/PopUpButton.js';
@import './components/Alert.js';
@import './handlers/fillMurray.js';
@import './handlers/placeCage.js';
@import './handlers/placeHoldIt.js';
@import './handlers/placeKitten.js';
@import './handlers/unsplashIt.js';
================================================
FILE: src/utils.js
================================================
/**
* createPluginHandler - Creates a handler function that takes the context
* parameter required by Sketch plugins and enhances it with a number of
* helpful properties.
*
* @param {Function} func
* @return {Function} A function suitable to be used as a Plugin handler
*/
// eslint-disable-next-line no-unused-vars
const createPluginHandler = function(func) {
return function(context) {
const api = context.api();
const document = api.selectedDocument;
const selection = document.selectedLayers;
const target = (selection.isEmpty) ? {group: document.selectedPage} :
getTargetLayer(selection, context);
const newImgFrame = (target.frame) ? {
x: target.frame.x,
y: target.frame.y,
width: target.frame.width,
height: target.frame.height
} : {
x: 0,
y: 0,
width: 400,
height: 300
};
const props = {
api: api,
document: document,
page: document.selectedPage,
selection: selection,
target: target,
newImgFrame: newImgFrame
};
func(props);
};
};
/**
* createConfirmHandler - Creates a standard Day Player alert confirmation handler
* function that takes a single param, the Alert being used at the time.
*
* @param {Object} props Configuration for the handler
* @param {Function} func Optional function to run after all standard bits
* @return {Function} A function suitable to be used as an Alert.onConfirm
*/
// eslint-disable-next-line no-unused-vars
const createConfirmHandler = function(props, func) {
const urlBuilder = props.urlBuilder || function(parts) {
return `${parts.protocol}${parts.host}/${parts.width}/${parts.height}`;
};
return function(alert) {
const userChosenOptions = alert.views.filter(function(view) {
return view.is('input') || view.is('select');
}).reduce(function(obj, view, i) {
obj[view.name] = view.val();
return obj;
}, {});
const opts = Object.assign({}, props.initOpts, userChosenOptions);
const sizeDisplay = `${opts.width}x${opts.height}`;
props.api.message(`Creating a ${sizeDisplay}px image from ${props.host}...`);
const url = urlBuilder({
protocol: 'https://',
host: props.host,
width: opts.width,
height: opts.height,
allParts: opts
});
const img = props.group.newImage({
frame: new props.api.Rectangle(opts.x, opts.y, opts.width, opts.height),
name: `${props.host}-${sizeDisplay}`
});
img.imageURL = NSURL.URLWithString(url);
};
};
/**
* Determine if appending image to an artboard, group, layer, or none.
*
* @param {Selection} selection The current Selection
* @param {Object} context The current context
* @return {Object} target The selected layers
*/
const getTargetLayer = function(selection, context) {
var layers = [];
selection.iterate(function(layer) {
layers.push(layer);
});
// TODO: Currently we'll only create an image for a single layer selected. We
// only grab the first one off the list of selections. In the future, we should
// create an image for each selection.
const firstLayer = layers[0];
var target = {
selection: selection,
frame: (firstLayer.isShape) ? firstLayer.frame : null
};
if (firstLayer.isGroup) {
target.group = firstLayer;
} else {
// FIXME: If the user has selected layer(s) that do not count as a group;
// (shape, text, line, etc) we need to set the target.group to the parent
// group of the selected layer(s).
// The JS API does not currently offer a way to access the parentGroup of
// a Layer object. To get around this, we use the low-level _object and
// parentGroup() method.
// Doing so gives us an unwrapped Sketch Object. We must use wrapObject to
// ensure we return a wrapped object for the target.group.
// In the future, it would be good to have a Layer.parentGroup getter.
const api = context.api();
const document = api.selectedDocument;
target.group = api.wrapObject(firstLayer._object.parentGroup(), document);
}
return target;
};
/**
* dumpObj - Introspect objects
* @param {Object} obj
*/
// eslint-disable-next-line no-unused-vars
const dumpObj = function(obj) {
log('------------------------');
log('## Dumping object ' + obj);
log('------------------------');
log('obj.properties:');
log(obj.class().mocha().properties());
log('obj.propertiesWithAncestors:');
log(obj.class().mocha().propertiesWithAncestors());
log('obj.classMethods:');
log(obj.class().mocha().classMethods());
log('obj.classMethodsWithAncestors:');
log(obj.class().mocha().classMethodsWithAncestors());
log('obj.instanceMethods:');
log(obj.class().mocha().instanceMethods());
log('obj.instanceMethodsWithAncestors:');
log(obj.class().mocha().instanceMethodsWithAncestors());
log('obj.protocols:');
log(obj.class().mocha().protocols());
log('obj.protocolsWithAncestors:');
log(obj.class().mocha().protocolsWithAncestors());
log('obj.treeAsDictionary():');
log(obj.treeAsDictionary());
};
gitextract_gh6j5y9l/
├── .eslintrc
├── .gitignore
├── .travis.yml
├── LICENSE.md
├── Makefile
├── README.md
├── manifest.json
├── package.json
├── resources/
│ ├── fillmurray.icns
│ ├── lorempixel.icns
│ ├── placecage.icns
│ ├── placeholdit.icns
│ ├── placekitten.icns
│ └── unsplashit.icns
├── scripts/
│ └── release.js
└── src/
├── components/
│ ├── Alert.js
│ ├── Label.js
│ ├── PopUpButton.js
│ └── TextField.js
├── handlers/
│ ├── fillMurray.js
│ ├── placeCage.js
│ ├── placeHoldIt.js
│ ├── placeKitten.js
│ └── unsplashIt.js
├── index.cocoascript
└── utils.js
Condensed preview — 26 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (33K chars).
[
{
"path": ".eslintrc",
"chars": 1840,
"preview": "{\n \"ecmaFeatures\": {\n \"modules\": true,\n \"experimentalObjectRestSpread\": true\n },\n \"rules\": {\n "
},
{
"path": ".gitignore",
"chars": 66,
"preview": "npm-debug.log\nnode_modules/\nDay Player.sketchplugin\nDayPlayer.zip\n"
},
{
"path": ".travis.yml",
"chars": 603,
"preview": "language: node_js\nnode_js:\n- 5.12.0\nsudo: false\ncache:\n directories:\n - /home/travis/.local\n - node_modules\n - $(npm"
},
{
"path": "LICENSE.md",
"chars": 1076,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Tyler Gaw\n\nPermission is hereby granted, free of charge, to any person obtaini"
},
{
"path": "Makefile",
"chars": 1294,
"preview": "PLUGIN_PATH := ~/Library/Application\\ Support/com.bohemiancoding.sketch3/Plugins/\nPLUGIN_DIR := Day\\ Player.sketchplugin"
},
{
"path": "README.md",
"chars": 3897,
"preview": "[ Download "
},
{
"path": "manifest.json",
"chars": 1201,
"preview": "{\n \"name\": \"Day Player\",\n \"description\": \"A Plugin for creating images from placeholder services.\",\n \"author\": \"Tyler"
},
{
"path": "package.json",
"chars": 653,
"preview": "{\n \"name\": \"day-player-plugin-sketchapp\",\n \"version\": \"3.0.0\",\n \"description\": \"A Sketch Plugin for creating placehol"
},
{
"path": "scripts/release.js",
"chars": 1342,
"preview": "/* eslint-env node */\n/* eslint-disable strict, no-console */\n'use strict';\n\nconst version = require('../package.json')."
},
{
"path": "src/components/Alert.js",
"chars": 2470,
"preview": "/**\n * Alert A facade for NSAlert. Includes a number of convenience methods and a\n * chainable interface.\n *\n * @param {"
},
{
"path": "src/components/Label.js",
"chars": 1374,
"preview": "/**\n * Label A facade for NSTextField without any editable styling. Includes a\n * number of convenience methods and a ch"
},
{
"path": "src/components/PopUpButton.js",
"chars": 923,
"preview": "/**\n * PopUpButton A facade for NSPopUpButton. Includes a number of convenience\n * methods and a chainable interface.\n *"
},
{
"path": "src/components/TextField.js",
"chars": 1321,
"preview": "/**\n * TextField A facade for NSTextField. Includes a number of convenience\n * methods and a chainable interface.\n *\n * "
},
{
"path": "src/handlers/fillMurray.js",
"chars": 1283,
"preview": "// eslint-disable-next-line no-unused-vars\nconst fillMurray = createPluginHandler(function(props) {\n const GREY_TITLE ="
},
{
"path": "src/handlers/placeCage.js",
"chars": 1287,
"preview": "// eslint-disable-next-line no-unused-vars\nconst placeCage = createPluginHandler(function(props) {\n const GREY_TITLE = "
},
{
"path": "src/handlers/placeHoldIt.js",
"chars": 1481,
"preview": "// eslint-disable-next-line no-unused-vars\nconst placeHoldIt = createPluginHandler(function(props) {\n const initOpts = "
},
{
"path": "src/handlers/placeKitten.js",
"chars": 1277,
"preview": "// eslint-disable-next-line no-unused-vars\nconst placeKitten = createPluginHandler(function(props) {\n const GREY_TITLE "
},
{
"path": "src/handlers/unsplashIt.js",
"chars": 1520,
"preview": "// eslint-disable-next-line no-unused-vars\nconst unsplashIt = createPluginHandler(function(props) {\n const GREY_TITLE ="
},
{
"path": "src/index.cocoascript",
"chars": 345,
"preview": "@import './utils.js';\n@import './components/Label.js';\n@import './components/TextField.js';\n@import './components/PopUpB"
},
{
"path": "src/utils.js",
"chars": 5079,
"preview": "/**\n * createPluginHandler - Creates a handler function that takes the context\n * parameter required by Sketch plugins a"
}
]
// ... and 6 more files (download for full content)
About this extraction
This page contains the full source code of the tylergaw/day-player GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 26 files (29.6 KB), approximately 8.5k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.