Replace boolean cell flags with CellType enum (event, title, continuation, gap, chain, signal)
This commit is contained in:
@@ -177,28 +177,28 @@ function render(data) {
|
|||||||
|
|
||||||
for (let r = 0; r < numRows; r++) {
|
for (let r = 0; r < numRows; r++) {
|
||||||
const cells = data.tracks.map(t => t.cells[r] || {});
|
const cells = data.tracks.map(t => t.cells[r] || {});
|
||||||
const hasCue = cells.some(c => c.block_id && c.event && (data.blocks[c.block_id] || {}).type === 'cue');
|
const hasCue = cells.some(c => (c.type === 'event' || c.type === 'signal') && c.block_id && (data.blocks[c.block_id] || {}).type === 'cue');
|
||||||
const hasSignal = !hasCue && cells.some(c => c.event && c.is_signal);
|
const hasSignal = !hasCue && cells.some(c => c.type === 'signal');
|
||||||
const rowCls = hasCue ? ' cue-row' : (hasSignal ? ' sig-row' : '');
|
const rowCls = hasCue ? ' cue-row' : (hasSignal ? ' sig-row' : '');
|
||||||
|
|
||||||
cells.forEach((c, ti) => {
|
cells.forEach((c, ti) => {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.className = 'cell' + rowCls;
|
div.className = 'cell' + rowCls;
|
||||||
if (c.is_title) {
|
if (c.type === 'title') {
|
||||||
const block = data.blocks[c.block_id] || {};
|
const block = data.blocks[c.block_id] || {};
|
||||||
const loop = block.loop ? ' \u21A9' : '';
|
const loop = block.loop ? ' \u21A9' : '';
|
||||||
div.innerHTML = `<div class="block block-mid ${block.type || ''}"><div class="title">${block.name || ''}${loop}</div></div>`;
|
div.innerHTML = `<div class="block block-mid ${block.type || ''}"><div class="title">${block.name || ''}${loop}</div></div>`;
|
||||||
} else if (c.is_chain) {
|
} else if (c.type === 'chain') {
|
||||||
const nextCell = data.tracks[ti]?.cells[r+1] || {};
|
const nextCell = data.tracks[ti]?.cells[r+1] || {};
|
||||||
const sym = nextCell.is_start ? '\u2193' : '\u2502';
|
const sym = nextCell.event === 'START' ? '\u2193' : '\u2502';
|
||||||
div.innerHTML = `<div style="text-align:center;color:var(--fg-dim);font-size:14px;line-height:24px">${sym}</div>`;
|
div.innerHTML = `<div style="text-align:center;color:var(--fg-dim);font-size:14px;line-height:24px">${sym}</div>`;
|
||||||
} else if (c.block_id) {
|
} else if (c.type === 'event' || c.type === 'signal') {
|
||||||
const block = data.blocks[c.block_id] || {};
|
const block = data.blocks[c.block_id] || {};
|
||||||
const isInfinity = r === numRows - 1 && !c.is_end && !c.is_title;
|
const isInfinity = r === numRows - 1 && c.event !== 'END' && c.event !== 'GO';
|
||||||
let seg = 'mid';
|
let seg = 'mid';
|
||||||
if (c.is_start && c.is_end) seg = 'single';
|
if (c.event === 'GO') seg = 'single';
|
||||||
else if (c.is_start) seg = 'start';
|
else if (c.event === 'START') seg = 'start';
|
||||||
else if (c.is_end) seg = 'end';
|
else if (c.event === 'END') seg = 'end';
|
||||||
|
|
||||||
div.className += isInfinity ? ' infinity-cell' : '';
|
div.className += isInfinity ? ' infinity-cell' : '';
|
||||||
let inner = `<div class="block block-${seg} ${block.type || ''}">`;
|
let inner = `<div class="block block-${seg} ${block.type || ''}">`;
|
||||||
@@ -206,12 +206,15 @@ function render(data) {
|
|||||||
inner += `<div class="cue-label">${block.name || ''}</div>`;
|
inner += `<div class="cue-label">${block.name || ''}</div>`;
|
||||||
} else if (c.event) {
|
} else if (c.event) {
|
||||||
let hCls = 'hook';
|
let hCls = 'hook';
|
||||||
if (c.is_signal) hCls += ' sig';
|
if (c.type === 'signal') hCls += ' sig';
|
||||||
inner += `<div class="${hCls}">${c.event.replace('_', ' ')}</div>`;
|
inner += `<div class="${hCls}">${c.event.replace('_', ' ')}</div>`;
|
||||||
}
|
}
|
||||||
inner += `</div>`;
|
inner += `</div>`;
|
||||||
if (isInfinity) inner += `<div class="infinity-marker">∿∿∿</div>`;
|
if (isInfinity) inner += `<div class="infinity-marker">∿∿∿</div>`;
|
||||||
div.innerHTML = inner;
|
div.innerHTML = inner;
|
||||||
|
} else if (c.type === 'continuation') {
|
||||||
|
const block = data.blocks[c.block_id] || {};
|
||||||
|
div.innerHTML = `<div class="block block-mid ${block.type || ''}"></div>`;
|
||||||
}
|
}
|
||||||
timeline.appendChild(div);
|
timeline.appendChild(div);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,15 +20,21 @@ type Timeline struct {
|
|||||||
exclusives []exclusiveGroup `json:"-"`
|
exclusives []exclusiveGroup `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CellType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
CellEvent CellType = "event"
|
||||||
|
CellTitle CellType = "title"
|
||||||
|
CellContinuation CellType = "continuation"
|
||||||
|
CellGap CellType = "gap"
|
||||||
|
CellChain CellType = "chain"
|
||||||
|
CellSignal CellType = "signal"
|
||||||
|
)
|
||||||
|
|
||||||
type TimelineCell struct {
|
type TimelineCell struct {
|
||||||
|
Type CellType `json:"type"`
|
||||||
BlockID string `json:"block_id,omitempty"`
|
BlockID string `json:"block_id,omitempty"`
|
||||||
IsStart bool `json:"is_start,omitempty"`
|
|
||||||
IsEnd bool `json:"is_end,omitempty"`
|
|
||||||
Event string `json:"event,omitempty"`
|
Event string `json:"event,omitempty"`
|
||||||
IsTitle bool `json:"is_title,omitempty"`
|
|
||||||
IsSignal bool `json:"is_signal,omitempty"`
|
|
||||||
IsGap bool `json:"-"`
|
|
||||||
IsChain bool `json:"is_chain,omitempty"`
|
|
||||||
row int `json:"-"`
|
row int `json:"-"`
|
||||||
track *TimelineTrack `json:"-"`
|
track *TimelineTrack `json:"-"`
|
||||||
}
|
}
|
||||||
@@ -84,7 +90,7 @@ func (g exclusiveGroup) satisfied(tracks []*TimelineTrack) bool {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c := t.Cells[row]
|
c := t.Cells[row]
|
||||||
if c.IsGap || c.IsChain || c.BlockID == "" {
|
if c.Type != CellEvent && c.Type != CellTitle && c.Type != CellSignal {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -167,19 +173,18 @@ func (track *TimelineTrack) appendCells(cells ...*TimelineCell) {
|
|||||||
|
|
||||||
func getCueCells(block *Block) []*TimelineCell {
|
func getCueCells(block *Block) []*TimelineCell {
|
||||||
return []*TimelineCell{{
|
return []*TimelineCell{{
|
||||||
|
Type: CellEvent,
|
||||||
BlockID: block.ID,
|
BlockID: block.ID,
|
||||||
IsStart: true,
|
|
||||||
IsEnd: true,
|
|
||||||
Event: "GO",
|
Event: "GO",
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBlockCells(block *Block) []*TimelineCell {
|
func getBlockCells(block *Block) []*TimelineCell {
|
||||||
return []*TimelineCell{
|
return []*TimelineCell{
|
||||||
{BlockID: block.ID, IsStart: true, Event: "START"},
|
{Type: CellEvent, BlockID: block.ID, Event: "START"},
|
||||||
{BlockID: block.ID, IsTitle: true},
|
{Type: CellTitle, BlockID: block.ID},
|
||||||
{BlockID: block.ID, Event: "FADE_OUT"},
|
{Type: CellEvent, BlockID: block.ID, Event: "FADE_OUT"},
|
||||||
{BlockID: block.ID, IsEnd: true, Event: "END"},
|
{Type: CellEvent, BlockID: block.ID, Event: "END"},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,9 +219,9 @@ func (tl *Timeline) buildCells(endChains map[string]bool) {
|
|||||||
}
|
}
|
||||||
if block.Type != "cue" && lastOnTrack[block.Track] != block {
|
if block.Type != "cue" && lastOnTrack[block.Track] != block {
|
||||||
if endChains[block.ID] {
|
if endChains[block.ID] {
|
||||||
track.appendCells(&TimelineCell{IsChain: true})
|
track.appendCells(&TimelineCell{Type: CellChain})
|
||||||
} else {
|
} else {
|
||||||
track.appendCells(&TimelineCell{IsGap: true})
|
track.appendCells(&TimelineCell{Type: CellGap})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,7 +237,7 @@ func (tl *Timeline) buildConstraints() {
|
|||||||
t := tl.findCell(target.Block, target.Hook)
|
t := tl.findCell(target.Block, target.Hook)
|
||||||
if source.track != t.track {
|
if source.track != t.track {
|
||||||
tl.addConstraint("same_row", source, t)
|
tl.addConstraint("same_row", source, t)
|
||||||
source.IsSignal = true
|
source.Type = CellSignal
|
||||||
}
|
}
|
||||||
group.members = append(group.members, t)
|
group.members = append(group.members, t)
|
||||||
}
|
}
|
||||||
@@ -301,7 +306,7 @@ func (tl *Timeline) enforceExclusives() bool {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c := t.Cells[row]
|
c := t.Cells[row]
|
||||||
if c.IsGap || c.IsChain || c.BlockID == "" {
|
if c.Type != CellEvent && c.Type != CellTitle && c.Type != CellSignal {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tl.insertGap(t, row)
|
tl.insertGap(t, row)
|
||||||
@@ -320,11 +325,11 @@ func (tl *Timeline) isAllRemovableGapRow(row int, except *TimelineTrack) bool {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
c := t.Cells[row]
|
c := t.Cells[row]
|
||||||
if !c.IsGap && !c.IsChain {
|
if c.Type != CellGap && c.Type != CellChain && c.Type != CellContinuation {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
hasBefore := row > 0 && t.Cells[row-1].BlockID != "" && !t.Cells[row-1].IsGap && !t.Cells[row-1].IsChain
|
hasBefore := row > 0 && (t.Cells[row-1].Type == CellEvent || t.Cells[row-1].Type == CellTitle || t.Cells[row-1].Type == CellSignal)
|
||||||
hasAfter := row+1 < len(t.Cells) && t.Cells[row+1].BlockID != "" && !t.Cells[row+1].IsGap && !t.Cells[row+1].IsChain
|
hasAfter := row+1 < len(t.Cells) && (t.Cells[row+1].Type == CellEvent || t.Cells[row+1].Type == CellTitle || t.Cells[row+1].Type == CellSignal)
|
||||||
if hasBefore && hasAfter {
|
if hasBefore && hasAfter {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -358,10 +363,11 @@ func (tl *Timeline) insertGap(track *TimelineTrack, beforeIndex int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gap := &TimelineCell{IsGap: true, row: beforeIndex, track: track}
|
gap := &TimelineCell{Type: CellGap, row: beforeIndex, track: track}
|
||||||
if beforeIndex > 0 {
|
if beforeIndex > 0 {
|
||||||
prev := track.Cells[beforeIndex-1]
|
prev := track.Cells[beforeIndex-1]
|
||||||
if prev.BlockID != "" && !prev.IsEnd {
|
if prev.BlockID != "" && prev.Event != "END" && prev.Event != "GO" {
|
||||||
|
gap.Type = CellContinuation
|
||||||
gap.BlockID = prev.BlockID
|
gap.BlockID = prev.BlockID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user