Come creare un plug-in di schizzo con JavaScript, HTML e CSS (parte 1)

Pubblicato: 2022-03-10
Riassunto rapido ↬ Se hai mai lavorato con Sketch, è probabile che ci siano stati molti momenti in cui hai pensato: "Se solo Sketch potesse fare questa cosa in particolare, sarei in grado di svolgere il compito a portata di mano molto più veloce, più facile e migliore. Bene, non preoccuparti più! In questo articolo in due parti imparerai come creare i tuoi plug-in Sketch da zero, fornendoti le competenze necessarie per risolvere esattamente questo tipo di problemi.

Questo tutorial è rivolto a persone che conoscono e utilizzano l'app Sketch e non hanno paura di dilettarsi con il codice. Per trarne il massimo profitto, dovrai avere almeno un'esperienza di base nella scrittura di JavaScript (e, facoltativamente, HTML/CSS).

Il plugin che creeremo si chiama "Mosaico". Nella prima parte, impareremo i file di base che compongono un plug-in di Sketch; scriveremo del JavaScript e creeremo un'interfaccia utente per il nostro plugin con l'aiuto di HTML e CSS. Il prossimo articolo parlerà di come collegare l'interfaccia utente al codice del plugin principale, come implementare le caratteristiche principali del plugin e, alla fine, imparerai anche come ottimizzare il codice e il modo in cui funziona il plugin.

Condividerò anche il codice del plugin (JS, HTML, CSS) e i file che potrai esaminare e utilizzare per scopi di apprendimento.

Cosa sono i plugin di schizzo e come funzionano?

In Sketch, i plug-in sono un modo per aggiungere caratteristiche e funzionalità che non sono presenti in Sketch "out of the box". Considerando che ci saranno quasi sempre alcune funzionalità o integrazioni mancanti in un dato programma (soprattutto dato il vasto numero di esigenze che ogni singolo designer potrebbe avere!), Si può iniziare a immaginare come i plugin potrebbero essere particolarmente utili e potenti. I plug-in di Sketch sono in grado di fare praticamente tutto ciò che ti aspetteresti, come manipolare il colore, la forma, le dimensioni, l'ordine, lo stile, il raggruppamento e gli effetti dei livelli, ma sono anche in grado di fare cose come fare richieste a risorse Internet, presentare un utente interfaccia e molto altro ancora!

Per quanto riguarda la programmazione, tutti i plugin di Sketch sono scritti in codice JavaScript. Beh, in realtà, non è del tutto vero. È più preciso dire che la maggior parte dei plug-in di Sketch sono scritti in JavaScript, poiché è anche possibile scrivere un plug-in di Sketch in uno dei linguaggi di programmazione di Apple, Objective-C e Swift, sebbene richiedano anche una piccola conoscenza di JavaScript.

Non preoccuparti però. In questo articolo, ci concentreremo su come creare plug-in di Sketch utilizzando solo JavaScript, HTML e CSS . Non esamineremo le basi di HTML, CSS o JavaScript: questo articolo presuppone almeno una certa conoscenza ed esperienza con tutti e tre. Il sito Web per sviluppatori MDN offre un ottimo posto per saperne di più sullo sviluppo Web.

Altro dopo il salto! Continua a leggere sotto ↓

Iniziamo!

In primo luogo, cosa stiamo facendo?

In questo tutorial, ti insegnerò come creare un plug-in di base adatto ai principianti che sarà in grado di creare, duplicare e modificare livelli, oltre a presentare all'utente una bella interfaccia utente. In questo modo, il mio obiettivo è stabilire una conoscenza fondamentale su cui puoi basarti e utilizzarla per creare i tuoi plugin.

Il plugin che costruiremo si chiama Mosaic, ed è effettivamente un "generatore di pattern". Dai da mangiare ai tuoi livelli, modifica alcune impostazioni e creerà un motivo:

Immagine che mostra l'interfaccia utente del plug-in Mosaic e alcuni modelli di esempio.
L'interfaccia utente di Mosaic e alcuni esempi di pattern realizzati con essa. (Grande anteprima)

Se desideri installare e giocare con Mosaic, puoi scaricare il plug-in completo da GitHub.

Un po' di storia: Mosaic si ispira in gran parte a un plug-in Adobe Fireworks della vecchia scuola chiamato Twist-and-Fade . Twist-and-Fade era piuttosto potente, in grado di duplicare un livello qualsiasi numero di volte mentre ne regolava la tonalità, la posizione, la rotazione, le dimensioni e l'opacità. Il plugin è stato anche in grado di generare GIF animate, come questa, dove ha creato i frame per i due elementi rotanti nella cassetta:

Immagine che mostra una cassetta musicale con tamburi rotanti
Cassetta animata (sorgente). (Grande anteprima)

(Ecco un video che mostra Twist and Fade se sei interessato a vedere esattamente come funziona.)

Ai fini di questo tutorial, costruiremo un plug-in in qualche modo simile per Sketch, sebbene volutamente semplificato in modo da mantenere il tutorial il più accessibile possibile. Nello specifico, il nostro plugin sarà in grado di:

  • Duplica qualsiasi livello di schizzo (bitmap o vettoriale) e modifica la posizione, la rotazione e l'opacità del livello dei duplicati. Questo ci darà un'introduzione alla manipolazione dei livelli usando le API JavaScript di Sketch.
  • Visualizza un'interfaccia utente creata utilizzando HTML, CSS e JS, che ti insegnerà come creare facilmente un'interfaccia per il plug-in, utilizzando tecnologie web con cui potresti già avere familiarità. L'interfaccia del plug-in è piuttosto importante poiché è il modo in cui raccoglieremo gli input dell'utente su come l'utente desidera che appaia l'immagine del mosaico risultante.

Creazione del nostro plug-in di base in dieci secondi piatti

Innanzitutto, creeremo la "base" (o modello) per il plug-in che vogliamo creare. Potremmo creare manualmente tutti i file e le cartelle necessari che compongono un plug-in, ma fortunatamente non è necessario, perché Sketch può farlo per noi. Dopo aver generato il plug-in del modello, saremo in grado di personalizzarlo come meglio credi.

C'è una tecnica davvero semplice e veloce che possiamo usare per creare il plug-in del modello, che è praticamente il mio metodo di riferimento quando devo montare un plug-in insieme per risolvere qualsiasi problema che sto affrontando in un dato momento. Ecco come funziona:

Con Sketch aperto, controlla la barra dei menu nella parte superiore dello schermo e fai clic su Plugins -> Run Script . Questo aprirà una finestra di dialogo che possiamo usare per testare ed eseguire il codice. Possiamo anche salvare qualsiasi codice che inseriamo al suo interno come plug-in, che è la parte a cui siamo particolarmente interessati in questo momento.

Cancella il codice già presente in questa finestra di dialogo e sostituiscilo con il seguente codice demo:

 const UI = require("sketch/ui"); UI.message(" Hey there, you fantastic plugin developer you! This is your plugin! Talking to you from the digital computer screen! In Sketch! Simply stupendous!");

Quindi, premi Save Script as Plugin -in nella parte inferiore sinistra della finestra, inserisci il nome che desideri che questo plug-in abbia (nel nostro caso, questo è "Mosaico"), quindi Save Script as Plugin -in ancora una volta.

Premi "Salva" nella parte inferiore sinistra della finestra e inserisci il nome che desideri per questo plugin. (Grande anteprima)

Che ci crediate o no, abbiamo già finito: non resta che mangiare la torta che abbiamo appena sfornato. Ecco la parte divertente. Aprendo di nuovo il menu Plugin, dovresti vedere qualcosa del genere: il tuo nuovissimo plugin elencato come "Mosaico"! Cliccaci sopra!

(Grande anteprima)

Congratulazioni, hai appena scritto il tuo primo plugin per Sketch!

Quello che dovresti vedere dopo aver fatto clic su "Mosaico" dovrebbe essere come il breve video qui sopra, con un messaggio di descrizione comando discreto che appare nella parte inferiore dello schermo che inizia con le parole "Ehi lì...", che è esattamente ciò che lo dice il codice che abbiamo incollato da fare. Questo è ciò che rende questa tecnica così eccezionale: rende facile incollare, modificare e testare il codice senza dover creare un plug-in da zero. Se hai familiarità con o hai mai giocato con la console web del tuo browser, questo è fondamentalmente quello. Avere questo strumento nella tasca dei pantaloni durante la creazione e il test del codice è un must.

Facciamo un rapido riassunto di ciò che fa il codice che hai aggiunto:

Innanzitutto, importa il modulo sketch/ui della libreria JS incorporata di Sketch e lo assegna alla variabile UI . Questo modulo contiene un paio di utili metodi relativi all'interfaccia, uno dei quali utilizzeremo:

 const UI = require("sketch/ui");

Successivamente, chiama il metodo message (che fa parte del modulo sketch/ui ) con la stringa di testo che vogliamo visualizzare nel suggerimento che abbiamo visto:

 UI.message(" Hey there, you fantastic plugin developer you! This is your plugin! Talking to you from the digital computer screen! In Sketch! Simply stupendous!");

Il metodo message() fornisce un ottimo modo per presentare un messaggio discreto all'utente; è ottimo per i casi in cui non è necessario rubare il focus (non modale) e non sono necessari pulsanti o campi di testo fantasiosi. Esistono anche altri modi per presentare elementi comuni dell'interfaccia utente come avvisi, prompt e simili, alcuni dei quali verranno utilizzati durante la creazione di Mosaic.

Personalizzazione dei metadati del nostro plugin

Ora abbiamo un plugin di base da cui partire, ma dobbiamo ancora modificarlo ulteriormente e renderlo veramente nostro. Il nostro prossimo passo sarà cambiare i metadati del plugin.

Per questo passaggio, dovremo dare un'occhiata a quello che viene chiamato bundle di plugin . Quando premi Salva nella finestra "Esegui script", Sketch ha salvato il tuo plug-in come una cartella denominata Mosaic.sketchplugin che puoi trovare nella directory ~/Library/Application Support/com.bohemiancoding.sketch3/Plugins . È un po' lungo e fastidioso da ricordare; come scorciatoia, puoi anche richiamarlo tramite Plugins -> Manage Plugins -> (right-click your plugin) -> Reveal Plugins Folder . Anche se appare nel Finder come un singolo file, in realtà è una cartella contenente tutto ciò di cui il nostro plug-in ha bisogno per l'esecuzione di Sketch. Il motivo per cui appare come un singolo file nonostante sia una cartella è perché quando hai installato Sketch per la prima volta, Sketch ha registrato l'estensione .sketchplugin come un "bundle" (un tipo speciale di cartella che appare come un file) e ne ha chiesto l'apertura automatica in Schizzo una volta aperto.

Diamo un'occhiata all'interno. Fai clic con il pulsante destro del mouse su Mosaic.sketchplugin , quindi fai clic su "Mostra contenuto pacchetto". All'interno, dovresti vedere la seguente struttura di directory:

 Contents/ └ Resources/ └ Sketch/ └ manifest.json └ script.cocoascript

Ti starai chiedendo perché c'è un file con l'estensione .cocoascript . Non preoccuparti: è solo un normale file JavaScript e contiene solo il codice che abbiamo inserito in precedenza. Vai avanti e rinomina questo file in index.js , che cambierà la struttura della directory in modo che assomigli a quella seguente:

 Contents/ └ Resources/ └ Sketch/ └ manifest.json └ index.js

Il modo più comune per organizzare i file all'interno di un bundle di plugin è il seguente: il tuo codice (JavaScript) e manifest.json appartengono a Sketch/ e le risorse (immagini, file audio, file di testo, ecc.) appartengono a Resources/ .

Iniziamo modificando il file denominato manifest.json . Aprilo all'interno del tuo editor di codice preferito, come Visual Studio Code o Atom.

Vedrai che al momento c'è relativamente poco qui dentro, ma ne aggiungeremo presto. Il manifest del plugin ha principalmente due scopi:

  1. Innanzitutto, fornisce metadati che descrivono il plug-in all'utente, ad esempio il nome, la versione, il nome dell'autore e così via. Sketch utilizza queste informazioni nella finestra di dialogo Sketch -> Preferences -> Plugins per creare un elenco e una descrizione per il tuo plugin.
  2. In secondo luogo, spiega anche a Sketch come dedicarsi alla tua attività; ovvero, dice a Sketch come vorresti che appaia il menu del tuo plug-in, quali tasti di scelta rapida assegnare al tuo plug-in e dove risiede il codice del tuo plug-in (in modo che Sketch possa eseguirlo).

Considerando lo scopo n. 1, che descrive il plug-in all'utente, probabilmente noterai che in questo momento non viene fornita alcuna descrizione o autore, il che creerebbe confusione per l'utente e renderebbe difficile l'identificazione del plug-in. Risolviamolo regolando i valori delle chiavi rilevanti su:

 { "description": "Generate awesome designs and repeating patterns from your layers!", "author": "=> Your name here <=" }

Quindi, regoliamo l'identificatore del plug-in. Questo identificatore utilizza quella che viene chiamata "notazione di dominio inversa" che è un modo davvero conciso (o noioso, scegli tu) per dire "prendi il dominio del tuo sito, inverti l'ordine, quindi metti il ​​nome del tuo prodotto alla fine". Verrà fuori qualcosa del tipo: com.your-company-or-your-name-its-not-that-big-a-deal.yourproduct .

Non devi attenerti a questa convenzione di denominazione: puoi mettere quello che vuoi qui, purché sia ​​abbastanza unico da evitare conflitti con altri plugin (anche se probabilmente è una buona idea attenersi al formato RDN, soprattutto perché fornisce un sistema semplice e riutilizzabile per i tuoi identificatori di plugin).

A tal fine, cambia il tuo identificatore in com.your-name.mosaic :

 { "identifier": "com.your-name.mosaic" }

Personalmente mi piace prendere tutte le chiavi relative ai metadati (titolo, autore, identificatore, ecc.) e raggrupparle nella parte superiore del manifest in modo che non siano sparse ovunque e aiutino a preservare la mia sanità mentale quando ho bisogno di trovarle .

Quindi, diamo un'occhiata ai tasti del menu e dei commands . Questi due sono responsabili di dire a Sketch quale codice chiamare e in risposta a cosa.

Se guardi la chiave del menu , vedrai che contiene una chiave del title , il cui valore è il nome con cui il nostro plugin apparirà nel menu Plugins . Ha anche una chiave items , che è un elenco di identificatori di comando :

 { "menu": { "title": "Mosaic", "items": [ "com.bohemiancoding.sketch.runscriptidentifier" ] } }

Al momento c'è solo un identificatore di comando in questo elenco, "com.bohemiancoding.sketch.runscriptidentifier" . Gli identificatori di comando puntano sempre a un comando nell'elenco dei commands . In questo momento il nostro plugin ha solo un comando, che è quello con questo identificatore:

 { "commands": [ { "script" : "script.cocoascript", "name" : "Mosaic", "handlers" : { "run" : "onRun" }, "identifier" : "com.bohemiancoding.sketch.runscriptidentifier" } ] }

Ogni volta che aggiungi un identificatore di comando a una voce di menu , Sketch cercherà la voce di comando che ha quell'identificatore e visualizzerà il valore della sua chiave del name (che in questo caso è "Mosaico") e la mostrerà invece nel menu del tuo plug-in dell'identificatore.

Per quanto riguarda il ruolo svolto dai comandi, possiamo pensare a una voce di comando come un modo per dire a Sketch quale funzione nel codice JavaScript del nostro plug-in vogliamo eseguire quando quel comando viene invocato, la "chiamata" di solito è il clic dell'utente sul menu associato articolo. La voce del comando non fa nulla da sola, è solo JSON: fornisce semplicemente una descrizione a Sketch di dove cercare il JavaScript che deve essere eseguito quando viene invocato il comando.

Finora abbiamo parlato di cosa fanno il name di un comando e le chiavi identifier , ma ci sono altre due chiavi in ​​un comando che devono essere indirizzate: script e handlers .

La chiave script indica a Sketch dove si trova il file JavaScript che dovrebbe essere eseguito. Nota come Sketch presuppone che il file di script in questione si trovi nella cartella Sketch/ , motivo per cui per semplicità ti consigliamo di assicurarti che tutto il tuo codice JavaScript risieda da qualche parte nella cartella Sketch/ . Prima di passare da questa chiave è importante assicurarsi di modificare il valore di questa chiave in index.js , proprio come abbiamo rinominato il file in precedenza. In caso contrario, Sketch non sarà in grado di trovare ed eseguire il file JavaScript.

Il valore della chiave dei handlers è ciò che Sketch esamina per determinare quale funzione nel tuo JavaScript chiamare. Qui abbiamo un solo set di gestori: run , con il valore onRun . run è il nome di un'azione Sketch predefinita e incorporata. Questa azione di run verrà sempre chiamata quando un utente fa clic su una voce di menu che fa riferimento a questo comando. onRun è il nome di una funzione nel file script.cocoascript generato automaticamente (che abbiamo rinominato index.js ) e la funzione che vogliamo venga chiamata quando si verifica l'evento run , ovvero quando l'utente fa clic sulla voce di menu.

Nell'esempio che abbiamo finora, questo processo riproduce qualcosa del genere:

  1. L'utente fa clic sulla nostra voce di menu.
  2. Sketch trova il comando associato a quella voce di menu.
  3. Sketch trova il file di script a cui fa riferimento il comando e lo esegue (che in questo caso significa che esegue JavaScript in index.js ).
  4. Poiché questo comando è stato richiamato da un clic su una voce di menu, è considerato un'azione di run . Ciò significa che Sketch esaminerà il valore handlers.run del comando per la funzione da chiamare successivamente, che in questo caso è onRun .
  5. Sketch chiama la funzione onRun .

I comandi sono più comunemente chiamati in risposta a un utente che fa clic su una delle voci di menu, ma possono anche essere chiamati in risposta ad altre azioni dell'utente, come l'utente che modifica la selezione o una proprietà su un livello. Tuttavia, per questo plugin, non utilizzeremo nessuna di queste altre azioni. (Puoi saperne di più sulle azioni e su come funzionano nella pagina della guida di Action API.)

Prima di passare da questo manifest, vorremo apportare altre due modifiche. Al momento, il nostro menù ha la struttura:

 Mosaic └ Mosaic 
Immagine che mostra la voce di menu Mosaic nidificata in modo ridondante all'interno di un altro menu denominato Mosaic
Abbastanza ridondante, vero? (Grande anteprima)

...che è un po' ridondante poiché il nostro plugin ha solo una voce di menu. Aggiunge anche un po 'di attrito non necessario per il nostro utente poiché il nostro plug-in ora richiede due clic per essere invocato anziché uno. Possiamo risolvere questo problema aggiungendo isRoot: true al nostro menu :

 { "menu": { "title" : "Mosaic", "items" : [ "com.bohemiancoding.sketch.runscriptidentifier" ], "isRoot": true } }

Questo dice a Sketch di posizionare il primo livello di voci di menu direttamente sotto il menu Plugins , invece di nidificarle sotto il title del menu .

Premi Salva e torna a Sketch. Dovresti vedere che ora Mosaic -> Mosaic è stato sostituito solo da Mosaic : perfetto!

Immagine che mostra l'interfaccia utente del plugin Mosaic
Interfaccia utente di Mosaic. (Grande anteprima)

Per quanto riguarda la nostra seconda modifica, andiamo avanti e rinominiamo questo identificatore di comando in qualcosa di meno ingombrante. Poiché gli identificatori di comando devono essere univoci solo nel contesto di un singolo plug-in, possiamo tranquillamente rinominarlo in qualcosa di più conciso ed ovvio, come "open" :

 { "commands": [ { ... "identifier" : "open" } ], "menu": { ... "items" : [ "open" ] } }

Prima di procedere, è utile notare che i menu possono contenere anche altri menu. Puoi facilmente creare un sottomenu annidando un'altra voce { title: ..., items: ... } all'interno dell'elenco delle items di un altro menu:

 { "menu": { "title" : "Mosaic", "items" : [ "open", { "title" : "I'm a sub-menu!", "items" : [ "another-command-identifier" ] } ] } }

Creazione dell'interfaccia utente del plug-in

Finora abbiamo scritto del codice demo e personalizzato il manifest del nostro plugin. Passiamo ora alla creazione della sua interfaccia utente, che è essenzialmente una pagina Web incorporata in una finestra (in modo simile ai browser con cui hai familiarità):

La finestra del plugin. (Grande anteprima)
Immagine che mostra i componenti che compongono l'interfaccia del nostro plugin: finestra e vista web
I componenti che compongono il nostro plugin. (Grande anteprima)

La finestra

Il design dell'interfaccia utente di Mosaic ha una propria finestra, che possiamo considerare il componente più basilare; inizieremo con esso. Per creare e visualizzare una finestra, dovremo utilizzare una classe incorporata in macOS per impostazione predefinita, chiamata NSWindow . Nel resto di questo tutorial, lo faremo un po' (usando API integrate come NSWindow ) che potrebbe sembrare un po' scoraggiante se non hai familiarità con esso, ma non preoccuparti: spiegherò tutto lungo la strada!

Nota: mentre stiamo parlando di API integrate, il motivo per cui siamo in grado di utilizzare questa classe è grazie a un bridge presente nel runtime JavaScript utilizzato dai plug-in di Sketch. Questo bridge importa automaticamente queste classi, metodi e funzioni integrate che normalmente sarebbero disponibili solo per le applicazioni native.

Apri Sketch/index.js nel tuo editor di codice, elimina ciò che è già presente e incolla quanto segue:

 function onRun(context){ const window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_( NSMakeRect(0, 0, 145, 500), NSWindowStyleMaskClosable | NSWindowStyleMaskTitled | NSWindowStyleMaskResizable, NSBackingStoreBuffered, false ); window.releasedWhenClosed = false; window.makeKeyAndOrderFront(nil); };

Diamo un'occhiata a cosa fa questo primo bit di codice:

 function onRun(context){

Ricordi in precedenza quando abbiamo parlato dei comandi e di come funzionano e abbiamo detto a Sketch di chiamare in risposta a un clic del menu chiamato onRun ? (Se hai bisogno di un aggiornamento, rivisita quella parte sopra, quindi torna indietro.) Tutto ciò che fa è creare quella funzione. Noterai anche che la nostra funzione onRun accetta un argomento di context . Questo è un argomento che Sketch chiamerà i tuoi gestori di comando che possono fornirci determinate informazioni. Successivamente, lo utilizzeremo per ottenere l'URL del nostro pacchetto di plug-in sul computer dell'utente.

 const window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer( NSMakeRect(0, 0, 145, 500), NSWindowStyleMaskClosable | NSWindowStyleMaskTitled | NSWindowStyleMaskResizable, NSBackingStoreBuffered, false );

Qui stiamo effettivamente facendo alcune cose:

  1. Per prima cosa, chiamiamo alloc() su NSWindow ; questo fondamentalmente significa "mettere da parte un po' di memoria per un'istanza di NSWindow". È sufficiente sapere che dovrai farlo per ogni istanza di una classe nativa che desideri creare. Il metodo alloc è disponibile in ogni classe nativa.
  2. Successivamente, chiamiamo il metodo di inizializzazione di NSWindow (ovvero il metodo che crea effettivamente un'istanza di NSWindow ), chiamato initWithContentRect:styleMask:backing:defer: . Noterai che è diverso da quello che chiamiamo nel nostro codice sopra: ha un sacco di due punti ( : ) tra ogni argomento. Dal momento che non possiamo usare quella sintassi in JavaScript, Sketch la rinomina convenientemente in qualcosa che possiamo effettivamente usare sostituendo i due punti con i caratteri di sottolineatura, che è il modo in cui otteniamo il suo nome JS: initWithContentRect_styleMask_backing_defer .
  3. Successivamente, passiamo in ciascuno degli argomenti necessari al metodo. Per il primo argomento, contentRect , forniamo un rettangolo con una dimensione sufficientemente grande per la nostra interfaccia utente.
  4. Per styleMask , utilizziamo una maschera di bit che dice che vogliamo che la nostra finestra abbia un pulsante di chiusura, una barra del titolo e che sia ridimensionabile.
  5. I prossimi due argomenti, backing e defer , saranno sempre impostati su NSBackingStoreBuffered e false , quindi non dobbiamo preoccuparcene. (La documentazione per questo metodo approfondisce ulteriormente il motivo per cui è così.)
 window.releasedWhenClosed = false; window.makeKeyAndOrderFront(null);

Qui impostiamo la proprietà NSWindow di releasedWhenClosed su false , che significa: "Ehi! non eliminare questa finestra dalla memoria solo perché l'utente la chiude." Quindi chiamiamo makeKeyAndOrderFront (null) che significa: "Sposta questa finestra in primo piano e mettila a fuoco sulla tastiera".

Visualizzazione Web: l'interfaccia

Per semplificare le cose, ho già scritto il codice HTML e CSS dell'interfaccia utente web del plugin che useremo; l'unico codice rimanente che dovremo aggiungere ad esso si occuperà di assicurarci di essere in grado di comunicare tra esso e il nostro codice del plug-in di Sketch.

Quindi, scarica il codice HTML e CSS. Una volta scaricato, estrailo, quindi sposta la cartella denominata "web-ui" nella cartella Risorse del nostro plug-in.

Nota : la scrittura e l'ottimizzazione del codice HTML/CSS effettivo non rientrano nell'ambito di questo tutorial, poiché si concentra su JavaScript che alimenta le funzionalità principali del plug-in; ma ci sono un sacco di tutorial sul web su questo argomento, se vuoi saperne di più.

Se esegui il nostro plug-in ora, vedrai che mostra una finestra: sì, progressi! Ma è vuoto, senza titolo e non ancora particolarmente utile. Dobbiamo ottenerlo per mostrare la nostra interfaccia web. Per fare ciò, dovremo utilizzare un'altra classe nativa, WKWebView , che è una vista creata appositamente per la visualizzazione di contenuti web.

Aggiungeremo il codice necessario per creare il nostro WKWebView sotto il codice che abbiamo scritto per la nostra finestra:

 function onRun(context){ // Create window const window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer( NSMakeRect(0, 0, 145, 500), NSWindowStyleMaskClosable | NSWindowStyleMaskTitled | NSWindowStyleMaskResizable, NSBackingStoreBuffered, false ); window.releasedWhenClosed = false; // Create web view, and set it as the view for our window to display const webView = WKWebView.alloc().init(); window.contentView = webView; // Load our UI into the web view const webUIFolderURL = context.scriptURL .URLByDeletingLastPathComponent() .URLByAppendingPathComponent("../Resources/web-ui/"); const indexURL = webUIFolderURL.URLByAppendingPathComponent("index.html"); webView.loadFileURL_allowingReadAccessToURL(indexURL, webUIFolderURL); // Make window key and move to front window.makeKeyAndOrderFront(nil); };

Se eseguiamo il nostro plugin ora, vedremo che ora abbiamo una finestra aperta che mostra la nostra interfaccia utente web. Successo!

Ancora una volta, prima di andare avanti, esaminiamo cosa fa il codice che abbiamo aggiunto:

 const webView = WKWebView.alloc().init();

Questo dovrebbe sembrare familiare: è fondamentalmente lo stesso di quello che abbiamo fatto quando abbiamo creato il nostro NSWindow : allocare memoria per una visualizzazione Web, quindi inizializzarlo.

 window.contentView = webView;

Questa riga di codice indica alla nostra finestra di visualizzare la visualizzazione Web appena creata.

 const webUIFolderURL = context.scriptURL .URLByDeletingLastPathComponent() .URLByAppendingPathComponent("../Resources/web-ui/");

Qui il nostro obiettivo è creare un URL che punti alla cartella web-ui che abbiamo creato in precedenza. Per ottenere quell'URL, abbiamo bisogno di un modo per capire dove si trova il pacchetto del nostro plugin nel filesystem dell'utente. Qui utilizziamo la proprietà context.scriptURL , che ci fornisce l'URL dello script attualmente in esecuzione . Tuttavia, questo non ci fornisce una String JavaScript come ci si potrebbe aspettare, ma un'istanza di una classe nativa, NSURL , che contiene alcuni metodi che semplificano la manipolazione delle stringhe URL.

Dobbiamo trasformare ciò che ci fornisce context.scriptURL

 file://path-to-your-plugin/Contents/Sketch/index.js

- in:

 file://path-to-your-plugin/Contents/Resources/web-ui/

Passo dopo passo:

  1. La prima volta che si chiama URLByDeletingLastPathComponent() ci dà file://path-to-your-plugin/Contents/Sketch/
  2. Richiamando URLByDeletingLastPathComponent() ci viene restituito file://path-to-your-plugin/Contents/
  3. E infine, aggiungendo Resources/web-ui/ alla fine usando URLByAppendingPathComponent ("Resources/web-ui/") ci dà file://path-to-your-plugin/Contents/Resources/web-ui/

Dobbiamo anche creare un secondo URL che punti direttamente al file index.html :

 const indexURL = webUIFolderURL.URLByAppendingPathComponent("index.html");

Infine, diciamo alla nostra vista web di caricare index.html e di dargli accesso al contenuto della cartella web-ui :

 webView.loadFileURL_allowingReadAccessToURL(indexURL, webUIFolderURL);

Bene. Finora, abbiamo una finestra che mostra la nostra interfaccia utente web, proprio come volevamo. Tuttavia, non è ancora del tutto completo: il nostro design originale non ha una barra del titolo (o "cromo"), ma la nostra finestra attuale sì. C'è anche il fatto che quando facciamo clic all'interno di un documento di Sketch, quel documento si sposta davanti alla nostra finestra, il che non è quello che vogliamo: vogliamo che l'utente possa interagire con la finestra del plug-in e il documento di Sketch senza dover rifocalizzare costantemente da una finestra all'altra.

Per risolvere questo problema, dobbiamo prima sbarazzarci della finestra predefinita Chrome e mantenere solo i pulsanti. L'aggiunta delle due righe di codice di seguito eliminerà la barra del titolo.

Nota: come prima, tutte le proprietà e i metodi che utilizziamo di seguito sono documentati nella pagina della documentazione di NSWindow .

 window.titlebarAppearsTransparent = true; window.titleVisibility = NSWindowTitleHidden;

Queste due righe di codice successive rimuoveranno i pulsanti della finestra (noti anche come "semafori" nel gergo di MacOS) di cui non abbiamo bisogno - "zoom" e "riduci a icona" - lasciando solo il pulsante "chiudi":

 window.standardWindowButton(NSWindowZoomButton).hidden = true; window.standardWindowButton(NSWindowMiniaturizeButton).hidden = true;

Già che ci siamo, andiamo anche avanti e cambiamo il colore di sfondo della finestra in modo che corrisponda a quello della nostra interfaccia utente web:

 window.backgroundColor = NSColor.colorWithRed_green_blue_alpha(1, 0.98, 0.98, 1);

Successivamente, dobbiamo fare qualcosa per mantenere la nostra finestra del plug-in mobile sopra le altre finestre, in modo che l'utente possa interagire con i propri documenti Sketch senza doversi preoccupare che la finestra di Mosaic scompaia. Possiamo usare un tipo speciale di NSWindow per questo, chiamato NSPanel , che è in grado di "stare in cima" alle altre finestre. Tutto ciò che serve per questo è cambiare NSWindow in NSPanel , che è una modifica del codice a riga singola:

 const window = NSPanel.alloc().initWithContentRect_styleMask_backing_defer(

Ora diciamo alla nostra finestra del pannello di fluttuare (rimanere sopra tutte le altre) e di mettere a fuoco tastiera/mouse solo quando necessario:

 window.floatingPanel = true; window.becomesKeyOnlyIfNeeded = true;

Possiamo anche modificare la nostra finestra in modo che si riapra automaticamente nell'ultima posizione in cui si trovava:

 window.frameAutosaveName = "mosaic-panel-frame";

Questa riga dice fondamentalmente "ricorda la posizione di questa finestra salvandola con le preferenze di Sketch sotto la chiave mosaic-panel-frame ".

Tutti insieme, ora abbiamo il seguente codice:

 function onRun(context){ // Create window const window = NSPanel.alloc().initWithContentRect_styleMask_backing_defer( NSMakeRect(0, 0, 145, 500), NSWindowStyleMaskClosable | NSWindowStyleMaskTitled | NSWindowStyleMaskResizable, NSBackingStoreBuffered, false ); window.becomesKeyOnlyIfNeeded = true; window.floatingPanel = true; window.frameAutosaveName = "mosaic-panel-frame"; window.releasedWhenClosed = false; window.standardWindowButton(NSWindowZoomButton).hidden = true; window.standardWindowButton(NSWindowMiniaturizeButton).hidden = true; window.titlebarAppearsTransparent = true; window.titleVisibility = NSWindowTitleHidden; window.backgroundColor = NSColor.colorWithRed_green_blue_alpha(1, 0.98, 0.98, 1); // Create web view, and set it as the view for our window to display const webView = WKWebView.alloc().init(); window.contentView = webView; // Load our UI into the webview const webUIFolderURL = context.scriptURL .URLByDeletingLastPathComponent() .URLByAppendingPathComponent("../Resources/web-ui/"); const indexURL = webUIFolderURL.URLByAppendingPathComponent("index.html"); webView.loadFileURL_allowingReadAccessToURL(indexURL, webUIFolderURL); // Make window key and move to front window.makeKeyAndOrderFront(nil); };

Organizzare il codice

Prima di passare alla parte successiva, è una buona idea organizzare il nostro codice in modo che sia più facile navigare e modificare. Dal momento che abbiamo ancora molto più codice da aggiungere e vogliamo evitare che index.js diventi una discarica disordinata per tutto il nostro codice, dividiamo un po' le cose e spostiamo il nostro codice specifico dell'interfaccia utente in un file chiamato ui.js , nella cartella Sketch . Estrarremo anche alcune delle attività dell'interfaccia utente che svolgiamo, come la creazione della vista Web e della finestra, nelle loro funzioni.

Crea un nuovo file chiamato ui.js e inserisci il codice qui sotto al suo interno:

 // Private var _window; function createWebView(pageURL){ const webView = WKWebView.alloc().init(); webView.loadFileURL_allowingReadAccessToURL(pageURL, pageURL.URLByDeletingLastPathComponent()); return webView; }; function createWindow(){ const window = NSPanel.alloc().initWithContentRect_styleMask_backing_defer( NSMakeRect(0, 0, 420, 646), NSWindowStyleMaskClosable | NSWindowStyleMaskTitled | NSWindowStyleMaskResizable, NSBackingStoreBuffered, false ); window.becomesKeyOnlyIfNeeded = true; window.floatingPanel = true; window.frameAutosaveName = "mosaic-panel-frame"; window.releasedWhenClosed = false; window.standardWindowButton(NSWindowZoomButton).hidden = true; window.standardWindowButton(NSWindowMiniaturizeButton).hidden = true; window.titlebarAppearsTransparent = true; window.titleVisibility = NSWindowTitleHidden; window.backgroundColor = NSColor.colorWithRed_green_blue_alpha(1, 0.98, 0.98, 1); return window; }; function showWindow(window){ window.makeKeyAndOrderFront(nil); }; // Public function loadAndShow(baseURL){ if(_window){ showWindow(_window); return; } const pageURL = baseURL .URLByDeletingLastPathComponent() .URLByAppendingPathComponent("../Resources/web-ui/index.html"); const window = createWindow(); const webView = createWebView(pageURL); window.contentView = webView; _window = window; showWindow(_window); }; function cleanup(){ if(_window){ _window.orderOut(nil); _window = null; } }; // Export module.exports = { loadAndShow, cleanup };

Ci sono un paio di modifiche chiave che abbiamo apportato qui che è importante notare. Oltre al fatto che abbiamo creato funzioni specifiche per creare, nascondere e mostrare la nostra finestra e la sua visualizzazione web, abbiamo anche modularizzato il codice della nostra interfaccia utente.

Notare la module.exports = { loadAndShow, cleanup } in fondo? Questo è un modo per noi di specificare esattamente quali oggetti e funzioni possono utilizzare gli script che importano questo codice dell'interfaccia utente (e nascondere quelli di cui non vogliamo che si preoccupino), il che significa che ora abbiamo un'API più organizzata con cui interagire, mostrando e distruggendo la nostra interfaccia utente.

Letture consigliate : Liberare il pieno potenziale dei simboli in Sketch

Vediamo come appare in pratica. Di nuovo in index.js , rimuovi il vecchio codice e aggiungi quanto segue:

 const UI = require("./ui"); function onRun(context){ UI.loadAndShow(context.scriptURL); };

Stiamo utilizzando una funzione speciale che Sketch ci rende automaticamente disponibile, require , per importare il nostro codice ui.js e assegnare il modulo restituito alla variabile UI . Questo ci dà accesso a un'API semplificata per attivare la nostra interfaccia utente. Le cose ora sono molto più ordinate e facili da trovare!

Conclusione

Ben fatto, sei arrivato lontano! In the next part of this tutorial, we'll give our web UI the ability to send us a message when the “Apply” button is clicked, and we'll focus on the main plugin functionality: actually generating layer mosaics!