Public
Edited
Feb 11, 2024
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
<style id ="preview-styles">
/*.mono-list {
list-style-type: none;
font-family: 'Roboto', Monospace;
font-weight: normal;
margin-bottom: 5px;
} */
.cubit-container {
position: relative;
width: 400px; /* Specify the width */
height: 200px; /* Specify the height */
/* border: 1px solid black; */
}

.corner {
font-family: 'Roboto', Monospace;
color: silver;
position: absolute;
width: 77px;
height: 77px;
/* border: 1px solid red; */
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 5px;
box-sizing: border-box;
}
.top-left {
top: 0;
left: 0;
}
.top-right {
top: 0;
right: 0;
}
.bottom-left {
bottom: 0;
left: 0;
}
.bottom-right {
bottom: 0;
right: 0;
}
.stat {
font-size: 24px;
font-weight: bold;
}
.sub-txt {
font-size: 14px;
text-align: center;
}

</style>
<h1>Preview Your Value Blocks</h1>
<p class="line">Daily Journal Entries for <span class="for-txt">${journalData.defaultCreators.join(',')}</span></p>
<div class="cubit-container">
<svg id="cubit" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="block" class="cube-unit">
<rect width="21" height="24" fill="var(--left)" stroke="var(--stroke)" transform="skewY(30)"/>
<rect width="21" height="24" fill="var(--right)" stroke="var(--stroke)" transform="skewY(-30) translate(21 24.3)"/>
<rect width="21" height="21" fill="var(--top)" stroke="var(--stroke)" transform="scale(1.41,.81) rotate(45) translate(0 -21)"/>
</g>
</defs>
<g id="daily-cubit" transform='translate(50 -25)'>
<use class="emj-clr-7" href="#block" x="121" y="112"></use>
<use class="emj-clr-5" href="#block" x="142" y="124"></use>
<use class="emj-clr-1" href="#block" x="163" y="136"></use>
<use class="emj-clr-4" href="#block" x="100" y="124"></use>
</g>
</svg>
<div class="corner top-left">
<div class="stat">+${journalData.statsSummary.totalBlocks}</div>
<div class="sub-txt">Value Blocks</div>
</div>
<div class="corner top-right">
<div class="stat">${journalData.statsSummary.totalBlocks*100}</div>
<div class="sub-txt">$ Value</div>
</div>
<div class="corner bottom-left">
<div class="stat">${journalData.statsSummary.totalBlocks*10}</div>
<div class="sub-txt">Gratitude Required</div>
</div>
<div class="corner bottom-right">
<div class="stat">+${journalData.statsSummary.totalBlocks*100}</div>
<div class="sub-txt">Gratitude Reward</div>
</div>
</div>
<br>
<p class="line" id="journalDate"> <b>${journalData.date}</b></p>
<ul id="blocksPreview">
<p class="line">⬜️ good nights rest 😴 |Hlth| {VTL} </p>
<p class="line">🟪 nourishing bfast 😋 |Hlth| {VTL} </p>
<p class="line">🟧 bachelorette planning 🥳 |Fun|(Sa)</p>
<p class="line">🟦 laundry & dishes 🧺🧼 |Joy|</p>
<p class="line"> 🟧🟧🟧🟧🟧 Coded HTML / CSS / JS 👨🏻‍💻
<span class="frame-txt">Better Economy</span>
<span class="for-txt sm">Lindsay</span>
<span class="group-txt sm">Economy Pilot</span>
<span class="blc-type sm">Doing</span>
<span class="details sm">Lots of extra details about why this block is so amazing here. It is really very cool and it is worth sharing with the world. </span>
</p>
<p class="line"> 🟩🟩🟩 Coded HTML / CSS / JS 👨🏻‍💻
<span class="frame-txt">Better Economy</span>
<span class="for-txt sm">L,B</span>
<span class="group-txt sm">Economy Pilot</span>
<span class="blc-type sm">Doing</span>
<span class="details sm">Lots of extra details about why this block is so amazing here. It is really very cool and it is worth sharing with the world. </span>
</p>
</ul>
<p class="line"><b> More Details: </b></p>
<ul>
<p class="line"> Story: ${journalData.emojiStory} </p>
<p class="line"> Frames: ${journalData.statsSummary.frames} </p>
<p class="line"> Groups: ${journalData.statsSummary.groups} </p>
</ul>
Insert cell
Insert cell
Insert cell
blocksHtml = {

let entries = reassemble //journalData.blockRecords
let cubit = journalData.blockIdx
let blcEmjClasses = emojiBlocksIndex.map(c => c.clrClass)
// Get the container elements
let ul = document.getElementById('blocksPreview')
let g = document.getElementById('daily-cubit')
//let style = document.getElementById('preview-styles')

let entriesHTML = entries.map(row => {

let frame = `<span class="frame-txt">${row.labels.frame}</span>`
let forWho = row.labels.forWho ? `<span class="for-txt sm">${row.labels.forWho}</span>` : ''
var group = row.labels.group ? `<span class="group-txt sm">${row.labels.group}</span>` : ''
let type = `<span class="blc-type sm">Doing</span>`
let details = row.details ? `<span class="details sm">${row.details}</span>` : ''

return `<p class="line"> ${row.main}
${frame}
${forWho}
${group}
${details}
</p>`
})


// Write over or Clear the existing lists
ul.innerHTML = entriesHTML.join('')
g.innerHTML = ''

// Create and append <use> elements based on the data array
cubit.forEach((blc, idx) => {
let use = document.createElement('use');
let classStrg = "emj-clr-" + blc.emojiIdx
use.setAttribute('class', classStrg);
use.setAttribute('href', '#block');
use.setAttribute('x', blc.cubitX);
use.setAttribute('y', blc.cubitY);
g.appendChild(use);
});

const svgElement = document.getElementById('cubit'); // Get the SVG element by ID

// Modify the innerHTML to trigger a redraw
svgElement.innerHTML = svgElement.innerHTML;

// Option #2 - Probably best for Email HTML

let htmlList = entries.map(item => {
return `<li class="mono-list">${item.main}</li>`
})

return {svgHtml: svgElement.innerHTML} //{htmlList}
}
Insert cell
reassemble = {

let parsed = journalData.parsed

let rendered = parsed.map(row => {
let blocks = row.blocks.raw.join('')
let words = row.text
let emojis = row.vibes

let main = blocks + " " + words + " " + emojis


let frame = row.frame
let forWho = row.who ? row.who.join(',') : null
let group = row.group
// let type = row.type
let labels = {frame, forWho, group}

let details = row.details

return {main, labels, details}
})

return rendered
}
Insert cell
Insert cell
journalData = {

// find indexOf():
// 1st "(" and optional 2nd "("
// 1st ")" and optional 2nd ")"
// 1st "|" and 2nd "|"
// 1st "{"
// 1st "}"

if(pastedBlockJournal){

var pastedDay = pastedBlockJournal
} else {
// Initial Sample Data
var pastedDay = `(B,L) May 27, 2023

🟦🟦 Quality Sleep 🛌 |Hlth| [ce]

🟪🟪 Eating Vegan 🌱 |Veg| [ce]

🟪🟪 Car Free🚶🏻‍♀️🚶🏻‍♂️|Eco| [ce]

🟪🟪 Minimalism 🪷|Simp| [ce]

🟩 Beach Medi (L) 🧘🏻‍♀️🏝 |Peac|:: Touched my inner self and found peace

🟩🟩 Morning Walk🚶🏻‍♀️🌹|Mov|:: Beautiful AM walk where we stopped and smelled the roses

🟨 Breakfast (L) 🍊🌮 |Hlth|

🟧🟧 Notes / Draw (B) 📘✍🏼 |+E|{EP1}

🟨 Online Groceries (L) 🛒🌭 |+L|

🟪 Beach Social (L) 🌊🌞|Scl|(Jl,Jy)

🟧 Roots of Old Game (B) 📝 |+E|{EP1}

🟧 Chat with GPT (B) 🔬🧫|+E|{EP1}

🟨 Dinner (L) 🍝 |Hlth|

🟩🟩 Streaming 📺 |Play|`

}

let blockRecords = pastedDay.split('\n').filter(line => line != "");

let lineOne = blockRecords.shift()
let lineOneLeftParIdx1 = lineOne.indexOf("(");

if(lineOneLeftParIdx1 == 0){
let lineOneRightParIdx1 = lineOne.indexOf(")");
var defaultCreators = lineOne.slice(lineOneLeftParIdx1 + 1, lineOneRightParIdx1).trim().split(",");
var date = lineOne.split(")")[1].trim()
var parsedDate = new Date(date)
} else {
var date = lineOne
var defaultCreators = null
}

var regex = /<a?:.+?:\d{18}>|\p{Extended_Pictographic}/gu; // /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;

var blocksIndex = []

// blocks, text, creators, vibes, frame, who, group, type, details

let parsed = blockRecords.map((row, idx) => {
let blockEntry = row

let firstLeftParIdx = blockEntry.indexOf("("); // returns -1 if none found
let closingLeftParIdx = blockEntry.indexOf("(", firstLeftParIdx + 1)
let openFrameIdx1 = blockEntry.indexOf("|");
let closeFrameIdx1 = blockEntry.indexOf("|", openFrameIdx1 + 1)
let finalFrameIdx = blockEntry.lastIndexOf("|")

let debug = {} // add debug info as needed

// blocks
let parts = row.split(" ")
let raw = parts.shift().match(regex)
blocksIndex.push(raw)
let qty = raw.length
let blocks = {raw, qty}
// text
let textStartPos = qty*2
let afterBlocks = blockEntry.slice(textStartPos)
let fistEmojiIdx = afterBlocks.search(regex) - 1

debug.firstEmjoiIdx = fistEmojiIdx
let startFrameIdx = afterBlocks.indexOf("|")
let startGroupIdx = afterBlocks.indexOf("{")
let nextBreakIdx
if(startGroupIdx && startGroupIdx < startFrameIdx){
// group "{" comes before frame "|"
nextBreakIdx = startGroupIdx
} else {
// typical break is at frame "|"
nextBreakIdx = startFrameIdx
}
debug.nextBreakIdx = nextBreakIdx
let textEndPos
let beginVibes
if(firstLeftParIdx == -1 || firstLeftParIdx > openFrameIdx1){
// use "emoji" break or "|" break
if(fistEmojiIdx > 0){
textEndPos = fistEmojiIdx + 1
beginVibes = textEndPos - 1
} else {
textEndPos = startFrameIdx
}
} else {
// use "(" break
textEndPos = afterBlocks.indexOf("(");
beginVibes = afterBlocks.indexOf(")");
}
let text = afterBlocks.slice(0, textEndPos).trim();

// vibes
let vibes = beginVibes ? afterBlocks.slice(beginVibes + 1, startFrameIdx).trim() : '' // .match(regex);
// creators
let leftParIdx1 = blockEntry.indexOf("(");
let rightParIdx1 = blockEntry.indexOf(")");
let creators
if(firstLeftParIdx == -1 || firstLeftParIdx > openFrameIdx1){
// use defaultCreator
creators = defaultCreators
} else {
creators = blockEntry.slice(leftParIdx1 + 1, rightParIdx1).trim().split(",");
}
// frame
let frame = blockEntry.slice(openFrameIdx1 + 1, closeFrameIdx1).trim();
// who
let afterFrame = blockEntry.slice(finalFrameIdx)
let leftParIdx2 = afterFrame.lastIndexOf("(");
let who
if(leftParIdx2 == -1){
// use defaultCreator
if(defaultCreators){
who = null
} else {
who = creators
}
} else {
let rightParIdx2 = afterFrame.lastIndexOf(")");
who = afterFrame.slice(leftParIdx2 + 1, rightParIdx2).trim().split(",");
}
// group
let leftCurlIdx = blockEntry.indexOf("{");
if(leftCurlIdx != -1){
let rightCurlIdx = blockEntry.indexOf("}");
var group = blockEntry.slice(leftCurlIdx + 1, rightCurlIdx).trim() //.split(",");
} else {
var group = null
}

// type
let leftSqrIdx = blockEntry.indexOf("[");
if(leftSqrIdx != -1){
let rightSqrIdx = blockEntry.indexOf("]");
var type = blockEntry.slice(leftSqrIdx + 1, rightSqrIdx).trim() //.split(",");
} else {
var type = null
}

// details
let details = blockEntry.split("::")
if(details.length == 2){
details = details[1].trim()
} else {
details = null
}
return {blocks, text, debug, creators, vibes, frame, who, group, type, details}

})

let processed = parsed.map((row, idx) => {

// add "Date" and "ID"

let creatorSplit = row.creators.map(creator => {

let qtyCreators = row.creators.length
let qtyBlocks = row.blocks.qty
let counts = {qtyCreators, qtyBlocks} // only return during debugging

let id = nanoid()
let blocks = Math.ceil(qtyBlocks/qtyCreators) // round up on any partial block division
let text = row.text
let vibes = row.vibes
let frame = row.frame
let who = row.who
let group = row.group
let type = row.type
let details = row.details

return {id, blocks, text, creator, vibes, frame, who, group, type, details}
})

return creatorSplit
}).flat()

// Block Index for Colored 3D Cubes

let flatBlockIdx = blocksIndex.flat()
let blockIdx = flatBlockIdx.map((blc,idx) => {
let hexCode = blc.codePointAt(0).toString(16)
let emojiIdx = emojiBlocksIndex.findIndex(obj => obj.hexCode === hexCode)
let cubitX = cubitPositions[idx].x
let cubitY = cubitPositions[idx].y
return {blc, hexCode, emojiIdx, cubitX, cubitY}
})

// Emoji Day Story

let emojiStory = (parsed.map(e => e.vibes)).join('')

// Stats

let uniqueCreators = Array.from(new Set(processed.map(obj => obj.creator)));


// Calculate stats summary
let statsSummary = processed.reduce((summary, obj) => {
const { creator, group, color, frame, /*type,*/ blocks } = obj;
summary.totalBlocks += blocks;
summary.creators[creator] = (summary.creators[creator] || 0) + blocks;
summary.groups[group] = (summary.groups[group] || 0) + blocks;
// summary.colors[color] = (summary.colors[color] || 0) + blocks;
summary.frames[frame] = (summary.frames[frame] || 0) + blocks;
// summary.types[type] = (summary.types[type] || 0) + blocks;
return summary;
}, {
totalBlocks: 0,
creators: {},
groups: {},
// colors: {},
frames: {},
// types: {}
});


return {date, parsedDate, defaultCreators, blockRecords, blockIdx, parsed, processed, emojiStory, uniqueCreators, statsSummary}

}
Insert cell
//serverTestResp = (await fetch("https://5c02-75-223-154-16.ngrok-free.app")).text()
Insert cell
function swatches(colors) {
return html`${colors.map(c => `<div title="${c}" style="
display: inline-block;
margin-right: 3px;
width: 33px;
height: 33px;
background: ${c};
"></div>`)}`;
}
Insert cell
tinycolor = require('tinycolor2')
Insert cell
emojiBlocksIndex = {

let emojiList = ["🟥", "🟧", "🟨", "🟩", "🟦", "🟪", "⬛️", "⬜️", "🟫"]
let colors = ["red", "darkorange", "gold", "forestgreen", "blue", "darkviolet", "black", "silver", "saddlebrown"]
let colorCodes = ["RED", "ORNG", "YLW", "GRN", "BLU", "PRPL", "BLK", "SLV", "BRN"]

let objList = emojiList.map((emoji, idx) => {
let color = colors[idx]
let hexColor = tinycolor(color).toHexString()
let colorCode = colorCodes[idx]
let hexCode = emoji.codePointAt(0).toString(16)
// let reDraw = String.fromCodePoint("0x"+hexCode);

let l10 = tinycolor(color).lighten(10).toString()
let l20 = tinycolor(color).lighten(20).toString()
let l30 = tinycolor(color).lighten(30).toString()

let cbHxClrs = [l30, l20, l10, hexColor]

let clrClass = `.emj-clr-${idx}{--right: ${cbHxClrs[0]}; --top: ${cbHxClrs[1]}; --left: ${cbHxClrs[2]}; --stroke: ${cbHxClrs[3]};}`
return {emoji, color, hexColor, colorCode, hexCode, cbHxClrs, clrClass}
})

return objList
}
Insert cell
emojiColors3D = {
return swatches([].concat(...(emojiBlocksIndex.map(c => c.cbHxClrs))))
}
Insert cell
emjBlckClasses = {
let blcEmjClasses = emojiBlocksIndex.map(c => c.clrClass)
let cssClasses = blcEmjClasses.join('\n')
return html`<style>${cssClasses}</style>`
}
Insert cell
Insert cell
tinyColorPallet = {
let tcArray = Object.values(tcColorNames)
let hex = tcArray.map(c => '#' + c)
return swatches(hex)
}
Insert cell
<style>

.line {
font-family: "Roboto", Monospace; /* Specify the font family */
margin: 0; /* Reset default margin */
line-height: 1.2; /* Adjust the line spacing */
font-size: 17px;
margin-bottom: 8px;
}

.sm {
font-size: 17px;
}

.frame-txt {
display: inline-block;
padding: 2px 9px;
border: 1px solid silver;
}

.for-txt {
display: inline-block;
padding: 4px 9px;
background-color: whitesmoke; /* Set your desired background color */
color: grey; /* Set the text color */
border-radius: 30px; /* Adjust the border-radius to control the roundness */
}

.group-txt {
display: inline-block;
padding: 2px 9px;
border: 1px solid silver;
color: grey;
border-radius: 30px;
}

.blc-type {
display: inline-block;
padding: 3px 9px;
color: grey;
background-color: whitesmoke; /* Set your desired background color */
}

.details {
color: silver
}

</style>
<p class="line"> 🟧🟧🟧🟧🟧 Coded HTML / CSS / JS 👨🏻‍💻
<span class="frame-txt">Better Economy</span>
<span class="for-txt sm">Lindsay</span>
<span class="group-txt sm">Economy Pilot</span>
<span class="blc-type sm">Doing</span>
<span class="details sm">Lots of extra details about why this block is so amazing here. It is really very cool and it is worth sharing with the world. </span>
</p>
Insert cell
<style>

.toggle {
--width: 40px;
--height: calc(var(--width) / 2);
--border-radius: calc(var(--height) / 2);
display: inline-block;
cursor: pointer;
}

.toggle-input {
display: none;
}

.toggle-details {
display: none;
}

.toggle-fill {
position: relative;
width: var(--width);
height: var(--height);
border-radius: var(--border-radius);
background: #dddddd;
transition: background 0.2s;
}

.toggle-fill::after {
content: "";
position: absolute;
top: 0;
left: 0;
height: var(--height);
width: var(--height);
background: #ffffff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);
border-radius: var(--border-radius);
transition: transform 0.2s;
}

.toggle-input:checked ~ .toggle-fill {
background: yellowgreen;
}
.toggle-input:checked ~ .toggle-fill::after {
transform: translateX(var(--height));
}

.toggle-input:checked ~ .toggle-details {
display: block;
}
</style>

<label class="toggle" for="myToggle">
<input class="toggle-input" name="" type="checkbox" id="myToggle">
<div class="toggle-fill"></div>
<p class="toggle-details"> Some extra words </p>
<p> Other text </p>
</label>
Insert cell
blockCoords = (row, lane, stack) => {

// from input sliders for debug only
// let row = rowPosition
// let stack = stackPosition
// let lane = lanePosition

// Offsets for optimal position testing

// We can update the relative viewport x, y starting block coordinates for optimal placement
let xRef = 121 // 121 // 10
let yRef = 112 // 112 // 100

// each "day" represents a column position in a lane (week) (0 to 6, 1 to 7)
let xAdjRow = - row * 21 // decreasing steps of 21
let yAdjRow = row * 12 // increasing steps of 12

// each new block is "stacked" per day, so we can call that "stack position" (0 to 26, 1 to 27)
let yAdjStack = - stack * 24

// each week is a lane position (0 to 51, 1 to 52)

let xAdjLane = lane * 21
let yAdjLane = lane * 12

let xPosition = xRef + xAdjRow + xAdjLane
let yPosition = yRef + yAdjRow + yAdjStack + yAdjLane

return {x: xPosition, y: yPosition}
}
Insert cell
cubitPositions = {
let size = 3; // Size of the Cubit (3x3x3)
let blocks = [];
for (let stack = 1; stack <= size; stack++) {
for (let row = 1; row <= size; row++) {
for (let lane = 1; lane <= size; lane++) {
blocks.push({ row, lane, stack });
}
}
}

blocks.forEach((b,idx) => {
let coords = blockCoords(b.row, b.lane, b.stack)
blocks[idx].x = coords.x
blocks[idx].y = coords.y
})
return blocks
}
Insert cell
nanoid = (await import('nanoid/nanoid.js')).nanoid //.then(module => module.nanoid)
Insert cell
dateObj = {
let dateString = "December 17, 2023"
let localTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone
// Parse the date string (assuming the format is recognized)
let parsedDate = new Date(dateString)
// Format the date for display in the user's time zone
let localDate = parsedDate.toLocaleString('en-US', { weekday: "short",
month: "short",
year: "numeric",
day: "numeric",
// hour: "numeric",
// minute: "numeric",
timeZoneName: "short",
timeZone: localTimeZone
});

return {dateString, localTimeZone, parsedDate, localDate}
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more