Creative Writing with a focus on Nature Literature
+
Sustainable Architecture and Design
+
Mythology and Folklore Studies
+
Psychology of Mindfulness and Well-being
+
Renewable Energy Systems and Policy
+
Herbal Medicine and Botanical Studies
+
Wildlife Management and Conservation Biology
+
Cultural Anthropology with a focus on Indigenous Practices
+
+
+
+
Each program at Whispering Pines is designed to integrate academic excellence with an appreciation
+ for the natural world, fostering a unique learning environment for students.
+
+
+
+
-
-
+
\ No newline at end of file
diff --git a/src/ManualSlotController.js b/src/ManualSlotController.js
new file mode 100644
index 0000000..c6ee0a0
--- /dev/null
+++ b/src/ManualSlotController.js
@@ -0,0 +1,72 @@
+/**
+ * A simple Lit reactive controller to apply manual slotting to a component.
+ *
+ * Using manual slotting gives us the ability to surround the child nodes with additional
+ * elements without resorting to manipulating the page's DOM. This is important for
+ * elements with strict parent-child relationships, like `ul` and `li`, since otherwise
+ * they would require the component's user to add those elements.
+ *
+ * When using this:
+ * - Make sure your component has `slotAssignment: "manual"` in its shadowRootOptions.
+ * - Add the `_observer = new ManualSlotController(this)` property to your component's class.
+ * - In your component's render, map over children to create the slots. Something like:
+ *
+ * ```
+ * ${map(Array.from(this.children), () => html`
`)}
+ * ```
+ */
+export class ManualSlotController {
+ /**
+ * @type import("lit").LitElement
+ * @private
+ */
+ _host;
+
+ /**
+ * @type MutationObserver
+ * @private
+ */
+ _observer;
+
+ /**
+ * @param {import("lit").LitElement} host
+ */
+ constructor(host) {
+ this._host = host;
+ this._observer = new MutationObserver((list) => {
+ this._host.requestUpdate();
+ });
+ // This binds the controller to the element's lifecycle
+ host.addController(this);
+ }
+
+ /**
+ * Find the child nodes and slots, and assign the children to each slot.
+ *
+ * The render of the host component is expected to create the slots, but this
+ * function will take care of assigning the elements to them.
+ * @private
+ */
+ _refreshInternal() {
+ let items = Array.from(this._host.children);
+ let slots = Array.from(this._host.shadowRoot.querySelectorAll('slot'));
+ for (let slot of slots) {
+ if (items.length > 0) {
+ slot.assign(items.shift());
+ }
+ }
+ }
+
+ hostUpdated() {
+ // Called by Lit after the host component's render.
+ this._refreshInternal();
+ }
+
+ hostConnected() {
+ this._observer.observe(this._host, {childList: true});
+ }
+
+ disconnect() {
+ this._observer.disconnect();
+ }
+}
\ No newline at end of file
diff --git a/src/ilw-section-nav.css b/src/ilw-section-nav.css
index e69de29..c72992d 100644
--- a/src/ilw-section-nav.css
+++ b/src/ilw-section-nav.css
@@ -0,0 +1,44 @@
+@layer base {
+ :root {
+ --ilw-section-nav--margin: 1.5em 0 0 0;
+
+ --ilw-section-nav--color: var(--il-blue);
+ --ilw-section-nav--color--focus: var(--il-blue);
+ --ilw-section-nav--color--hover: var(--il-altgeld);
+ --ilw-section-nav--color--active: var(--il-altgeld);
+ --ilw-section-nav--line-height: 2.75rem; /*var: Height of a nav element*/
+ --ilw-section-nav--level-padding: 0.9375rem; /*var: Left indentation for levels*/
+ --ilw-section-nav--level2-padding: 1.5625rem; /*var: Specific indentation for level 2 children*/
+ --ilw-section-nav--level0-font-size: 1.125rem; /*var: First level children font size*/
+ --ilw-section-nav--level1-font-size: 1rem; /*var: Font size for all deeper children*/
+ --ilw-section-nav--font-weight: 600; /*var: Font weight for menu items*/
+
+ --ilw-section-nav--item-padding: 0 10px 0 20px;
+
+ --ilw-section-nav--level1-border: 1px solid var(--il-storm-lighter-3);
+
+ --ilw-section-nav--root-font-size: 1.25rem;
+ --ilw-section-nav--root-background: var(--il-storm-lighter-4);
+ --ilw-section-nav--root-font-weight: 700;
+ }
+}
+
+ilw-section-nav {
+ a {
+ color: var(--ilw-section-nav--color);
+ text-decoration: var(--ilw-link--focused-background-color);
+ display: block;
+ padding: var(--ilw-section-nav--item-padding);
+
+ &[aria-current="page"] {
+ color: var(--ilw-section-nav--color--active);
+ }
+ &:hover {
+ text-decoration: underline;
+ color: var(--ilw-section-nav--color--hover);
+ }
+ &:focus {
+ color: var(--ilw-section-nav--color--focus);
+ }
+ }
+}
diff --git a/src/ilw-section-nav.js b/src/ilw-section-nav.js
index ae6ef62..668a21e 100644
--- a/src/ilw-section-nav.js
+++ b/src/ilw-section-nav.js
@@ -1,12 +1,25 @@
-import { LitElement, html } from 'lit';
-import styles from './ilw-section-nav.styles';
-import './ilw-section-nav.css';
+import { LitElement, html } from "lit";
+import styles from "./ilw-section-nav.styles";
+import "./ilw-section-nav.css";
+import { ManualSlotController } from "./ManualSlotController.js";
+import { map } from "lit/directives/map.js";
+import { classMap } from "lit/directives/class-map.js";
class SectionNav extends LitElement {
+ static shadowRootOptions = {
+ ...LitElement.shadowRootOptions,
+ slotAssignment: "manual",
+ };
static get properties() {
return {
- theme: { type: String, attribute: true }
+ theme: {},
+ collapse: { type: Boolean },
+ open: { reflect: true },
+ label: {},
+ noRoot: { type: Boolean, attribute: "no-root" },
+ _isRoot: { state: true, type: Boolean },
+ _level: {state: true, type: Number}
};
}
@@ -14,18 +27,78 @@ class SectionNav extends LitElement {
return styles;
}
+ _observer = new ManualSlotController(this);
+
constructor() {
super();
- this.theme = '';
+ this.theme = "";
+ this.collapse = false;
+ this.open = "false";
+ this.label = "Pages In This Section";
+ this.noRoot = false;
+ this._isRoot = true;
+ this._level = 0;
+ }
+
+ connectedCallback() {
+ super.connectedCallback()
+ let parent = this.parentElement.closest("ilw-section-nav");
+ if (!parent) {
+ this._isRoot = true;
+ } else {
+ this._isRoot = false;
+ this._level = parent._level + 1;
+ }
+ }
+
+ /**
+ * Toggle between open and closed states when collapsed.
+ *
+ * @arg {"true" | "false" | undefined} open Provide the argument to force a specific state.
+ */
+ toggle(open = this.open) {
+ if (open) {
+ if ( this.open === open) {
+ return;
+ }
+ this.open = open;
+ } else if (this.open === "true") {
+ this.open = "false";
+ } else {
+ this.open = "true";
+ }
+
}
render() {
- return html`
-