├── .gitignore
├── .vscode
├── settings.json
└── tasks.json
├── LICENSE
├── README.md
├── index.d.ts
├── modules
└── LineChart.js
├── parse-docs.js
├── scriptable.sh
├── tsconfig.json
└── widgets
├── Crypto-Line-Chart.js
└── InfoWidget.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | lerna-debug.log*
8 |
9 | # Diagnostic reports (https://nodejs.org/api/report.html)
10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11 |
12 | # Runtime data
13 | pids
14 | *.pid
15 | *.seed
16 | *.pid.lock
17 |
18 | # Directory for instrumented libs generated by jscoverage/JSCover
19 | lib-cov
20 |
21 | # Coverage directory used by tools like istanbul
22 | coverage
23 | *.lcov
24 |
25 | # nyc test coverage
26 | .nyc_output
27 |
28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29 | .grunt
30 |
31 | # Bower dependency directory (https://bower.io/)
32 | bower_components
33 |
34 | # node-waf configuration
35 | .lock-wscript
36 |
37 | # Compiled binary addons (https://nodejs.org/api/addons.html)
38 | build/Release
39 |
40 | # Dependency directories
41 | node_modules/
42 | jspm_packages/
43 |
44 | # TypeScript v1 declaration files
45 | typings/
46 |
47 | # TypeScript cache
48 | *.tsbuildinfo
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Microbundle cache
57 | .rpt2_cache/
58 | .rts2_cache_cjs/
59 | .rts2_cache_es/
60 | .rts2_cache_umd/
61 |
62 | # Optional REPL history
63 | .node_repl_history
64 |
65 | # Output of 'npm pack'
66 | *.tgz
67 |
68 | # Yarn Integrity file
69 | .yarn-integrity
70 |
71 | # dotenv environment variables file
72 | .env
73 | .env.test
74 |
75 | # parcel-bundler cache (https://parceljs.org/)
76 | .cache
77 |
78 | # Next.js build output
79 | .next
80 |
81 | # Nuxt.js build / generate output
82 | .nuxt
83 | dist
84 |
85 | # Gatsby files
86 | .cache/
87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
88 | # https://nextjs.org/blog/next-9-1#public-directory-support
89 | # public
90 |
91 | # vuepress build output
92 | .vuepress/dist
93 |
94 | # Serverless directories
95 | .serverless/
96 |
97 | # FuseBox cache
98 | .fusebox/
99 |
100 | # DynamoDB Local files
101 | .dynamodb/
102 |
103 | # TernJS port file
104 | .tern-port
105 |
106 | .DS_Store
107 | sources
108 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.exclude": {
3 | "sources/.Trash": true,
4 | "sources/cache": true
5 | }
6 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "Run",
8 | "type": "shell",
9 | "command": "open \"scriptable:///run/$(echo ${fileBasenameNoExtension} | sed 's/ /%20/g')\"",
10 | "group": {
11 | "kind": "build",
12 | "isDefault": true
13 | },
14 | "presentation": {
15 | "reveal": "never",
16 | "focus": false
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Slavik Nychkalo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Scriptable Development Environment
2 |
3 |
4 | This project includes
5 | - Scriptable types generated from documentation page
6 | - **RUN SCRIPT** hotkey: ⌘ + SHIFT + B, it will run current script in Scriptable
7 | > Script file name should not contain spaces
8 | - Folder with all your Scriptable apps
9 |
10 |
11 | ## Getting started
12 |
13 | How to start to develop scriptable apps with VSCode:
14 |
15 | 1. Download [Scriptable for MacOS](https://web.archive.org/web/20220721061634/https://scriptable.app/mac-beta/Scriptable.zip) (via Internet Archive Wayback Machine)
16 | 2. Enable iCloud sync for Scriptable
17 | 3. Download [VSCode](https://code.visualstudio.com/)
18 | 4. Clone this repository
19 | ```sh
20 | git clone https://github.com/gebeto/scriptables
21 | ```
22 | 5. Run command to initialize your sources folder link
23 | ```sh
24 | ./scriptable.sh init
25 | ```
26 | 6. Done! Open VSCode in the repo(`code .`) and start to build your apps fast and easy!
27 |
28 | > Folder `sources` is your scriptable folder link, you can edit files there and it will be updated in scriptable app.
29 |
30 |
31 | ## Initialize your local env
32 |
33 | Tou can use BASH script or [VSCode extension](https://marketplace.visualstudio.com/items?itemName=gebeto.vscode-scriptable) for it
34 |
35 | ```sh
36 | $ ./scriptable.sh init
37 | ```
38 |
39 |
40 | ## Import your script for git integration
41 |
42 | > IMPORTANT: Script name should not contain any **spaces**, because RUN hotkey will now working
43 |
44 | ```sh
45 | $ ./scriptable.sh import ScriptName
46 | # or
47 | $ ./scriptable.sh import Script-Name
48 | # or
49 | $ ./scriptable.sh import Script_Name
50 | ```
51 |
52 |
53 | ## Relative projects
54 | - [https://github.com/gebeto/scriptable-vscode](https://github.com/gebeto/scriptable-vscode)
55 | > plugin will replace `scriptable.sh` when it will done(work in progress).
56 | - [https://github.com/schl3ck/ios-scriptable-types](https://github.com/schl3ck/ios-scriptable-types)
57 | > Scriptable Typescript typings
58 |
59 |
60 | ## ERRORS
61 | If scriptable typing are not loaded for you, need to add `///` on top of the your script (like shown below).
62 | Where **path** is a relative path to the `index.d.ts` file.
63 |
64 | ```diff
65 | // Variables used by Scriptable.
66 | // These must be at the very top of the file. Do not edit.
67 | // icon-color: green; icon-glyph: magic;
68 | + ///
69 |
70 | ...
71 | ```
72 |
73 |
74 | ## Thanks
75 | - [schl3ck](https://github.com/schl3ck) for Scriptable types definition: [ios-scriptable-types](https://github.com/schl3ck/ios-scriptable-types)
76 |
--------------------------------------------------------------------------------
/modules/LineChart.js:
--------------------------------------------------------------------------------
1 | function normalize(items) {
2 | const min = Math.min(...items)
3 | const max = Math.max(...items)
4 | const diff = max - min;
5 | return items.map(i => (i - min) / diff)
6 | }
7 |
8 | /**
9 | *
10 | * @param {{ data, width, height, chartHeight, spacing }} options chart options
11 | * @returns DrawContext
12 | */
13 | function drawChart({ data, width, height, chartHeight, spacing }) {
14 | const items = data.map(i => i[0])
15 | const nitems = normalize(items)
16 | console.log(nitems)
17 | const c = new DrawContext()
18 | c.size = new Size(width, height)
19 | const p = new Path()
20 | p.addLines([
21 | new Point(0, height),
22 | new Point(0, height)
23 | ])
24 | // p.addQuadCurve(new Point(150, 150), new Point(0, 150))
25 | // p.addQuadCurve(new Point(300, 300), new Point(300, 150))
26 | const step = width / (nitems.length - 1)
27 | const halfStep = step / 2;
28 |
29 | const getPoint = (arr, index) => {
30 | const i = arr[index]
31 | const yy = i * chartHeight
32 | const y = (height - spacing) - yy
33 | return new Point(index * step, y)
34 | }
35 |
36 | const getCurvePoint = (arr, index, mp) => {
37 | const op = getPoint(arr, index + mp);
38 | const p = getPoint(arr, index)
39 | if (mp == -1) {
40 | p.x += halfStep
41 | return p
42 | } else if (mp == 1) {
43 | op.x -= halfStep
44 | return op
45 | }
46 | return p
47 | }
48 |
49 | p.addLine(new Point(0, height))
50 |
51 | nitems.forEach((i, index, arr) => {
52 | p.addLine(
53 | getPoint(arr, index),
54 | getCurvePoint(arr, index, 1),
55 | getCurvePoint(arr, index, -1)
56 | )
57 | })
58 | p.addLine(new Point(width, height))
59 | p.closeSubpath()
60 | c.addPath(p)
61 | c.setStrokeColor(Color.red())
62 | //c.setLineWidth(5)
63 | // c.strokePath()
64 | c.setFillColor(Color.purple())
65 | c.fillPath()
66 | return c;
67 | }
68 |
69 |
70 | module.exports.drawChart = drawChart;
71 |
--------------------------------------------------------------------------------
/parse-docs.js:
--------------------------------------------------------------------------------
1 | let methods = [...document.querySelectorAll('.md-clipboard+code')].map(i => {
2 | let row = '\t' + i.textContent.trim();
3 | if (row.match(/\)$/)) {
4 | row = row.replace(/\)$/, '): void;');
5 | } else {
6 | row = row + ";";
7 | }
8 | return row;
9 | }).join('\n');
10 | let title = document.querySelector('h1').textContent.trim().replace('¶', '');
11 | copy(`class ${title} \{\n${methods}\}`)
--------------------------------------------------------------------------------
/scriptable.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 |
4 | function show_commands() {
5 | echo "Available commands: '$1'"
6 | printf '\r\n'
7 | printf ' '
8 | printf '%s\n ' "${commands[@]}"
9 | printf '\r\n'
10 | }
11 |
12 |
13 | function upgradeTypes() {
14 | curl https://raw.githubusercontent.com/schl3ck/ios-scriptable-types/master/dist/scriptable.d.ts -o index.d.ts
15 | }
16 |
17 |
18 | function init() {
19 | ln -s ~/Library/Mobile\ Documents/iCloud~dk~simonbs~Scriptable/Documents/ sources
20 | }
21 |
22 |
23 | function import() {
24 | ln ~/Library/Mobile\ Documents/iCloud~dk~simonbs~Scriptable/Documents/"$1.js" "widgets/$1.js"
25 | }
26 |
27 |
28 | function importModule() {
29 | ln ~/Library/Mobile\ Documents/iCloud~dk~simonbs~Scriptable/Documents/modules/"$1.js" "modules/$1.js"
30 | }
31 |
32 |
33 | function list() {
34 | ls ~/Library/Mobile\ Documents/iCloud~dk~simonbs~Scriptable/Documents/
35 | }
36 |
37 |
38 | commands=(init list import importModule upgradeTypes)
39 |
40 |
41 | if [[ $# -gt 0 ]] && [[ "${commands[@]}" =~ "$1" ]]; then
42 | $1 "${@:2}";
43 | else
44 | show_commands "$commands"
45 | fi
46 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "module": "commonjs",
5 | "lib": ["ES2015"],
6 | "strict": true,
7 | "esModuleInterop": true,
8 | "skipLibCheck": true,
9 | "forceConsistentCasingInFileNames": true
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/widgets/Crypto-Line-Chart.js:
--------------------------------------------------------------------------------
1 | // Variables used by Scriptable.
2 | // These must be at the very top of the file. Do not edit.
3 | // icon-color: red; icon-glyph: download;
4 | ///
5 |
6 | const data_ = [[1], [1.9], [4], [2.8], [5], [2.4]];
7 | const crypto = args.widgetParameter || "btc";
8 | const req = new Request("https://api.kuna.io/v3/book/" + crypto + "uah");
9 | const dd = await req.loadJSON();
10 | const data = dd.slice(0, 30);
11 | data.reverse();
12 |
13 | const lw = new ListWidget();
14 |
15 | const chart = importModule("modules/LineChart").drawChart({
16 | data: data,
17 | width: 300,
18 | height: 300,
19 | chartHeight: 140,
20 | spacing: 50,
21 | });
22 | lw.backgroundImage = chart.getImage();
23 | const text = lw.addText(crypto.toUpperCase());
24 | text.url = "https://github.com";
25 | text.leftAlignText();
26 | text.font = Font.boldMonospacedSystemFont(24);
27 | text.textColor = Color.black();
28 | const dateText = lw.addDate(new Date());
29 | dateText.applyTimeStyle();
30 | dateText.font = Font.boldMonospacedSystemFont(8);
31 | dateText.textColor = Color.black();
32 | dateText.textOpacity = 0.3;
33 | lw.addSpacer();
34 | Script.setWidget(lw);
35 | lw.presentSmall();
36 |
--------------------------------------------------------------------------------
/widgets/InfoWidget.js:
--------------------------------------------------------------------------------
1 | // Variables used by Scriptable.
2 | // These must be at the very top of the file. Do not edit.
3 | // icon-color: light-brown; icon-glyph: magic;
4 | ///
5 |
6 | const ww = new ListWidget()
7 | ww.setPadding(0,0,0,0);
8 |
9 |
10 | const color = {
11 | shadow: Color.dynamic(
12 | new Color("#000000", 0.01),
13 | new Color("#FFFFFF", 0.04),
14 | ),
15 | cardBackground: Color.dynamic(
16 | new Color("#555555", 0.1),
17 | new Color("#FFFFFF", 0.1),
18 | ),
19 | cardBackgroundSmall: Color.dynamic(
20 | new Color("#555555", 0.1),
21 | new Color("#FFFFFF", 0.12),
22 | ),
23 | caption: Color.dynamic(
24 | new Color("#000000", 0.6),
25 | new Color("#FFFFFF", 0.6),
26 | ),
27 | white: Color.dynamic(
28 | new Color("#000000", 0.8),
29 | Color.white(),
30 | ),
31 | black: Color.dynamic(
32 | Color.white(),
33 | new Color("#000000", 0.8),
34 | ),
35 | }
36 |
37 | function addSFIcon(stack, name, size) {
38 | const sfIcon = SFSymbol.named(name);
39 | sfIcon.applyFont(Font.boldRoundedSystemFont(size));
40 | const sfImage = stack.addImage(sfIcon.image);
41 | sfImage.tintColor = color.white;
42 | sfImage.imageOpacity = 0.8;
43 | sfImage.imageSize = new Size(size, size);
44 | return sfImage;
45 | }
46 |
47 |
48 | const stackRoot = ww.addStack();
49 | // stackRoot.borderColor = new Color("#FFFFFF");
50 | // stackRoot.borderWidth = 6;
51 | stackRoot.setPadding(10, 10, 10, 10);
52 | stackRoot.cornerRadius = 20;
53 | // stackRoot.size = new Size(136, 136);
54 | stackRoot.layoutVertically();
55 |
56 | const stackTopRoot = stackRoot.addStack();
57 | stackTopRoot.centerAlignContent();
58 | const stackTopLeft = stackTopRoot.addStack();
59 | stackTopRoot.addSpacer();
60 | // const stackTopCenter = stackTopRoot.addStack();
61 | // stackTopCenter.backgroundColor = Color.dynamic(
62 | // new Color("#555555", 0.1),
63 | // new Color("#FFFFFF", 0.1),
64 | // );
65 | // stackTopCenter.size = new Size(2, 38);
66 | // stackTopCenter.cornerRadius = 1;
67 | // stackTopRoot.addSpacer();
68 | const stackTopRight = stackTopRoot.addStack();
69 |
70 | stackTopRoot.layoutHorizontally();
71 | stackTopRoot.cornerRadius = 14;
72 | stackTopRoot.borderWidth = 2;
73 | stackTopRoot.borderColor = color.shadow;
74 | stackTopRoot.backgroundColor = color.cardBackground;
75 | stackTopRoot.setPadding(8, 12, 8, 8);
76 |
77 | stackTopLeft.centerAlignContent();
78 | stackTopLeft.layoutVertically();
79 | stackTopLeft.topAlignContent();
80 |
81 | // stackTopRight.borderColor = Color.red();
82 | // stackTopRight.borderWidth = 1;
83 | stackTopRight.layoutVertically();
84 | stackTopRight.bottomAlignContent();
85 | addSFIcon(stackTopRight, "figure.walk.diamond.fill", 36);
86 |
87 | const titleText = stackTopLeft.addText("128");
88 | // const titleText = stackTopLeft.addText(`${Device.screenScale()}`);
89 | titleText.font = Font.boldRoundedSystemFont(36);
90 |
91 | const captionText = stackTopLeft.addText("Steps");
92 | captionText.font = Font.regularRoundedSystemFont(12);
93 | captionText.textColor = color.caption;
94 |
95 | stackRoot.addSpacer();
96 |
97 | function createFlexibleBlock(root) {
98 | const stack = root.addStack();
99 | stack.centerAlignContent()
100 | stack.backgroundColor = color.cardBackgroundSmall;
101 | stack.borderWidth = 2;
102 | stack.borderColor = color.shadow;
103 | stack.cornerRadius = 14;
104 | stack.addSpacer();
105 | const stackCenter = stack.addStack();
106 | stackCenter.layoutVertically()
107 | stackCenter.addSpacer();
108 | const stackResult = stackCenter.addStack()
109 | stackCenter.addSpacer();
110 | stack.addSpacer();
111 | return stackResult;
112 | }
113 |
114 | const stackBottom = stackRoot.addStack();
115 | const stackBottomLeft = createFlexibleBlock(stackBottom);
116 | addSFIcon(stackBottomLeft, "video.fill", 28)
117 | stackBottom.addSpacer();
118 | const stackBottomRight = createFlexibleBlock(stackBottom);
119 | const i = addSFIcon(stackBottomRight, "camera.fill", 28)
120 | stackBottomRight.url = "camera://photo";
121 |
122 |
123 | // ww.presentSmall();
124 | ww.presentMedium();
--------------------------------------------------------------------------------