diff --git a/template-visual/annotated-document/README.md b/template-visual/annotated-document/README.md new file mode 100644 index 00000000..53951c49 --- /dev/null +++ b/template-visual/annotated-document/README.md @@ -0,0 +1,8 @@ +## A Template for an Annotated Document Article + +To do: + - Externalize text in `index.html` to some other file so it's easier to find/change + - Make `style.css` more readable - CEV: working on highlighting the important parts of file + - Try to figure out a way to make annotations less manual (i.e. not requiring as much tinkering in the console) + - Comment everything thoroughly - CEV: worked on config.js showing were comments are used - Pending review. + - Write instructions on how to use this template in this file \ No newline at end of file diff --git a/template-visual/annotated-document/index.html b/template-visual/annotated-document/index.html new file mode 100644 index 00000000..39bff83d --- /dev/null +++ b/template-visual/annotated-document/index.html @@ -0,0 +1,163 @@ + + + Annotating the Kalven Report + + + + + + + + + + + + + + + + + +
+
+
+
+ + Chicago Maroon Logo + +
+
+
+
+
+
+
+ Chicago Maroon Logo +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Report Page 1 +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Report Page 2 +
+
+
+
+
+
+
+
+
+ Report Page 3 +
+
+
+
+
+
+
+
+ Letter Page 1 +
+
+
+
+
+
+
+ Letter Page 2 +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + + + + diff --git a/template-visual/annotated-document/js/config.js b/template-visual/annotated-document/js/config.js new file mode 100644 index 00000000..a15867b6 --- /dev/null +++ b/template-visual/annotated-document/js/config.js @@ -0,0 +1,121 @@ +/** + * This file controls the annotation text that appears in the + * sticky annotation card as the reader scrolls through the document. + * + * How the file works: + * - Each numbered key corresponds to a highlighted section in the document. + * - The number must match the id of a highlight div in index.html + * - When that highlight becomes active on scroll, its text is displayed in the annotation card. + * + * Important: + * - Editors should only edit the text inside (` `). + * - Do not change the numbers unless you also change the highlights in index.html. + * - HTML is allowed inside the strings (links, italics, line breaks). + */ + +annotations = { + 1: `“Each moment we find ourselves in will call for a slightly different reading of the report,” Jamie Kalven said.

“But the report is now often enforced through ‘administrative fiat.’ It can quickly harden into a creed.”`, + 2: `Jamie Kalven both began and ended our conversation with this phrase, emphasizing the report's invitation for ongoing discussion: “I think it’s really clear that they were staking out a point of departure, and that they were quite explicitly acknowledging that there were questions and tensions between competing values… in the report that they were bequeathing to the future. They were expecting a kind of ongoing deliberative process.”

Kalven added: “When I urge people to argue from the report, as opposed to against it, I'm suggesting going back to that point of departure and reclaiming the logic of the report.”`, + 3: `Despite its academic mission, the University has interests as a corporate entity. “There's just a bunch of housekeeping stuff that the University has to do. They have to balance the books, they have to clean the dorms,” Jamie Kalven said. “If you think about the University's role in urban renewal, which was in fairly recent history when the Kalven Report was written, I think that's, again, a kind of underlying context for those passages about the University as a corporate entity. I think there's something deeply unresolved there,” he said.`, + 4: `The report leaves ambiguous the distinction between academic freedom and freedom of speech.

“I see it as this kind of vessel that contains certain statements with clarity and then contains within it all sorts of tensions between competing values and contains within it questions that the drafters didn't foresee,” Jamie Kalven said.

“There are things under First Amendment law that are protected, not so much because they're thought to be of intrinsic value to us as individuals or to the society, but because we don't trust the state as a censor, that's a different logic than how we organize ourselves as a university community to maximize intellectual autonomy and freedom,” Kalven added.`, + 5: `“I'm also struck that the Committee, early in the report, is ticking off the various occasions when the University has taken some kind of action, much of it in the context of the McCarthy-era incursions on higher education,” Jamie Kalven told the Maroon.

The Broyles Bill inquiry refers to Illinois senator Paul Broyles’s commission investigating Communist influence in the state. The Commission held hearings about UChicago professors' political actions, during which University-funded legal representatives accompanied students and faculty members. Then-University chancellor Robert Maynard Hutchins called the proceedings “unconstitutional and un-American.”

The Senate Internal Security Committee, chaired by Indiana Senator William E. Jenner, accused faculty at UChicago and other universities of involvement in Communist and subversive committees.

The National Defense Education Act of 1958 required any student who applied for a federal loan under the act to sign a loyalty oath and make an affidavit stating that they did not support any organization that encouraged an illegal overthrow of the U.S. government. `, + 6: `“My understanding,” Jamie Kalven said, “is there was a student sit-in—including Bernie Sanders, who was an undergraduate here—in response to which the University changed some discriminatory rental policies. Nobody's made much of that as a precedent, but doesn't that suggest at least one instance where there was a direct challenge to the practices of the University as a corporate entity in the broader neighborhood that was successful?”`, + 7: `“In 1967, student activism is now building to a crescendo on the U of C campus and elsewhere,” Jamie Kalven explained. “I think there were multiple issues, but one of the most salient issues at the time was whether it was appropriate for the University to cooperate with the Selective Service, with the draft, which was a matter of really urgent personal concern for male students.” In addition to the anti-Vietnam War movement, Kalven noted “the beginnings of stirrings of activism addressed to apartheid in South Africa.”`, + 8: `When Jamie was editing his father's book, he titled it A Worthy Tradition based on Harry Kalven Jr. 's understanding of tradition in the context of the First Amendment. “The idea was that the First Amendment, as he understood it, was more than simply a body of law,” Jamie Kalven said. “It was a tradition of the society—and a living tradition—as opposed to just the dead hand of tradition.”`, + 9: `Speaking on the “several dangers that exist right now,” Jamie Kalven said, “One is that decision makers will simply take cover under this notion of political neutrality and/or institutional neutrality, and invoke the Kalven Report, which would be, I think, just a complete misreading of the character of the report.”

“Another danger,” Kalven added, “is to disaggregate what's going on and just address each thing, the attacks on DEI, the NIH funding, coming after foreign students who've simply exercised First Amendment rights. If you think of each thing in isolation, there's the temptation to say, ‘We can make a concession here in the interest of the institution in order to live to fight another day,’ that kind of logic. I actually think that's a really dangerous course.”`, + 10: `An earlier version of the draft did not include “or the individual student,” and the published report still does not mention staff. “I think that’s the sort of thing that, if it were pointed out, it would immediately be addressed,” Jamie Kalven said. “It’s interesting, you know, as a limitation of the report as written, but it emphasizes the freedom of individuals.”`, + 11: `Amidst student activism for divestment from Sudan, the Chicago Tribune reported that John Hope Franklin, then the only surviving member of the Committee, wrote, “We were strong in our position that the university should not jump every time that a crisis arose.” He did, however, note that the Darfur situation warranted an exception.

In a 2006 op-ed in the Maroon titled “Unfinished business of the Kalven Report,” Jamie Kalven cited Franklin’s position: “It is telling, though, that the one surviving member of the Kalven Committee, Professor John Hope Franklin, has unequivocally stated that ‘the desperate situation in Darfur is so tragic that it qualifies as the exceptional instance where I have no difficulty in concluding that divestment is consistent with the core values of our report and the mission of the University.’”`, + 12: `Kalven distinguished between bravery as an individual characteristic and courage as “a social virtue.” He emphasized the importance of “the solidarity of the shaken,” a phrase coined by Czech philosopher Jan Patočka, a political dissident against the Communist Party in Czechoslovakia. “We must keep our values visible to one another,” Kalven said.`, + 13: `This passage has a different tenor than other sections, which are encircled by caveats. Indicating the use of “obligation” in talking about actively defending the University's values, Kalven called this “very close to stating a moral imperative.”`, + 14: `The term “presumption” is a legal assumption that a fact is true based on other known quantities. Jamie Kalven emphasized his father’s thinking as a legal scholar: “I can imagine him thinking of it as a sort of common law process… where you’re sort of continuously refining a principle, deepening it, and testing it against those sorts of practical challenges presented by different fact situations.”`, + 15: `“Something else that has been effectively raised recently is an important distinction between discussion and deliberation,” referring to arguments from associate professor of philosophy and deputy dean of the Humanities Division Anton Ford. “You can talk all day about whatever, but what feels to me missing is some kind of deliberative process. And it’s not sufficient to say that the nature of the University is such that we can’t put everything up to vote—that's sort of a straw man, because there are other deliberative forms.”`, + 16: `“There’s a kind of delicacy that is apparent in the document and the surrounding correspondence—a delicacy of managing tensions within the Committee,” Jamie Kalven said when asked about the special comment. “It’s pretty clear that Stiegler has taken the position that the University should have complete and absolute freedom to act in its corporate capacity. There should be no exceptions allowed.”

“Stigler’s position illuminates what the Committee ultimately landed on as a formulation, but I think the other point you could make about it is in terms of the way the University has applied it over the years, it might be called the Stigler Report rather than the Kalven Report.”`, + 17: `This letter is one that Harry Kalven Jr. sent to members of the Committee on the Role of the University in Political and Social Action.

“This document should be read alongside the report,” Jamie Kalven told the Maroon. “You have a quite explicit expression of the drafters’ intentions. If we were a court interpreting a law, this would say a lot about legislative intent.”`, +}; + +content = { + 'title': `“Living Tradition” or “Administrative Fiat”?:
Annotating the Kalven Report`, + 'subtitle': `Drawing upon an interview with journalist Jamie Kalven, son of Harry Kalven Jr. of the Kalven Report, the Maroon annotates this oft-cited but little read document.`, + 'authors': `Written by + Anushree Vashist + and + Celeste Alcalay`, + 'developers': `Design and Development by + Austin Steinhart`, + 'article-text': `

+ In 1967, University President George Beadle appointed a + faculty committee—chaired by First Amendment scholar + Harry Kalven Jr.—to prepare “a statement on the + University’s role in political and social action.” The + resulting report articulates the University’s commitment + to institutional neutrality. By abstaining from speech + about political and social issues, the report says, the + University allows its individual members the fullest + freedom of expression. +

+

+ Journalist Jamie Kalven, Harry Kalven Jr.’s son, sat + down with the Maroon to walk through the Kalven + Report. In the 14 years he spent editing his father’s + manuscript on the First Amendment and the American + tradition of freedom of speech, Jamie Kalven reviewed + hundreds of Harry Kalven Jr.’s papers to + familiarize + himself with his father’s thinking. +

+

+ Providing context on his father’s writing, Jamie Kalven + argues that we, now in a moment of attacks on academic + freedom and higher education, should return to “the + point of departure” the document provides. +

+ Reading from a letter addressed to the members of the + drafting committee, which you’ll find publicly available for + the first time on the Maroon’s website, Jamie Kalven + discusses where his father decided to “spend the emphasis” + in the report. Harry Kalven Jr. concluded that, in 1967, + stating the general principle against collective action was + more important than foregrounding the exceptional cases in + which collective action may have been appropriate. +

+ Still, there will be exceptions, moments when the “very + mission of the University and its values of free + inquiry” are under threat. +

+

+ Jamie Kalven + believes + that, today, we find ourselves in one such moment. +

+

+ Listen to the Maroon’s conversation with Jamie + Kalven + here. +

` +}; + +sessionStorage.setItem('annotations', JSON.stringify(annotations)); +sessionStorage.setItem('content', JSON.stringify(content)); diff --git a/template-visual/annotated-document/js/main.js b/template-visual/annotated-document/js/main.js new file mode 100644 index 00000000..5cd57ec9 --- /dev/null +++ b/template-visual/annotated-document/js/main.js @@ -0,0 +1,151 @@ +// inspired by https://www.nytimes.com/interactive/2025/02/13/us/doc-annotation-memo-from-bove.html + +// -------------- constants -------------- +let active_highlight = document.querySelector('.highlight.active'); +let next_highlight; +let annotations; +let currentHighlightIndex = 1; +let isMobile = window.innerWidth < 1075; +let mobileOffset = isMobile ? 30 : 0; + +// isMobile = true; + +if (isMobile) { + //change logo to black + document.querySelector('#maroon-logo').src = + 'static/images/transparent-nameplate-small.png'; +} +// -------------- waypoints -------------- + +function createWaypoint() { + for (let i = 1; i < 18; i++) { + new Waypoint({ + element: document.querySelector(`#highlight-${i}`), + handler: function (direction) { + if (direction == 'down') { + if (i != 1) { + // make active + next_highlight = document.querySelector( + `#highlight-${i}` + ); + activateNextHighlight(next_highlight); + currentHighlightIndex = parseInt(i); + + updateAnnotationCard(annotations[i]); + } + } else { + if (i == 1) { + // make active + next_highlight = document.querySelector( + `#highlight-${i}` + ); + activateNextHighlight(next_highlight); + currentHighlightIndex = parseInt(i); + } else { + next_highlight = document.querySelector( + `#highlight-${i - 1}` + ); + activateNextHighlight(next_highlight); + + updateAnnotationCard(annotations[i - 1]); + } + } + }, + offset: offset(i) + }); + } +} + +// ------ functions --------- + +function offset(i) { + if (i <= 3) { + value = 55 - mobileOffset; + } else { + value = 45 - mobileOffset; + } + return String(value) + '%'; +} + +function updateAnnotationCard(newText) { + const annotationCardElement = document.querySelector('.annotation-card'); + const annotationTextElement = document.querySelector( + '.annotation-card-text' + ); + + // Add fade-out class to the entire card + annotationCardElement.classList.add('fade-out'); + + // Wait for the fade-out animation to complete + setTimeout(() => { + // Update the text content + annotationTextElement.innerHTML = newText; + + // Remove fade-out class and add fade-in class to the entire card + annotationCardElement.classList.remove('fade-out'); + annotationCardElement.classList.add('fade-in'); + + // Remove fade-in class after the animation completes + setTimeout(() => { + annotationCardElement.classList.remove('fade-in'); + }, 200); + }, 200); +} + +// function to deactive current highlight and active next highlight +function activateNextHighlight(next_highlight) { + if (active_highlight.classList.contains('active')) { + active_highlight.classList.remove('active'); + } + active_highlight = next_highlight; + active_highlight.classList.add('active'); +} + +// -------- event listeners --------- + +function addEventListeners() { + // Add event listener for keydown events to switch between highlights + document.addEventListener('keydown', (event) => { + if (event.key === 'ArrowRight') { + console.log(currentHighlightIndex); + currentHighlightIndex++; + const nextHighlight = document.querySelector( + `#highlight-${currentHighlightIndex}` + ); + activateNextHighlight(nextHighlight); + updateAnnotationCard(annotations[currentHighlightIndex]); + } else if (event.key === 'ArrowLeft') { + currentHighlightIndex--; + const prevHighlight = document.querySelector( + `#highlight-${currentHighlightIndex}` + ); + activateNextHighlight(prevHighlight); + updateAnnotationCard(annotations[currentHighlightIndex]); + } + }); +} + +// ------- init -------- + +function init() { + content = JSON.parse(sessionStorage.getItem('content')); + for (const key in content) { + if (content[key] != null) { + console.log('Setting ' + key); + document.getElementById(key).innerHTML = content[key]; + } + } + + annotations = JSON.parse(sessionStorage.getItem('annotations')); + document.querySelector('.annotation-card-text').innerHTML = annotations[1]; + createWaypoint(); + addEventListeners(); +} + +document.addEventListener('DOMContentLoaded', () => { + // force scroll to top on refresh + window.onbeforeunload = function () { + window.scrollTo(0, 0); + }; + init(); +}); diff --git a/template-visual/annotated-document/js/noframework.waypoints.min.js b/template-visual/annotated-document/js/noframework.waypoints.min.js new file mode 100644 index 00000000..3979ced1 --- /dev/null +++ b/template-visual/annotated-document/js/noframework.waypoints.min.js @@ -0,0 +1,513 @@ +/*! +Waypoints - 4.0.1 +Copyright © 2011-2016 Caleb Troughton +Licensed under the MIT license. +https://github.com/imakewebthings/waypoints/blob/master/licenses.txt +*/ +!(function () { + 'use strict'; + function t(n) { + if (!n) throw new Error('No options passed to Waypoint constructor'); + if (!n.element) + throw new Error('No element option passed to Waypoint constructor'); + if (!n.handler) + throw new Error('No handler option passed to Waypoint constructor'); + (this.key = 'waypoint-' + e), + (this.options = t.Adapter.extend({}, t.defaults, n)), + (this.element = this.options.element), + (this.adapter = new t.Adapter(this.element)), + (this.callback = n.handler), + (this.axis = this.options.horizontal ? 'horizontal' : 'vertical'), + (this.enabled = this.options.enabled), + (this.triggerPoint = null), + (this.group = t.Group.findOrCreate({ + name: this.options.group, + axis: this.axis + })), + (this.context = t.Context.findOrCreateByElement( + this.options.context + )), + t.offsetAliases[this.options.offset] && + (this.options.offset = t.offsetAliases[this.options.offset]), + this.group.add(this), + this.context.add(this), + (i[this.key] = this), + (e += 1); + } + var e = 0, + i = {}; + (t.prototype.queueTrigger = function (t) { + this.group.queueTrigger(this, t); + }), + (t.prototype.trigger = function (t) { + this.enabled && this.callback && this.callback.apply(this, t); + }), + (t.prototype.destroy = function () { + this.context.remove(this), + this.group.remove(this), + delete i[this.key]; + }), + (t.prototype.disable = function () { + return (this.enabled = !1), this; + }), + (t.prototype.enable = function () { + return this.context.refresh(), (this.enabled = !0), this; + }), + (t.prototype.next = function () { + return this.group.next(this); + }), + (t.prototype.previous = function () { + return this.group.previous(this); + }), + (t.invokeAll = function (t) { + var e = []; + for (var n in i) e.push(i[n]); + for (var o = 0, r = e.length; r > o; o++) e[o][t](); + }), + (t.destroyAll = function () { + t.invokeAll('destroy'); + }), + (t.disableAll = function () { + t.invokeAll('disable'); + }), + (t.enableAll = function () { + t.Context.refreshAll(); + for (var e in i) i[e].enabled = !0; + return this; + }), + (t.refreshAll = function () { + t.Context.refreshAll(); + }), + (t.viewportHeight = function () { + return window.innerHeight || document.documentElement.clientHeight; + }), + (t.viewportWidth = function () { + return document.documentElement.clientWidth; + }), + (t.adapters = []), + (t.defaults = { + context: window, + continuous: !0, + enabled: !0, + group: 'default', + horizontal: !1, + offset: 0 + }), + (t.offsetAliases = { + 'bottom-in-view': function () { + return this.context.innerHeight() - this.adapter.outerHeight(); + }, + 'right-in-view': function () { + return this.context.innerWidth() - this.adapter.outerWidth(); + } + }), + (window.Waypoint = t); +})(), + (function () { + 'use strict'; + function t(t) { + window.setTimeout(t, 1e3 / 60); + } + function e(t) { + (this.element = t), + (this.Adapter = o.Adapter), + (this.adapter = new this.Adapter(t)), + (this.key = 'waypoint-context-' + i), + (this.didScroll = !1), + (this.didResize = !1), + (this.oldScroll = { + x: this.adapter.scrollLeft(), + y: this.adapter.scrollTop() + }), + (this.waypoints = { vertical: {}, horizontal: {} }), + (t.waypointContextKey = this.key), + (n[t.waypointContextKey] = this), + (i += 1), + o.windowContext || + ((o.windowContext = !0), (o.windowContext = new e(window))), + this.createThrottledScrollHandler(), + this.createThrottledResizeHandler(); + } + var i = 0, + n = {}, + o = window.Waypoint, + r = window.onload; + (e.prototype.add = function (t) { + var e = t.options.horizontal ? 'horizontal' : 'vertical'; + (this.waypoints[e][t.key] = t), this.refresh(); + }), + (e.prototype.checkEmpty = function () { + var t = this.Adapter.isEmptyObject(this.waypoints.horizontal), + e = this.Adapter.isEmptyObject(this.waypoints.vertical), + i = this.element == this.element.window; + t && + e && + !i && + (this.adapter.off('.waypoints'), delete n[this.key]); + }), + (e.prototype.createThrottledResizeHandler = function () { + function t() { + e.handleResize(), (e.didResize = !1); + } + var e = this; + this.adapter.on('resize.waypoints', function () { + e.didResize || + ((e.didResize = !0), o.requestAnimationFrame(t)); + }); + }), + (e.prototype.createThrottledScrollHandler = function () { + function t() { + e.handleScroll(), (e.didScroll = !1); + } + var e = this; + this.adapter.on('scroll.waypoints', function () { + (!e.didScroll || o.isTouch) && + ((e.didScroll = !0), o.requestAnimationFrame(t)); + }); + }), + (e.prototype.handleResize = function () { + o.Context.refreshAll(); + }), + (e.prototype.handleScroll = function () { + var t = {}, + e = { + horizontal: { + newScroll: this.adapter.scrollLeft(), + oldScroll: this.oldScroll.x, + forward: 'right', + backward: 'left' + }, + vertical: { + newScroll: this.adapter.scrollTop(), + oldScroll: this.oldScroll.y, + forward: 'down', + backward: 'up' + } + }; + for (var i in e) { + var n = e[i], + o = n.newScroll > n.oldScroll, + r = o ? n.forward : n.backward; + for (var s in this.waypoints[i]) { + var l = this.waypoints[i][s]; + if (null !== l.triggerPoint) { + var a = n.oldScroll < l.triggerPoint, + h = n.newScroll >= l.triggerPoint, + p = a && h, + u = !a && !h; + (p || u) && + (l.queueTrigger(r), (t[l.group.id] = l.group)); + } + } + } + for (var d in t) t[d].flushTriggers(); + this.oldScroll = { + x: e.horizontal.newScroll, + y: e.vertical.newScroll + }; + }), + (e.prototype.innerHeight = function () { + return this.element == this.element.window + ? o.viewportHeight() + : this.adapter.innerHeight(); + }), + (e.prototype.remove = function (t) { + delete this.waypoints[t.axis][t.key], this.checkEmpty(); + }), + (e.prototype.innerWidth = function () { + return this.element == this.element.window + ? o.viewportWidth() + : this.adapter.innerWidth(); + }), + (e.prototype.destroy = function () { + var t = []; + for (var e in this.waypoints) + for (var i in this.waypoints[e]) + t.push(this.waypoints[e][i]); + for (var n = 0, o = t.length; o > n; n++) t[n].destroy(); + }), + (e.prototype.refresh = function () { + var t, + e = this.element == this.element.window, + i = e ? void 0 : this.adapter.offset(), + n = {}; + this.handleScroll(), + (t = { + horizontal: { + contextOffset: e ? 0 : i.left, + contextScroll: e ? 0 : this.oldScroll.x, + contextDimension: this.innerWidth(), + oldScroll: this.oldScroll.x, + forward: 'right', + backward: 'left', + offsetProp: 'left' + }, + vertical: { + contextOffset: e ? 0 : i.top, + contextScroll: e ? 0 : this.oldScroll.y, + contextDimension: this.innerHeight(), + oldScroll: this.oldScroll.y, + forward: 'down', + backward: 'up', + offsetProp: 'top' + } + }); + for (var r in t) { + var s = t[r]; + for (var l in this.waypoints[r]) { + var a, + h, + p, + u, + d, + f = this.waypoints[r][l], + c = f.options.offset, + w = f.triggerPoint, + y = 0, + g = null == w; + f.element !== f.element.window && + (y = f.adapter.offset()[s.offsetProp]), + 'function' == typeof c + ? (c = c.apply(f)) + : 'string' == typeof c && + ((c = parseFloat(c)), + f.options.offset.indexOf('%') > -1 && + (c = Math.ceil( + (s.contextDimension * c) / 100 + ))), + (a = s.contextScroll - s.contextOffset), + (f.triggerPoint = Math.floor(y + a - c)), + (h = w < s.oldScroll), + (p = f.triggerPoint >= s.oldScroll), + (u = h && p), + (d = !h && !p), + !g && u + ? (f.queueTrigger(s.backward), + (n[f.group.id] = f.group)) + : !g && d + ? (f.queueTrigger(s.forward), + (n[f.group.id] = f.group)) + : g && + s.oldScroll >= f.triggerPoint && + (f.queueTrigger(s.forward), + (n[f.group.id] = f.group)); + } + } + return ( + o.requestAnimationFrame(function () { + for (var t in n) n[t].flushTriggers(); + }), + this + ); + }), + (e.findOrCreateByElement = function (t) { + return e.findByElement(t) || new e(t); + }), + (e.refreshAll = function () { + for (var t in n) n[t].refresh(); + }), + (e.findByElement = function (t) { + return n[t.waypointContextKey]; + }), + (window.onload = function () { + r && r(), e.refreshAll(); + }), + (o.requestAnimationFrame = function (e) { + var i = + window.requestAnimationFrame || + window.mozRequestAnimationFrame || + window.webkitRequestAnimationFrame || + t; + i.call(window, e); + }), + (o.Context = e); + })(), + (function () { + 'use strict'; + function t(t, e) { + return t.triggerPoint - e.triggerPoint; + } + function e(t, e) { + return e.triggerPoint - t.triggerPoint; + } + function i(t) { + (this.name = t.name), + (this.axis = t.axis), + (this.id = this.name + '-' + this.axis), + (this.waypoints = []), + this.clearTriggerQueues(), + (n[this.axis][this.name] = this); + } + var n = { vertical: {}, horizontal: {} }, + o = window.Waypoint; + (i.prototype.add = function (t) { + this.waypoints.push(t); + }), + (i.prototype.clearTriggerQueues = function () { + this.triggerQueues = { up: [], down: [], left: [], right: [] }; + }), + (i.prototype.flushTriggers = function () { + for (var i in this.triggerQueues) { + var n = this.triggerQueues[i], + o = 'up' === i || 'left' === i; + n.sort(o ? e : t); + for (var r = 0, s = n.length; s > r; r += 1) { + var l = n[r]; + (l.options.continuous || r === n.length - 1) && + l.trigger([i]); + } + } + this.clearTriggerQueues(); + }), + (i.prototype.next = function (e) { + this.waypoints.sort(t); + var i = o.Adapter.inArray(e, this.waypoints), + n = i === this.waypoints.length - 1; + return n ? null : this.waypoints[i + 1]; + }), + (i.prototype.previous = function (e) { + this.waypoints.sort(t); + var i = o.Adapter.inArray(e, this.waypoints); + return i ? this.waypoints[i - 1] : null; + }), + (i.prototype.queueTrigger = function (t, e) { + this.triggerQueues[e].push(t); + }), + (i.prototype.remove = function (t) { + var e = o.Adapter.inArray(t, this.waypoints); + e > -1 && this.waypoints.splice(e, 1); + }), + (i.prototype.first = function () { + return this.waypoints[0]; + }), + (i.prototype.last = function () { + return this.waypoints[this.waypoints.length - 1]; + }), + (i.findOrCreate = function (t) { + return n[t.axis][t.name] || new i(t); + }), + (o.Group = i); + })(), + (function () { + 'use strict'; + function t(t) { + return t === t.window; + } + function e(e) { + return t(e) ? e : e.defaultView; + } + function i(t) { + (this.element = t), (this.handlers = {}); + } + var n = window.Waypoint; + (i.prototype.innerHeight = function () { + var e = t(this.element); + return e ? this.element.innerHeight : this.element.clientHeight; + }), + (i.prototype.innerWidth = function () { + var e = t(this.element); + return e ? this.element.innerWidth : this.element.clientWidth; + }), + (i.prototype.off = function (t, e) { + function i(t, e, i) { + for (var n = 0, o = e.length - 1; o > n; n++) { + var r = e[n]; + (i && i !== r) || t.removeEventListener(r); + } + } + var n = t.split('.'), + o = n[0], + r = n[1], + s = this.element; + if (r && this.handlers[r] && o) + i(s, this.handlers[r][o], e), (this.handlers[r][o] = []); + else if (o) + for (var l in this.handlers) + i(s, this.handlers[l][o] || [], e), + (this.handlers[l][o] = []); + else if (r && this.handlers[r]) { + for (var a in this.handlers[r]) + i(s, this.handlers[r][a], e); + this.handlers[r] = {}; + } + }), + (i.prototype.offset = function () { + if (!this.element.ownerDocument) return null; + var t = this.element.ownerDocument.documentElement, + i = e(this.element.ownerDocument), + n = { top: 0, left: 0 }; + return ( + this.element.getBoundingClientRect && + (n = this.element.getBoundingClientRect()), + { + top: n.top + i.pageYOffset - t.clientTop, + left: n.left + i.pageXOffset - t.clientLeft + } + ); + }), + (i.prototype.on = function (t, e) { + var i = t.split('.'), + n = i[0], + o = i[1] || '__default', + r = (this.handlers[o] = this.handlers[o] || {}), + s = (r[n] = r[n] || []); + s.push(e), this.element.addEventListener(n, e); + }), + (i.prototype.outerHeight = function (e) { + var i, + n = this.innerHeight(); + return ( + e && + !t(this.element) && + ((i = window.getComputedStyle(this.element)), + (n += parseInt(i.marginTop, 10)), + (n += parseInt(i.marginBottom, 10))), + n + ); + }), + (i.prototype.outerWidth = function (e) { + var i, + n = this.innerWidth(); + return ( + e && + !t(this.element) && + ((i = window.getComputedStyle(this.element)), + (n += parseInt(i.marginLeft, 10)), + (n += parseInt(i.marginRight, 10))), + n + ); + }), + (i.prototype.scrollLeft = function () { + var t = e(this.element); + return t ? t.pageXOffset : this.element.scrollLeft; + }), + (i.prototype.scrollTop = function () { + var t = e(this.element); + return t ? t.pageYOffset : this.element.scrollTop; + }), + (i.extend = function () { + function t(t, e) { + if ('object' == typeof t && 'object' == typeof e) + for (var i in e) e.hasOwnProperty(i) && (t[i] = e[i]); + return t; + } + for ( + var e = Array.prototype.slice.call(arguments), + i = 1, + n = e.length; + n > i; + i++ + ) + t(e[0], e[i]); + return e[0]; + }), + (i.inArray = function (t, e, i) { + return null == e ? -1 : e.indexOf(t, i); + }), + (i.isEmptyObject = function (t) { + for (var e in t) return !1; + return !0; + }), + n.adapters.push({ name: 'noframework', Adapter: i }), + (n.Adapter = i); + })(); diff --git a/template-visual/annotated-document/static/images/black_m.png b/template-visual/annotated-document/static/images/black_m.png new file mode 100644 index 00000000..6e5302ab Binary files /dev/null and b/template-visual/annotated-document/static/images/black_m.png differ diff --git a/template-visual/annotated-document/static/images/cover_kr.webp b/template-visual/annotated-document/static/images/cover_kr.webp new file mode 100644 index 00000000..5b38656a Binary files /dev/null and b/template-visual/annotated-document/static/images/cover_kr.webp differ diff --git a/template-visual/annotated-document/static/images/letter1_kr.webp b/template-visual/annotated-document/static/images/letter1_kr.webp new file mode 100644 index 00000000..3395474c Binary files /dev/null and b/template-visual/annotated-document/static/images/letter1_kr.webp differ diff --git a/template-visual/annotated-document/static/images/letter2_kr.webp b/template-visual/annotated-document/static/images/letter2_kr.webp new file mode 100644 index 00000000..31e82198 Binary files /dev/null and b/template-visual/annotated-document/static/images/letter2_kr.webp differ diff --git a/template-visual/annotated-document/static/images/report1.png b/template-visual/annotated-document/static/images/report1.png new file mode 100644 index 00000000..62a4d55e Binary files /dev/null and b/template-visual/annotated-document/static/images/report1.png differ diff --git a/template-visual/annotated-document/static/images/report2.png b/template-visual/annotated-document/static/images/report2.png new file mode 100644 index 00000000..ad19291e Binary files /dev/null and b/template-visual/annotated-document/static/images/report2.png differ diff --git a/template-visual/annotated-document/static/images/report3.png b/template-visual/annotated-document/static/images/report3.png new file mode 100644 index 00000000..6bec3c86 Binary files /dev/null and b/template-visual/annotated-document/static/images/report3.png differ diff --git a/template-visual/annotated-document/static/images/transparent-nameplate-offwhite.png b/template-visual/annotated-document/static/images/transparent-nameplate-offwhite.png new file mode 100644 index 00000000..f9a0842b Binary files /dev/null and b/template-visual/annotated-document/static/images/transparent-nameplate-offwhite.png differ diff --git a/template-visual/annotated-document/static/images/transparent-nameplate-small.png b/template-visual/annotated-document/static/images/transparent-nameplate-small.png new file mode 100644 index 00000000..1d810a2c Binary files /dev/null and b/template-visual/annotated-document/static/images/transparent-nameplate-small.png differ diff --git a/template-visual/annotated-document/static/images/white_m.png b/template-visual/annotated-document/static/images/white_m.png new file mode 100644 index 00000000..53cc890b Binary files /dev/null and b/template-visual/annotated-document/static/images/white_m.png differ diff --git a/template-visual/annotated-document/static/style explained.txt b/template-visual/annotated-document/static/style explained.txt new file mode 100644 index 00000000..3df497f0 --- /dev/null +++ b/template-visual/annotated-document/static/style explained.txt @@ -0,0 +1,101 @@ +style.css controls how the article looks and where things are on the page. + +CSS is doing 3 things: + +# 1. Designing the article header + intro text (title, subtitle, etc). +# 2. Building the annotated-document layout: + the document pages / images + the overlay highlights / yellow boxes + the sticky annotation card / right side on desktop +# 3. Rearranging for mobile. + +At the top it loads Google Fonts: + - Montserrat + - Open Sans + - Playfair Display + +Then the named colors are used later (avoiding repeating hex codes). +:root { + --main-bg-color: #4d0000; + --maroon_color: #800000; +} + +Then making layouts predictable and removing default browser spacing: +# This affects everything # +* { box-sizing: border-box; } +body { margin:0; padding:0; font-family:'Georgia'; width:100%; } + + + +FIRST PART: Header section (the big split screen at the top): + + + +This part creates the “two-column hero”: +left: maroon background with title text +right: cover image + +More explanation needed for: + .header-container is display:flex and height:100vh (full screen). + .header-title-container and .header-img each get flex: 1 (half/half). + #title and #subtitle style typography (size, color, spacing). + + + +SECOND PART: Intro section (the “article text” before the document): + + +#intro-text { width: 50%; margin: auto; } - Centers the intro column on desktop.  +.article-text - Sets font size and line height  +link styles - Maroon color for hyperlinks inside intro.  + +# #intro-text and .article-text — they control readability. # + + + +THIRD PART: The annotated document layout + +This is for absolute positioning used later (for the annotation panel): +#content-container { + position: relative; +} + +This is how the scanned pages are positioned on desktop: +Important to highlight: left:-200px — this is a “layout hack” that future maintainers need to know exists. +#doc-container { + position: relative; + max-width: 800px; + left: -200px; +} + +max width controls how big the doc images appear +left:-200px shifts the doc left to make room for the annotation card + +# left:-200px — “layout hack” ### + +each page is: + .page { position: relative; } + inside it a .page-image img (the scan) + and a .page-highlights overlay on top + +FOURTH PART: Highlights (the yellow boxes over the document) + +Making the highlights layer match the image exactly. +.page-highlights { + position: absolute; + top:0; left:0; + width:100%; height:100%; +} + +The default is pale yellow, brighter with a border: +.highlight { background-color: #ffff1033; } +.highlight.active { border: 3px solid #ffe300; } + +Per-highlight positioning +Example: +#highlight-1 { left:10%; top:17%; width:78%; height:2.5%; } +These are the “coordinates” for each highlight box, relative to the image + +# Most important part of the document # +Each new article will need new highlight coordinates +if someone changes the page image size/aspect ratio it will break \ No newline at end of file diff --git a/template-visual/annotated-document/static/style.css b/template-visual/annotated-document/static/style.css new file mode 100644 index 00000000..dbe4e50f --- /dev/null +++ b/template-visual/annotated-document/static/style.css @@ -0,0 +1,646 @@ +@import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Open+Sans:ital,wght@0,300..800;1,300..800&family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap'); + +:root { + --main-bg-color: #4d0000; + --maroon_color: #800000; +} + +* { + box-sizing: border-box; +} + +body { + height: 100dvh; + margin: 0; + padding: 0; + font-family: 'Georgia', sans-serif; + width: 100%; +} + +.header-container { + display: flex; + height: 100vh; /* Full viewport height */ + margin-bottom: 50px; +} + +.header-title-container { + flex: 1; /* Takes up half the space */ + justify-content: center; /* Center horizontally */ + align-items: center; /* Center vertically */ + background-color: var(--main-bg-color); +} +.header-img { + flex: 1; /* Takes up half the space */ + display: flex; + justify-content: center; /* Center the image horizontally */ + align-items: center; /* Center the image vertically */ + background-color: #f0f0ef; +} + +.header-maroon { + margin-top: 10px; + width: 100%; + display: flex; + justify-content: center; +} + +.header-maroon img { + width: 220px; + margin: auto; +} + +#header-title { + height: 100%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + max-width: 500px; + margin: auto; +} + +.header-img img { + width: 100%; /* Make sure the image doesn't overflow */ + height: 100%; /* Make sure the image doesn't overflow */ + object-fit: scale-down; /* Scale the image */ +} + +.intro hr { + opacity: 60%; +} + +#intro-text a { + color: #800000; + text-decoration: none; +} + +#intro-text a:hover { + text-decoration: underline; +} + +#intro-text { + width: 50%; + margin: auto; +} + +#title { + font-size: 45px; + font-weight: 500; + line-height: 1.3; + text-align: center; + margin-bottom: 15px; + color: white; +} + +#subtitle { + padding-block: 5px; + font-size: 22px; + text-align: center; + margin-bottom: 10px; + font-weight: 400; + line-height: 1.3; + color: white; +} + +#intro-text hr { + margin-top: 30px; + margin-bottom: 20px; + border: 1px solid rgba(0, 0, 0, 0.273); + opacity: 60%; +} + +#byline { + padding-block: 1px; + margin-block: 2px; + font-size: 14px; + text-align: left; +} + +.byline-link { + font-weight: bold; + text-decoration: none; + color: #800000; +} + +.byline-link:hover { + text-decoration: underline; +} + +.article-text { + font-family: Georgia, 'Times New Roman', Times, serif; + font-size: 20px; + line-height: 1.7; +} + +.title-box { + margin: auto; +} + +.title-box img { + width: 100%; + margin: auto; + display: block; + transform: rotate(270deg); +} + +#content-container { + border-top: 1px solid #800000; + background-color: rgb(128, 0, 0, 0.1); + margin-top: 50px; + padding-top: 60px; + padding-bottom: 60px; + position: relative; +} + +#doc-container { + position: relative; + margin: auto auto 28px; + max-width: 800px; + left: -200px; +} + +.page { + position: relative; + margin-bottom: 28px; +} + +#page-report { + background-color: #fcf9f6; +} + +#report { + padding: 100px; + font-family: 'Times New Roman', Times, serif; + font-size: 20px; + font-size: 18px; +} + +#report-title { + font-weight: 600; + text-transform: uppercase; +} + +.page-image img { + height: auto; + max-width: 100%; +} + +.page-image#report { + height: 500px; + width: 100%; + background-color: #800000; +} + +.page-highlights { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.highlight { + position: relative; + background-color: #ffff1033; + border: 2px solid transparent; + transition: all 0.1s ease; +} + +.highlight.active { + background-color: #ffff104d; + border: 3px solid #ffe300; +} + +#highlight-1 { + left: 10%; + top: 17%; + width: 78%; + height: 2.5%; +} + +#highlight-2 { + left: 10%; + top: 23.1%; + width: 78%; + height: 5%; +} + +#highlight-3 { + left: 27.3%; + top: 26.7%; + width: 26%; + height: 2.5%; +} + +#highlight-4 { + left: 53.2%; + top: 24.3%; + width: 28.4%; + height: 2.5%; +} + +#highlight-5 { + left: 10%; + top: 24%; + width: 79%; + height: 4.5%; +} + +#highlight-6 { + left: 19%; + top: 23.8%; + width: 67%; + height: 2.5%; +} + +#highlight-7 { + left: 15%; + top: 23.5%; + width: 61.5%; + height: 2.5%; +} + +#highlight-8 { + left: 10%; + top: 27.5%; + width: 79%; + height: 2.5%; +} + +#highlight-9 { + left: 10%; + top: 29.2%; + width: 79%; + height: 5%; +} + +#highlight-10 { + left: 10%; + top: 50.3%; + width: 79%; + height: 5%; +} + +#highlight-11 { + left: 10%; + top: 54%; + width: 79%; + height: 5%; +} + +#highlight-12 { + left: 10%; + top: 34.3%; + width: 79%; + height: 5%; +} + +#highlight-13 { + left: 10%; + top: 57%; + width: 79%; + height: 10%; +} + +#highlight-14 { + left: 10%; + top: 71.5%; + width: 79%; + height: 5%; +} + +#highlight-15 { + left: 10%; + top: 19%; + width: 79%; + height: 10%; +} + +#highlight-16 { + left: 10%; + top: 46%; + width: 79%; + height: 23%; +} + +#highlight-17 { + left: 8%; + top: 32%; + width: 84%; + height: 9%; +} + +.annotation-container { + left: calc(50% + 250px); + height: 100%; + top: 0; + position: absolute; +} + +.sticky { + position: sticky; + top: 40px; + height: calc(100vh - 40px); +} + +.annotation-card { + position: absolute; + top: 50%; + transform: translateY(-50%); + background-color: white; + transition: all 0.1s ease; +} + +.annotation-card-inner { + left: 0; + position: relative; + height: auto; + top: 0; + max-height: calc(100vh - 90px); + width: 400px; + padding: 18px; + border: none; + border-left: 5px solid #800000; +} + +.annotation-card-text { + padding: 0 20px; + font-size: 17px; + font-family: Georgia, 'Times New Roman', Times, serif; + color: #444; + animation: fadeIn 0.2s ease-in-out forwards; +} + +.annotation-card-text a { + color: #800000; + text-decoration: none; +} + +.annotation-card-text a:hover { + text-decoration: underline; +} + +#annotation-logo { + content: ''; + position: absolute; + bottom: -15px; + right: -15px; + width: 50px; + height: 50px; + border-radius: 10px; + background-color: rgba(128, 0, 0, 0.2); +} + +#annotation-logo-c { + display: flex; + justify-content: center; + align-items: center; + height: 100%; +} + +#annotation-logo-c img { + width: 80%; +} + +#footer { + padding-block: 50px; +} + +.more-title { + font-size: 24px; + text-align: left; + font-family: Georgia, serif; + color: #000000; + font-weight: 400; + margin-bottom: 20px; +} + +.more-container { + width: 70%; + margin: auto; +} + +.more-articles { + display: flex; + justify-content: space-around; /* Distribute space evenly */ + align-items: stretch; /* Make all containers the same height */ + width: 100%; +} + +.article-container-outer { + display: flex; + flex-direction: column; + width: 30%; /* Adjust as needed for spacing */ +} + +.article-container-outer a { + text-decoration: none; +} + +.article-container { + display: flex; + flex-direction: column; + border: 1px solid #ccc; /* Optional: for visual separation */ + border-radius: 8px; /* Optional: for rounded corners */ + overflow: hidden; /* Ensure content doesn't overflow the container */ + background: #eeeeee; + height: 300px; +} + +.article-container:hover { + box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); +} +.article-container:hover .article-img img { + transform: scale(1.1); +} + +.article-container a { + display: block; +} + +.article-img { + margin: auto; + width: 150px; + overflow: hidden; /* Clip images that exceed the container */ +} + +.article-img img { + width: 100%; + height: auto; + object-fit: cover; +} + +.article-title { + height: 50%; + font-family: Georgia, serif; + font-size: 18px; + line-height: 1.35em; + padding: 15px 15px; + color: #000000; + text-decoration: none; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; + } +} + +.fade-out { + animation: fadeOut 0.2s ease-in-out forwards; +} + +.fade-in { + animation: fadeIn 0.2s ease-in-out forwards; +} + +@media (max-width: 1350px) { + .annotation-container { + left: calc(50% + 120px); + } + + #doc-container { + max-width: 580px; + } +} + +@media screen and (max-width: 1075px) { + /* change header */ + + .header-container { + flex-direction: column; /* Stack the title container below the image */ + height: auto; /* Adjust height to fit content */ + position: relative; + margin-bottom: 20px; + } + + .header-img img { + width: auto; + max-height: 60vh; + } + + .header-title-container { + margin-top: 20px; + width: 100%; /* Take full width */ + order: 2; /* Push to the bottom */ + background-color: white; + } + + #title, + #subtitle { + color: black; + } + + .header-maroon { + position: absolute; + top: 0; + left: 50%; + transform: translateX(-50%); + width: 100%; + height: auto; + display: flex; + justify-content: center; + } + + .header-maroon img { + width: 200px; + height: auto; + } + + #header-title { + width: 90%; + } + + .annotation-container { + left: 0; + width: 100%; + } + + #content-container { + padding-bottom: 200px; + } + + #doc-container { + left: 0; + } + + .sticky { + top: 0; + } + .annotation-card { + top: 80%; + } + + .annotation-card-inner { + border: 5px solid #800000; + width: 100%; + } + + .annotation-card-text { + font-size: 15px; + } + + #annotation-logo { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 30px; + height: 30px; + border-radius: 10px; + background-color: rgba(128, 0, 0, 0.2); + } + + #intro-text { + width: 90%; + } + + #title { + font-size: 28px; + } + + .title-box img { + width: 50%; + margin-top: 10px; + } + + .title-container { + padding-top: 50px; + } + + .title-box { + flex-direction: column; + } + + #byline { + font-size: 13px; + } + + #subtitle { + font-size: 20px; + } + + .more-articles { + flex-direction: column; /* Stack article containers */ + } + + .article-container-outer { + width: 100%; + } + + .article-container { + margin-bottom: 20px; /* Add spacing between articles */ + } +}