The editor used the browser's built-in drag-and-drop, which never fires for a touchscreen, flickered its drop highlight over a card's inner parts, and lost the drag whenever a board update arrived mid-drag (the editor was rebuilt under the pointer). Dragging is now driven by pointer events, one path for mouse and touch: a mouse drags as soon as it moves, a finger holds still for a moment first so a swipe still scrolls. A floating copy of the photo follows the pointer, the spot under it lights up, the editor auto-scrolls near its edges, and board updates wait until the drop. Tap a photo then tap a spot still works. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
155 lines
4.6 KiB
JSON
155 lines
4.6 KiB
JSON
{
|
||
"id": "band-lineup",
|
||
"name": "Band Lineup",
|
||
"version": "1.12.0",
|
||
"proddash": ">=1.4.0",
|
||
"description": "Stage lineup photos with mic/pack labels — a drag-in photo library plus optional Planning Center auto-fill",
|
||
"client": "client.js",
|
||
"server": "server.js",
|
||
"style": "style.css",
|
||
"minSize": {
|
||
"w": 4,
|
||
"h": 3
|
||
},
|
||
"defaultSize": {
|
||
"w": 8,
|
||
"h": 5
|
||
},
|
||
"configGroups": {
|
||
"Planning Center credentials": {
|
||
"collapsed": "whenSet",
|
||
"help": "Create a Personal Access Token at api.planningcenteronline.com and paste its Client ID + Secret here, or paste an OAuth 2.0 access token instead. Reading photos and birthdays needs People access on the token. Saved secrets never reach browsers."
|
||
},
|
||
"Stage": {
|
||
"help": "One mic/pack label per line, in the order they sit on stage. Scheduled people are matched into these by their Planning Center position (e.g. a line '[VOX 2] MIX 2' takes whoever is scheduled on Vox 2). Blank lines are empty spots."
|
||
},
|
||
"Photo library": {
|
||
"help": "Paste a Google Drive folder share link (set the folder to 'Anyone with the link → Viewer'). Every image is imported (file name → person's name) and kept in sync — add or remove photos in Drive and the board follows. A local folder path also works. If Drive can't be read, the board falls back to Planning Center photos."
|
||
}
|
||
},
|
||
"configSchema": {
|
||
"appId": {
|
||
"type": "string",
|
||
"label": "Client ID",
|
||
"default": "",
|
||
"group": "Planning Center credentials"
|
||
},
|
||
"secret": {
|
||
"type": "password",
|
||
"label": "Secret",
|
||
"default": "",
|
||
"group": "Planning Center credentials"
|
||
},
|
||
"accessToken": {
|
||
"type": "password",
|
||
"label": "OAuth 2.0 access token (instead of Client ID + Secret)",
|
||
"default": "",
|
||
"group": "Planning Center credentials"
|
||
},
|
||
"serviceTypeId": {
|
||
"type": "select",
|
||
"label": "Service type",
|
||
"default": "",
|
||
"optionsRoute": "/service-types"
|
||
},
|
||
"planId": {
|
||
"type": "select",
|
||
"label": "Plan",
|
||
"default": "",
|
||
"options": [
|
||
{
|
||
"value": "",
|
||
"label": "Automatic — today's plan, else the next upcoming"
|
||
}
|
||
],
|
||
"optionsRoute": "/plans",
|
||
"optionsDependsOn": "serviceTypeId"
|
||
},
|
||
"teams": {
|
||
"type": "text",
|
||
"label": "Teams to include",
|
||
"default": "Band\nWorship\nVocal\nProduction\nCommunication",
|
||
"help": "One team name (or keyword) per line. A person on any matching Planning Center team is eligible for the board."
|
||
},
|
||
"slots": {
|
||
"type": "text",
|
||
"label": "Stage slots",
|
||
"default": "[LEADER, VOX 1, ACOUSTIC] MIX 1\n[VOX 2] MIX 2\n[VOX 3] MIX 3\n[VOX 4] MIX 4\n[GUITAR, LEAD] MIX 5\n[BASS] MIX 6\n[VOX 5] MIX 7\n[PIANO]\n[DRUMS]\n[KEYS 2]\n[CALL TO WORSHIP] MC2\nSTAGE MANAGER\n[MC] MC1\n[SPEAKER] HEADSET",
|
||
"group": "Stage"
|
||
},
|
||
"columns": {
|
||
"type": "number",
|
||
"label": "Columns",
|
||
"default": 7,
|
||
"group": "Stage",
|
||
"help": "Default slots per row (each screen can still adjust with the − / + buttons in its title bar)."
|
||
},
|
||
"photoFolder": {
|
||
"type": "string",
|
||
"label": "Google Drive folder link",
|
||
"default": "",
|
||
"group": "Photo library",
|
||
"help": "e.g. https://drive.google.com/drive/folders/… (a local folder path also works). Leave blank to use Planning Center photos only."
|
||
}
|
||
},
|
||
"instanceGroups": {
|
||
"Birthday": {
|
||
"toggle": "birthdays"
|
||
}
|
||
},
|
||
"instanceSchema": {
|
||
"showNames": {
|
||
"type": "boolean",
|
||
"label": "Names",
|
||
"default": true
|
||
},
|
||
"showLabels": {
|
||
"type": "boolean",
|
||
"label": "Mic labels",
|
||
"default": true
|
||
},
|
||
"parallax": {
|
||
"type": "boolean",
|
||
"label": "Parallax motion",
|
||
"default": true
|
||
},
|
||
"birthdays": {
|
||
"type": "switch",
|
||
"label": "Birthday confetti",
|
||
"default": true,
|
||
"group": "Birthday"
|
||
},
|
||
"birthdayIntensity": {
|
||
"type": "select",
|
||
"label": "Intensity",
|
||
"default": "subtle",
|
||
"group": "Birthday",
|
||
"showWhen": "birthdays",
|
||
"options": [
|
||
{
|
||
"value": "subtle",
|
||
"label": "Subtle"
|
||
},
|
||
{
|
||
"value": "full",
|
||
"label": "Full"
|
||
}
|
||
]
|
||
},
|
||
"birthdayTest": {
|
||
"type": "select",
|
||
"label": "Force on (test)",
|
||
"default": "",
|
||
"group": "Birthday",
|
||
"showWhen": "birthdays",
|
||
"options": [
|
||
{
|
||
"value": "",
|
||
"label": "Off"
|
||
}
|
||
],
|
||
"optionsRoute": "/people"
|
||
}
|
||
}
|
||
}
|