diff --git a/demos/stefan/untitled-board-game/ubg-card.js b/demos/stefan/untitled-board-game/ubg-card.js index ddedd001b..648376c62 100644 --- a/demos/stefan/untitled-board-game/ubg-card.js +++ b/demos/stefan/untitled-board-game/ubg-card.js @@ -39,15 +39,6 @@ export default class Card { } } -// getType() { -// return this.versions.last.type; -// } - -// setType(type) { -// this.ensureUnprintedVersion(); -// this.versions.last.type = type; -// } - getTypes() { const type = this.versions.last.type; diff --git a/src/components/widgets/ubg-card.js b/src/components/widgets/ubg-card.js index fdc0150f9..a36db2d69 100644 --- a/src/components/widgets/ubg-card.js +++ b/src/components/widgets/ubg-card.js @@ -52,7 +52,13 @@ class FileCache { this.files = {}; } - dirtyFolder(path) {} + dirtyFolder(folderPath) { + for (const filePath in this.files) { + if (filePath.startsWith(folderPath)) { + delete this.files[filePath]; + } + } + } getFile(path, callback) { if (this.files[path]) { @@ -89,7 +95,9 @@ export default class UbgCard extends Morph { /*MD ## Build MD*/ async fetchAssetsInfo() { - return (await this.assetsFolder.fetchStats()).contents; + return globalThis.__ubg_file_cache__.getFile(this.assetsFolder, async url => { + return (await url.fetchStats()).contents; + }) } /*MD ## Extract Card Info MD*/ @@ -245,12 +253,14 @@ background: ${color}; } async loadImage(filePath) { - return new Promise((resolve, reject) => { - const image = new Image(); - image.addEventListener('load', resolve); - image.addEventListener('error', reject); - image.src = filePath; - }); + return globalThis.__ubg_file_cache__.getFile(filePath, filePath => { + return new Promise((resolve, reject) => { + const image = new Image(); + image.addEventListener('load', resolve); + image.addEventListener('error', reject); + image.src = filePath; + }); + }) } /*MD ## Rendering MD*/ diff --git a/src/components/widgets/ubg-cards.js b/src/components/widgets/ubg-cards.js index 33656fea1..e92529c8f 100644 --- a/src/components/widgets/ubg-cards.js +++ b/src/components/widgets/ubg-cards.js @@ -4,7 +4,6 @@ import Morph from 'src/components/widgets/lively-morph.js'; import ContextMenu from 'src/client/contextmenu.js'; import "src/external/pdf.js"; import { shake } from 'utils'; -import { Point } from 'src/client/graphics.js' import OpenAI from "demos/openai/openai.js" @@ -12,7 +11,7 @@ import d3 from 'https://d3js.org/d3.v7.min.js' import { uuid, without, getTempKeyFor, getObjectFor, flatMap, listAsDragImage } from 'utils'; -import paper from 'src/client/paperjs-wrapper.js' +// import paper from 'src/client/paperjs-wrapper.js' import 'https://lively-kernel.org/lively4/ubg-assets/load-assets.js'; import { querySelectorAllDeep } from 'src/external/querySelectorDeep/querySelectorDeep.js'; @@ -31,245 +30,128 @@ function identity(value) { return value; } -const fire = ; -const water = ; -const earth = ; -const wind = ; -const gray = ; -const question = ; - -class PathDataScaleCache { - static getPathData(element, size = lively.pt(10, 10)) { - if (!this.cache) { - this.cache = {} - } +// const fire = ; +// const water = ; +// const earth = ; +// const wind = ; +// const gray = ; +// const question = ; + +// class PathDataScaleCache { +// static getPathData(element, size = lively.pt(10, 10)) { +// if (!this.cache) { +// this.cache = {} +// } - const key = `${element}-${size.x}-${size.y}`; - if (!this.cache[key]) { - // lively.notify(`${element}-${size.x}-${size.y}`, 'cache miss') - this.cache[key] = this._scalePathData(element, size) - } +// const key = `${element}-${size.x}-${size.y}`; +// if (!this.cache[key]) { +// // lively.notify(`${element}-${size.x}-${size.y}`, 'cache miss') +// this.cache[key] = this._scalePathData(element, size) +// } - return this.cache[key] - } - - static _scalePathData(element, size) { - const { glyph } = forElement(element); - const path = new paper.Path(glyph.getAttribute('d')); - - path.scale(1, -1); - - const margin = size.scaleBy(0.1); - const boundingRect = new paper.Path.Rectangle({ - point: margin.toPair(), - size: size.subPt(margin.scaleBy(2)).toPair() - }); - path.fitBounds(boundingRect.bounds); - - return path.pathData; - } -} - -function tenTenPathData(element) { - return PathDataScaleCache.getPathData(element, lively.pt(10, 10)); -} - -const elementInfo = { - fire: { - name: 'fire', - faIcon: 'book', - glyph: fire, - get pathData() { return tenTenPathData('fire') }, - pathWidth: parseInt(fire.getAttribute('horiz-adv-x')), - pathHeight: parseInt(fire.getAttribute('vert-adv-y')), - fill: '#ffbbbb', - stroke: '#ff0000', - others: ['water', 'earth', 'wind'] - }, - water: { - name: 'water', - faIcon: 'droplet', - glyph: water, - get pathData() { return tenTenPathData('water') }, - pathWidth: parseInt(water.getAttribute('horiz-adv-x')), - pathHeight: parseInt(water.getAttribute('vert-adv-y')), - fill: '#8888ff', - stroke: '#0000ff', - others: ['fire', 'earth', 'wind'] - }, - earth: { - name: 'earth', - faIcon: 'mountain', - glyph: earth, - get pathData() { return tenTenPathData('earth') }, - pathWidth: parseInt(earth.getAttribute('horiz-adv-x')), - pathHeight: parseInt(earth.getAttribute('vert-adv-y')), - fill: 'rgb(255, 255, 183)', - stroke: '#ffd400', - others: ['fire', 'water', 'wind'] - }, - wind: { - name: 'wind', - faIcon: 'cloud', - glyph: wind, - get pathData() { return tenTenPathData('wind') }, - pathWidth: parseInt(wind.getAttribute('horiz-adv-x')), - pathHeight: parseInt(wind.getAttribute('vert-adv-y')), - fill: '#bbffbb', - stroke: '#00ff00', - others: ['fire', 'water', 'earth'] - }, - gray: { - name: 'gray', - faIcon: 'circle', - glyph: gray, - get pathData() { return tenTenPathData('gray') }, - pathWidth: parseInt(gray.getAttribute('horiz-adv-x')), - pathHeight: parseInt(gray.getAttribute('vert-adv-y')), - fill: '#dddddd', - stroke: '#5A5A5A', - others: ['gray', 'gray', 'gray'] - }, - unknown: { - name: 'unknown', - faIcon: 'question', - glyph: question, - get pathData() { return tenTenPathData('question') }, - pathWidth: parseInt(question.getAttribute('horiz-adv-x')), - pathHeight: parseInt(question.getAttribute('vert-adv-y')), - fill: 'pink', - stroke: 'violet', - others: ['question', 'question', 'question'] - } -}; - -function forElement(element) { - const cleanElement = (element || '').toLowerCase(); - return elementInfo[cleanElement] || elementInfo.unknown; -} - -class SVG { - - static inlineSVG(children, bounds = lively.rect(0, 0, 10, 10), attrs = '', style = '') { - return `${children}`; - } - - /*MD ## Basic Shapes MD*/ - static circleRing(center, innerRadius, outerRadius, attrs) { - return `` - } - - static circle(center, radius, attrs) { - return `` - } - - /*MD ## Icons MD*/ - static elementGlyph(element, center, radius, attrs) { - const pathData = PathDataScaleCache.getPathData(element, lively.pt(2 * radius, 2 * radius)); - return `` - } - - static elementSymbol(element, center, radius) { - const { name: elementName, fill, stroke } = forElement(element); - const innerRadius = .9 * radius; - return `${SVG.circle(center, innerRadius, `fill="${fill}"`)} -${SVG.elementGlyph(elementName, center, innerRadius, `fill="${stroke}"`)} - ${SVG.circleRing(center, innerRadius, radius, `fill="${stroke}"`)}` - } -} - -const castIcon = do { - const size = 100; - const bounds = lively.rect(0, 0, size, size) - const innerBounds = bounds.insetBy(5); - - const innerRadius = innerBounds.width / 2; - const outerCircle = SVG.circleRing(bounds.center(), innerRadius, bounds.width / 2, `fill="#7A7A7A"`); - - const sqrt2 = 2**.5 - const radius = innerRadius * 1 / (sqrt2 + 1); - const distToMiddle = innerRadius * sqrt2 / (sqrt2 + 1); - const elements = ['water', 'earth', 'fire', 'wind']; - const mainElements = elements.map((element, i) => { - const center = bounds.center().addPt(Point.polar(distToMiddle, Math.PI / 2 * i)); - return SVG.elementSymbol(element, center, radius) - }).join('\n'); - - SVG.inlineSVG(`${outerCircle} -${mainElements}`, bounds); -} - - -function previewSVG(svg) { - const hedronTemp = document.getElementById(svg.id) - if (hedronTemp) { - hedronTemp.remove() - } - document.body.insertAdjacentHTML("afterbegin", svg.outerHTML) -} - - -function rectToViewBox(rect) { - return `${rect.x} ${rect.y} ${rect.width} ${rect.height}` -} - - -const CARD_COST_VIEWBOX = lively.rect(0, 0, 376, 326); -const cardCostTwoSVG = do { - const C_OUTER = 'rgb(243, 243, 243)' - const C_INNER = 'rgb(129, 129, 129)' - const C_TOP = 'rgb(162, 165, 168)' - const C_IMAGE = 'rgb(148, 147, 152)' - const C_BOTTOM = C_TOP; +// return this.cache[key] +// } - const svg = ( - - - - - - - -); -svg -}; - -// previewSVG(cardCostTwoSVG) - -class FileCache { - - constructor() { - this.files = {}; - } - - dirtyFolder(path) {} - - getFile(path, callback) { - if (this.files[path]) { - // lively.notify('cache hit') - } else { - // lively.notify('cache miss') - this.files[path] = callback(path); - } - - return this.files[path]; - } - -} - -if (globalThis.__ubg_file_cache__) { - globalThis.__ubg_file_cache__.migrateTo(FileCache); -} else { - globalThis.__ubg_file_cache__ = new FileCache(); -} +// static _scalePathData(element, size) { +// const { glyph } = forElement(element); +// const path = new paper.Path(glyph.getAttribute('d')); + +// path.scale(1, -1); + +// const margin = size.scaleBy(0.1); +// const boundingRect = new paper.Path.Rectangle({ +// point: margin.toPair(), +// size: size.subPt(margin.scaleBy(2)).toPair() +// }); +// path.fitBounds(boundingRect.bounds); + +// return path.pathData; +// } +// } + +// function tenTenPathData(element) { +// return PathDataScaleCache.getPathData(element, lively.pt(10, 10)); +// } + +// const elementInfo = { +// fire: { +// name: 'fire', +// faIcon: 'book', +// glyph: fire, +// get pathData() { return tenTenPathData('fire') }, +// pathWidth: parseInt(fire.getAttribute('horiz-adv-x')), +// pathHeight: parseInt(fire.getAttribute('vert-adv-y')), +// fill: '#ffbbbb', +// stroke: '#ff0000', +// others: ['water', 'earth', 'wind'] +// }, +// water: { +// name: 'water', +// faIcon: 'droplet', +// glyph: water, +// get pathData() { return tenTenPathData('water') }, +// pathWidth: parseInt(water.getAttribute('horiz-adv-x')), +// pathHeight: parseInt(water.getAttribute('vert-adv-y')), +// fill: '#8888ff', +// stroke: '#0000ff', +// others: ['fire', 'earth', 'wind'] +// }, +// earth: { +// name: 'earth', +// faIcon: 'mountain', +// glyph: earth, +// get pathData() { return tenTenPathData('earth') }, +// pathWidth: parseInt(earth.getAttribute('horiz-adv-x')), +// pathHeight: parseInt(earth.getAttribute('vert-adv-y')), +// fill: 'rgb(255, 255, 183)', +// stroke: '#ffd400', +// others: ['fire', 'water', 'wind'] +// }, +// wind: { +// name: 'wind', +// faIcon: 'cloud', +// glyph: wind, +// get pathData() { return tenTenPathData('wind') }, +// pathWidth: parseInt(wind.getAttribute('horiz-adv-x')), +// pathHeight: parseInt(wind.getAttribute('vert-adv-y')), +// fill: '#bbffbb', +// stroke: '#00ff00', +// others: ['fire', 'water', 'earth'] +// }, +// gray: { +// name: 'gray', +// faIcon: 'circle', +// glyph: gray, +// get pathData() { return tenTenPathData('gray') }, +// pathWidth: parseInt(gray.getAttribute('horiz-adv-x')), +// pathHeight: parseInt(gray.getAttribute('vert-adv-y')), +// fill: '#dddddd', +// stroke: '#5A5A5A', +// others: ['gray', 'gray', 'gray'] +// }, +// unknown: { +// name: 'unknown', +// faIcon: 'question', +// glyph: question, +// get pathData() { return tenTenPathData('question') }, +// pathWidth: parseInt(question.getAttribute('horiz-adv-x')), +// pathHeight: parseInt(question.getAttribute('vert-adv-y')), +// fill: 'pink', +// stroke: 'violet', +// others: ['question', 'question', 'question'] +// } +// }; + +// function forElement(element) { +// const cleanElement = (element || '').toLowerCase(); +// return elementInfo[cleanElement] || elementInfo.unknown; +// } const SORT_BY = { ID: 'id', NAME: 'name' }; -const OUTSIDE_BORDER_ROUNDING = lively.pt(3, 3) - export default class Cards extends Morph { async initialize() { this.setAttribute("exportparts", 'danger'); @@ -379,7 +261,7 @@ export default class Cards extends Morph { return function filterFunction(card) { const id = card.getId(); const name = card.getName(); - const cardType = card.getType() + const cardType = card.getTypes() const element = card.getElement(); const cost = card.getCost(); const text = card.getText(); @@ -1239,7 +1121,7 @@ export default class Cards extends Morph { if (that && that.localName === 'lively-code-mirror' && document.contains(that)) { lively.showElement(that) - const matches = that.value.matchAll(/^([^0-9]+)?\s([0-9]+)?\s?([a-zA-Z ]+)?\s?(?:\(([0-9,]+)(\+?\-?\*?)\))?(?:\s?([0-9*+-]+))?\.\s(.*)?$/gmi); + const matches = that.value.matchAll(/^([^0-9]+)?\s([0-9]+)?\s?((?:[a-zA-Z]+\s)*[a-zA-Z]+)?\s?(?:\(([0-9,]+)(\+?\-?\*?)\))?(?:\s?([0-9*+-]+))?\.\s(.*)?$/gmi); const newCards = [...matches].map(match => { const card = new Card(); @@ -1257,13 +1139,27 @@ export default class Cards extends Morph { const typesAndElements = match[3]; if (typesAndElements) { - let type = '' + const types = [] let element; match[3].split(' ').forEach(te => { if (!te) { return; } + if (['fire', 'water', 'earth', 'wind', 'gray', 'dark', 'void'].includes(te.toLowerCase())) { + if (!element) { + element = te + } else if (Array.isArray(element)) { + element.push(te) + } else { + element = [element, te] + } + + return + } + + // not an element, so it is a type + types.push(te) // Transmutation & Transformation // Flux, Shift, Metamorph @@ -1287,23 +1183,10 @@ export default class Cards extends Morph { // Hierarchies & Secret Orders // Order, Guild, Circle - - if (['gadget', 'character', 'spell'].includes(te.toLowerCase())) { - type += te - return - } - - if (!element) { - element = te - } else if (Array.isArray(element)) { - element.push(te) - } else { - element = [element, te] - } }) - if (type) { - card.setType(type) + if (types.length > 0) { + card.setTypes(types) } if (element) { @@ -1593,10 +1476,11 @@ export default class Cards extends Morph { evt.preventDefault(); const menu = new ContextMenu(this, [ - ["foo", () => { - lively.notify(123) - }], ["bar", () => { - lively.notify(456) + ["Clear Assets File Cache", () => { + globalThis.__ubg_file_cache__.dirtyFolder(this.assetsFolder) + lively.success(123) + }], ["...", () => { + lively.notify('More to come...') }] ]); menu.openIn(document.body, evt, this); diff --git a/src/components/widgets/ubg-rules-text.js b/src/components/widgets/ubg-rules-text.js index 9e79f5f24..5763c70f4 100644 --- a/src/components/widgets/ubg-rules-text.js +++ b/src/components/widgets/ubg-rules-text.js @@ -361,34 +361,6 @@ const cardCostTwoSVG = do { svg }; - -class FileCache { - - constructor() { - this.files = {}; - } - - dirtyFolder(path) {} - - getFile(path, callback) { - if (this.files[path]) { - // lively.notify('cache hit') - } else { - // lively.notify('cache miss') - this.files[path] = callback(path); - } - - return this.files[path]; - } - -} - -if (globalThis.__ubg_file_cache__) { - globalThis.__ubg_file_cache__.migrateTo(FileCache); -} else { - globalThis.__ubg_file_cache__ = new FileCache(); -} - const VP_FILL = 'violet'; const VP_STROKE = '#9400d3'; // darkviolet const VP_FILL_ZERO = '#ddd';