Custom Project Deck
Apri i tuoi progetti — locali o su un host remoto via SSH — con un click, da una dashboard visiva che decidi tu come deve apparire: icone, colori, raggruppamenti per tag, persino il markup HTML della pagina. Niente più liste di link markdown da tenere aggiornate a mano o pannelli laterali stretti e poco personalizzabili.
Si apre come pagina a tutta larghezza nell'area centrale dell'editor (stile "Welcome Page"), non come pannello nella sidebar — la sidebar ha solo un'icona di lancio rapido.
Perché
Le estensioni "project switcher" esistenti funzionano ma offrono poco controllo grafico. Custom Project Deck usa una webview HTML/CSS scritta a mano in una pagina centrale, e il markup di come i progetti vengono mostrati è personalizzabile da te tramite un template HTML con una sintassi simile ad Angular ({{ variabile }}, *for, *if).
Uso
Icona Custom Project Deck nella Activity Bar: è una piccola webview con un bottone grande "Apri Custom Project Deck" e sotto tre bottoncini piccoli — Configura, Template, Stile (niente più link testuali: sono <button> veri, dimensionati e colorati come vogliamo, non vincolati alla welcome view nativa di VS Code). La dashboard si apre anche da sola all'avvio di VS Code (disattivabile con projectDeck.openOnStartup).
Al primo avvio è vuota. Usa Custom Project Deck: Configure (UI) (bottone "🛠️ Configura" in sidebar) per un editor a form. Non c'è più un file JSON grezzo da aprire: tag e progetti vivono in context.globalState dell'estensione (vedi "Sincronizzazione" sotto), l'unico modo per vederli in formato JSON è il tab di sola lettura dentro l'editor UI.
Editor UI (senza toccare il JSON a mano)
Custom Project Deck: Configure (UI) apre una pagina con tre tab (stile VS Code, con la barra in alto):
- Tag: tabella con id, nome, icona (emoji), colore (color picker nativo), elimina. Rinominare l'id di un tag aggiorna automaticamente i riferimenti nei progetti che lo usano; eliminare un tag lo rimuove subito da tutti i progetti che lo avevano assegnato.
- Progetti: tabella con nome, path (un unico campo testo — incolla l'URI completo,
file:///... o vscode-remote://ssh-remote+...), descrizione, icona, colore, tag assegnabili come checkbox, elimina.
- JSON: editor testuale per utenti "pro" — mostra lo stato corrente (comprese le modifiche non ancora salvate) e puoi modificarlo direttamente a mano. Bottone Applica valida il JSON (sintassi + forma:
tags/projects array, campi richiesti) e lo riversa nelle tab Tag/Progetti; se non è valido resta tutto com'era, con l'errore mostrato sopra l'editor. "Applica" aggiorna solo lo stato in memoria — serve comunque Salva per scrivere le modifiche.
Bottoni Salva (con validazione: nomi/path non vuoti, id tag univoci) e Annulla modifiche (ricarica l'ultimo stato salvato, scartando le modifiche non salvate — chiede conferma). Non c'è autosave: le modifiche restano solo in memoria finché non premi Salva. Se la dashboard è aperta in un'altra tab si aggiorna da sola dopo il salvataggio.
Sincronizzazione tra le tue macchine
Tag e progetti (non template/stile, per ora) sono salvati in context.globalState, marcato con setKeysForSync() — lo stesso meccanismo di Settings Sync che VS Code usa per le tue impostazioni. Se hai Settings Sync attivo (account Microsoft o GitHub collegato a VS Code), i tuoi progetti compaiono automaticamente anche sulle altre macchine dove usi lo stesso account, senza bisogno di file condivisi, NAS o altro — funziona per chiunque installi l'estensione, non solo per chi ha una propria infrastruttura di sync.
Nota: la propagazione non è istantanea multi-finestra — come per qualunque altra impostazione sincronizzata da VS Code, il valore aggiornato compare sulle altre macchine al prossimo avvio/sync di VS Code lì, non in tempo reale mentre lavori.
Schema dati
Due chiavi principali, tags (definizione dei tag disponibili) e projects (lista piatta di progetti, ognuno riferisce zero o più tag per id) — puoi vederle live nel tab JSON dell'editor UI. .project-deck.example.json in questo repo mostra la stessa forma, solo a scopo illustrativo (non è più un file che l'estensione legge):
{
"tags": [
{ "id": "enea", "name": "Enea", "icon": "☁️", "color": "#8a5cf6" } // "icon"/"color" opzionali
],
"projects": [
{
"name": "Workspace Agent",
"path": "vscode-remote://ssh-remote+utente@host:porta/percorso/assoluto",
"description": "Testo libero, opzionale",
"icon": "🚀", // opzionale
"color": "#4f8cff", // opzionale
"tags": ["enea"] // opzionale, id dei tag definiti sopra
}
]
}
- Progetti locali:
"path": "file:///percorso/assoluto"
- Progetti remoti SSH:
"path": "vscode-remote://ssh-remote+utente@host:porta/percorso/assoluto"
Template personalizzabile
Comando Custom Project Deck: Edit Template apre (creandolo al primo uso da media/content.template.html) il file che controlla tutto ciò che appare sotto la barra di ricerca — non solo lo stile della card, ma anche quanti raggruppamenti fare e su quali sottoinsiemi di progetti.
Nel template hai a disposizione questo scope:
projects: array di tutti i progetti (già filtrati dalla ricerca), ognuno arricchito con host (l'host SSH estratto dal path, se remoto) e tagObjects (i tag risolti a oggetti completi {id,name,icon,color})
projectsByTag: oggetto { [tagId]: Project[] } — per mostrare solo i progetti di un tag: *for="project of projectsByTag.enea"
projectsByName: oggetto { [nome]: Project } — per referenziare un singolo progetto scelto a mano, senza alcun *for: data-open="{{ projectsByName['Stal'].path }}"
tags: array dei tag definiti nel config
Sintassi supportata (motore scritto da zero, nessun eval — CSP della webview resta rigido):
{{ espressione }} — interpolazione testo/attributi
*for="item of espressione" — ripete l'elemento per ogni elemento dell'array risolto da espressione
*if="espressione" — mostra l'elemento solo se l'espressione è truthy
- Espressioni: path a proprietà (
project.name, tag.color), indicizzazione con chiave letterale o dinamica (projectsByTag['enea'], projects[0], projectsByTag[tag.id] — dentro le parentesi quadre può starci qualunque espressione, non solo un letterale fisso), ||, &&, !, literal stringa/numero/booleano. Niente chiamate a metodo o operatori matematici.
- Il click-to-open funziona tramite l'attributo
data-open="{{ project.path }}" su qualunque elemento — l'estensione ci attacca da sola il listener
Esempio: raggruppare per un tag specifico, hardcoded, invece della griglia unica di default (i gruppi vuoti dopo un filtro di ricerca non lasciano sezioni fantasma, avvolgendoli con *if="projectsByTag.enea.length"):
<h2 *if="projectsByTag.enea.length">Enea</h2>
<div class="project-grid" *if="projectsByTag.enea.length">
<div class="project-card" *for="project of projectsByTag.enea" data-open="{{ project.path }}">
<div class="project-card-name">{{ project.name }}</div>
</div>
</div>
Esempio: raggruppare per tutti i tag esistenti, dinamicamente — un solo blocco che si adatta da solo quando aggiungi/rinomini/elimini un tag dall'editor UI, senza mai toccare il template:
<div *for="tag of tags">
<h2 *if="projectsByTag[tag.id].length">{{ tag.icon }} {{ tag.name }}</h2>
<div class="project-grid" *if="projectsByTag[tag.id].length">
<div class="project-card" *for="project of projectsByTag[tag.id]" data-open="{{ project.path }}">
<div class="project-card-name">{{ project.name }}</div>
</div>
</div>
</div>
Se il template ha un errore (tag non chiuso, *for malformato, ecc.) compare un avviso inline al posto di una pagina bianca o di un crash.
Sviluppo
npm install
npm run compile # build una tantum
npm run watch # rebuild automatico
Premi F5 in VS Code per lanciare una finestra "Extension Development Host".
Stato
v0.1.0. Il path dei progetti nell'editor UI resta un campo testo libero (nessun builder guidato per gli URI SSH), e riordino/drag&drop di tag e progetti non c'è ancora. Template e stile personalizzati non sono ancora sincronizzati (restano file locali) — è il prossimo passo, richiede un ponte file↔globalState più delicato di quello già fatto per il config. Roadmap verso la pubblicazione sul Marketplace: icona 128×128, LICENSE, CHANGELOG, vsce package.