Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions docs/gtr-cof.css
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,45 @@ footer {
font-size: 15;
text-anchor: left;
fill: black;
}

/* Tuning Modal Styles */
#tuning-modal-close:hover,
#tuning-modal-close:focus {
color: #000;
}

.tuning-option {
padding: 12px 16px;
margin: 8px 0;
border: 2px solid #ddd;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
background-color: white;
}

.tuning-option:hover {
background-color: #f5f5f5;
border-color: #999;
}

.tuning-option.selected {
background-color: #e6f2ff;
border-color: #0066cc;
font-weight: bold;
}

.tuning-clickable {
cursor: pointer;
text-decoration: underline;
text-decoration-style: dotted;
}

.tuning-clickable:hover {
color: #0066cc;
}

.tuning-display {
fill: #0066cc;
}
15 changes: 13 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@
<div class="menu">Scale</div>
<div id="scale-dropdown" class="dropdown-content"></div>
</div>
<div class="dropdown">
<!-- <div class="dropdown">
<div class="menu">Tunings</div>
<div id="tuning-dropdown" class="dropdown-content"></div>
</div>
</div> -->
<div class="dropdown">
<div class="menu">Settings</div>
<div id="settings-dropdown" class="dropdown-content">
Expand Down Expand Up @@ -202,5 +202,16 @@
</footer>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="gtr-cof.js"></script>

<!-- Tuning Selector Modal -->
<div id="tuning-modal" style="display: none; position: fixed; z-index: 1000; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5);">
<div id="tuning-modal-content" style="background-color: #fefefe; margin: 5% auto; padding: 20px; border: 1px solid #888; width: 90%; max-width: 600px; max-height: 70vh; overflow-y: auto; border-radius: 5px; box-shadow: 0 4px 8px rgba(0,0,0,0.3);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; border-bottom: 1px solid #ddd; padding-bottom: 10px;">
<h2 style="margin: 0; font-size: 1.5em;">Select Tuning</h2>
<span id="tuning-modal-close" style="cursor: pointer; font-size: 32px; font-weight: bold; color: #aaa; line-height: 1;">&times;</span>
</div>
<div id="tuning-options-container"></div>
</div>
</div>
</body>
</html>
42 changes: 37 additions & 5 deletions src/gtr-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,46 @@ namespace gtr {

d3.selectAll("#gtr > *").remove();
let svg = d3.select("#gtr");
svg.append("text")
let tuningText = tuningInfo.tuning + " "
+ tuningInfo.description
+ (isLeftHanded ? ", Left Handed" : "")
+ (isNutFlipped ? ", Nut Flipped" : "");

let tuningGroup = svg.append("g")
.attr("class", "tuning-label-group");

tuningGroup.append("text")
.attr("class", "mode-text")
.attr("x", 30)
.attr("y", 11)
.text(tuningInfo.tuning + " "
+ tuningInfo.description
+ (isLeftHanded ? ", Left Handed" : "")
+ (isNutFlipped ? ", Nut Flipped" : ""));
.text("Tuning: ")

let tuningLabel = tuningGroup.append("text")
.attr("class", "mode-text tuning-display")
.attr("x", 80)
.attr("y", 11)
.style("text-decoration", "underline")
.style("text-decoration-style", "dotted")
.style("cursor", "pointer")
.text(tuningText);

// Get the actual bounding box of the text
let bbox = (<SVGTextElement>tuningLabel.node()).getBBox();

// Add invisible rectangle for better click target, sized to actual text
tuningGroup.insert("rect", "text") // Insert before text so text is on top
.attr("x", bbox.x - 2)
.attr("y", bbox.y - 2)
.attr("width", bbox.width + 4)
.attr("height", bbox.height + 4)
.attr("fill", "transparent")
.style("cursor", "pointer");

// Add click handler to the group
tuningGroup.on("click", function() {
tuning.showTuningModal();
});

let gtr = svg.append("g").attr("transform", "translate(0, 0) scale(1, 1)");
fretboardElement = <SVGGElement>gtr.node();

Expand Down
68 changes: 60 additions & 8 deletions src/tuning-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,21 +117,73 @@ namespace tuning {
index++;
}

d3.select("#tuning-dropdown")
// Delay modal initialization until DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initTuningModal);
} else {
// DOM is already ready
initTuningModal();
}
// Set initial tuning
raiseTuningChangedEvent(tunings[0]);
}

function raiseTuningChangedEvent(tuning: Tuning): void{
events.tuningChange.publish({
index: tuning.index
});
}

let currentTuningIndex: number = 0;

function initTuningModal(): void {
d3.select("#tuning-options-container")
.selectAll("div")
.data(tunings)
.enter()
.append("div")
.attr("class", "dropdown-content-item")
.on("click", x => raiseTuningChangedEvent(x))
.attr("class", (d, i) => "tuning-option" + (i === 0 ? " selected" : ""))
.on("click", (x, i) => {
selectTuning(i);
hideModal();
})
.text(x => x.tuning + " " + x.description);

d3.select("#tuning-modal-close").on("click", hideModal);

raiseTuningChangedEvent(tunings[0]);
}
// Click outside to close
d3.select("#tuning-modal").on("click", function() {
const event = d3.event as MouseEvent;
if (event.target === this) {
hideModal();
}
});

function raiseTuningChangedEvent(tuning: Tuning): void{
events.tuningChange.publish({
index: tuning.index
// Escape key to close
d3.select(document).on("keydown.tuningmodal", function() {
const event = d3.event as KeyboardEvent;
if (event.key === "Escape") {
hideModal();
}
});
}

function hideModal(): void {
d3.select("#tuning-modal").style("display", "none");
}

function selectTuning(index: number): void {
currentTuningIndex = index;

d3.selectAll(".tuning-option")
.classed("selected", (d, i) => i === index);

// Trigger tuning change
raiseTuningChangedEvent(tunings[index]);
}

export function showTuningModal(): void {
const modal = d3.select("#tuning-modal");
modal.style("display", "block");
}
}