Skip to content
Merged
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
113 changes: 113 additions & 0 deletions resource-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
function updateResourceList(data) {
const activeTags = Array.from(document.querySelectorAll(".tag-filter input:checked"))
.map(input => input.value);

const exclusiveToggle = document.getElementById("exclusive-filter-toggle").checked;

console.log("Active tags:", activeTags); // Debugging line
console.log("Exclusive mode:", exclusiveToggle); // Debugging line

// Filter resources based on active tags
const filteredData = data.filter(d => {
const resourceTags = Object.keys(d)
.filter(key => !["Name", "Link", "Description"].includes(key) && d[key].toLowerCase() === "yes");
if (exclusiveToggle) {
// In exclusive mode, include only resources with EXACTLY the active tags
return resourceTags.length === activeTags.length && activeTags.every(tag => resourceTags.includes(tag));
} else {
// Default mode: include resources with ANY of the active tags
return activeTags.some(tag => resourceTags.includes(tag));
}
});

// If no resources match, show a message
if (filteredData.length === 0) {
document.getElementById("resources-list").innerHTML = "<em>No resources match the selected filters.</em>";
return;
}

// Generate HTML for the filtered list
let html = "<ul>";
filteredData.forEach(d => {
const tags = Object.keys(d)
.filter(key => !["Name", "Link", "Description"].includes(key) && d[key].toLowerCase() === "yes");
html += `<li>
<strong><a href="${d.Link}" target="_blank">${d.Name}</a></strong>
<span>${d.Description}</span><br>
<span>${tags.map(tag => `<span class="tag">${tag}</span>`).join(" ")}</span>
</li><br>`;
});
html += "</ul>";

// Update the resource list with filtered resources
document.getElementById("resources-list").innerHTML = html;
}

// Generate filter checkboxes based on unique tag headers
function generateFilterCheckboxes(data) {
const tagHeaders = Object.keys(data[0]).filter(key => !["Name", "Link", "Description"].includes(key));

console.log("Tag Headers:", tagHeaders); // Debugging line

let filterHTML = "";
tagHeaders.forEach(tag => {
filterHTML += `
<div>
<label>
<input type="checkbox" value="${tag}" checked> ${tag}
</label>
</div>`;
});

document.getElementById("filter-controls").innerHTML = filterHTML;
}

// Attach event listeners to checkboxes
function attachFilterListeners(data) {
const checkboxes = document.querySelectorAll(".tag-filter input");
checkboxes.forEach(checkbox => {
checkbox.addEventListener("change", () => updateResourceList(data));
});

const exclusiveToggle = document.getElementById("exclusive-filter-toggle");
exclusiveToggle.addEventListener("change", () => updateResourceList(data));

const selectAllButton = document.getElementById("select-all-btn");
selectAllButton.addEventListener("click", () => {
// Check all checkboxes
checkboxes.forEach(checkbox => checkbox.checked = true);

// Update the resource list after selecting all
updateResourceList(data);
});

const deselectAllButton = document.getElementById("deselect-all-btn");
deselectAllButton.addEventListener("click", () => {
// Uncheck all checkboxes
checkboxes.forEach(checkbox => checkbox.checked = false);

// Update the resource list after deselecting all
updateResourceList(data);
});
}

// Load data and initialize filters
d3.csv("resources/resources.csv").then(function (data) {
// If no data, show an empty state message
if (!data || data.length === 0) {
document.getElementById("resources-list").innerHTML = "<em>No resources listed yet.</em>";
return;
}

// Generate and populate filters
generateFilterCheckboxes(data);

// Populate initial resource list
updateResourceList(data);

// Attach filter listeners
attachFilterListeners(data);
}).catch(function (error) {
console.error("Error loading resources:", error);
document.getElementById("resources-list").innerHTML = "<em>Could not load resources list.</em>";
});
30 changes: 19 additions & 11 deletions resources.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
<title>Interactive Blueprint</title>
<link rel="stylesheet" href="styles.css">
<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet'>
<!-- <script src="https://d3js.org/d3.v7.min.js"></script> -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="resource-list.js"></script>
<img src="images/bioecoocean_logo.png" alt="BioEcoOcean Logo" height="100px">
<img src="images/iode-unesco.png" alt="BioEcoOcean Logo" height="100px">
<img src="images/OBIS_logo.png" alt="BioEcoOcean Logo" height="100px">
Expand All @@ -23,18 +24,25 @@
</nav>
</header>
<h1> Resources</h1>
<p>Here you will find a list of resources that are relevant to each of the components of Blueprint.</p>
<p>Here you will find a list of resources that are relevant to each of the components of Blueprint. Check each box to display resources associated with a specific Blueprint component.</p>
<br><br>
<p><em>Under development: more content to come!</em></p><br>
<p>Resources include:</p>
<ul>
<li><a href="https://goosocean.org/document-list/168"> GOOS EOV Specification sheets</a></li>
<li>Data Resources:
<ul><li><a href="https://manual.obis.org/"> OBIS (Ocean Biodiversity Information System) Manual</a></li>
<li><a href="https://book.odis.org/index.html"> ODIS (Ocean Data & Information System) Manual</a></li>
</ul>
</li>
</ul>
<p>Resources:</p>
<div id="filter-controls" class="tag-filter">

<!-- Checkboxes will be dynamically generated here -->
</div>
<div>
<label class="switch-small">
<input type="checkbox" id="exclusive-filter-toggle">
<span class="slider-small"></span>
</label><span id="toggle-label-small">Show only resources with selected tags exclusively</span>
<button id="select-all-btn">Select All</button>
<button id="deselect-all-btn">Deselect All</button>
</div>
<div id="resources-list">
<!-- Resource list will be dynamically generated here -->
</div>

<footer>
<hr>
Expand Down
5 changes: 5 additions & 0 deletions resources/resources.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Name,Link,Description,Planning,Data Collection,Data Management,Analysis & Modellling,Data Products,Application in Society,Communication & Outreach,Evaluation,Explore & Review to Learn
GOOS EOV Spec sheets,https://goosocean.org/eov/,Link to all EOV spec sheets,yes,yes,yes,no,no,no,no,no,no
OBIS Manual,https://obis.org/manual/,Link to the OBIS manual,no,no,yes,no,no,no,no,no,no
ODIS Manual,https://book.odis.org/index.html,Link to the ODIS manual to contribute to ODIS,no,yes,yes,no,no,no,no,no,no
EOV Data Management,https://iobis.github.io/eov-data-management/,Link to the EOV data management guidelines,yes,yes,yes,no,no,no,no,no,no
98 changes: 98 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,102 @@ em{
font-size: larger;
color: #b80000 !important;
font-weight: bold;
}
.tag {
background: #e0f0ff;
color: #164076;
border-radius: 4px;
padding: 2px 6px;
margin-right: 4px;
font-size: 0.7em;
display: inline-block;
}
.tag-filter {
display: inline-block;
margin: 5px;
}
.tag-filter {
display: inline-block;
margin: 5px;
}
.tag-filter input[type="checkbox"]:checked + label::before {
background-color: #4CAF50; /* Change to green when checked */
border-color: #4CAF50; /* Match the border color */
}
.tag-filter label::after {
content: "✔"; /* Checkmark symbol */
position: absolute;
left: 4px;
top: 0px;
width: 20px;
height: 20px;
color: white;
font-size: 16px;
font-weight: bold;
line-height: 18px;
text-align: center;
opacity: 0;
transition: opacity 0.2s;
}
#resources-list ul {
list-style: none;
padding: 0;
}
#filter-controls {
display: flex;
flex-wrap: wrap;
gap: 10px; /* Space between checkboxes */
}

#filter-controls div {
display: flex;
align-items: center;
}

.switch-small {
position: relative;
display: inline-block;
width: 70px;
height: 22px;
vertical-align: middle;
margin: 5px;
}
.switch-small input {
opacity: 0;
width: 0;
height: 0;
}
.slider-small {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #191660;
transition: .4s;
border-radius: 15px;
}
.slider-small:before {
position: absolute;
content: "";
height: 15px;
width: 15px;
left: 5px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .slider-small {
background-color: #763eab;
}
input:checked + .slider-small:before {
transform: translateX(45px);
}
#toggle-label-small {
margin-left: 5px;
vertical-align: middle;
font-weight: bold;
font-size: regular;
}