add main html and test files
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								server_files/dogpepsi.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								server_files/dogpepsi.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 35 KiB  | 
							
								
								
									
										35
									
								
								server_files/dogpepsi.jpg.import
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								server_files/dogpepsi.jpg.import
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					[remap]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					importer="texture"
 | 
				
			||||||
 | 
					type="StreamTexture"
 | 
				
			||||||
 | 
					path="res://.import/dogpepsi.jpg-600a9f60613039ee9dabc11447d355f1.stex"
 | 
				
			||||||
 | 
					metadata={
 | 
				
			||||||
 | 
					"vram_texture": false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[deps]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source_file="res://server_files/dogpepsi.jpg"
 | 
				
			||||||
 | 
					dest_files=[ "res://.import/dogpepsi.jpg-600a9f60613039ee9dabc11447d355f1.stex" ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[params]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					compress/mode=0
 | 
				
			||||||
 | 
					compress/lossy_quality=0.7
 | 
				
			||||||
 | 
					compress/hdr_mode=0
 | 
				
			||||||
 | 
					compress/bptc_ldr=0
 | 
				
			||||||
 | 
					compress/normal_map=0
 | 
				
			||||||
 | 
					flags/repeat=0
 | 
				
			||||||
 | 
					flags/filter=true
 | 
				
			||||||
 | 
					flags/mipmaps=false
 | 
				
			||||||
 | 
					flags/anisotropic=false
 | 
				
			||||||
 | 
					flags/srgb=2
 | 
				
			||||||
 | 
					process/fix_alpha_border=true
 | 
				
			||||||
 | 
					process/premult_alpha=false
 | 
				
			||||||
 | 
					process/HDR_as_SRGB=false
 | 
				
			||||||
 | 
					process/invert_color=false
 | 
				
			||||||
 | 
					process/normal_map_invert_y=false
 | 
				
			||||||
 | 
					stream=false
 | 
				
			||||||
 | 
					size_limit=0
 | 
				
			||||||
 | 
					detect_3d=true
 | 
				
			||||||
 | 
					svg/scale=1.0
 | 
				
			||||||
							
								
								
									
										3
									
								
								server_files/files.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								server_files/files.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					first.md 2022-01-06 first article
 | 
				
			||||||
 | 
					second.md 2021-05-03 second article
 | 
				
			||||||
 | 
					second.md
 | 
				
			||||||
							
								
								
									
										47
									
								
								server_files/first.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								server_files/first.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					# Importance of Second Opinions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A Mayo Clinic study found that
 | 
				
			||||||
 | 
					Only 1/10 cases of patients seeking second opinions
 | 
				
			||||||
 | 
					received confirmation the first diagnosis was complete and correct
 | 
				
			||||||
 | 
					2/10 cases received a "distinctly different" diagnosis
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Yale Medecine recommends to seek a second opinion
 | 
				
			||||||
 | 
					when the diagnosis is cancer 
 | 
				
			||||||
 | 
					or
 | 
				
			||||||
 | 
					when surgery is recommended
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please tell your loved ones to seek 2nd opinions!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					First Opinions are often bad:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- https://newsnetwork.mayoclinic.org/discussion/mayo-clinic-researchers-demonstrate-value-of-second-opinions/
 | 
				
			||||||
 | 
					- https://newsnetwork.mayoclinic.org/discussion/mayo-clinic-researchers-demonstrate-value-of-second-opinions/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Key points:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> The Mayo Clinic study found that as many as
 | 
				
			||||||
 | 
					> - 9 out of 10 patients seeking a second opinion go home with a new or refined diagnosis.
 | 
				
			||||||
 | 
					> - 2 out of ten received a “distinctly different” diagnosis.
 | 
				
			||||||
 | 
					>- only 1 out of 10 referred patients receive confirmation that the original
 | 
				
			||||||
 | 
					> diagnosis was complete and correct.
 | 
				
			||||||
 | 
					> This is _out of patients seeking a 2nd opinion_, not patients in general
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Paper referenced by articles found at: https://onlinelibrary.wiley.com/doi/abs/10.1111/jep.12747
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When to Seek 2nd Opinions according to Yale
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- https://www.yalemedicine.org/news/second-opinions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Key points:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> Seek 2nd opinion:
 | 
				
			||||||
 | 
					> - When the diagnosis is cancer
 | 
				
			||||||
 | 
					> - **When surgery is recommended**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
							
								
								
									
										405
									
								
								server_files/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										405
									
								
								server_files/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,405 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					    <title>Parcel Sandbox</title>
 | 
				
			||||||
 | 
					    <meta charset="UTF-8" />
 | 
				
			||||||
 | 
					    <style></style>
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					  <body>
 | 
				
			||||||
 | 
					    <template id="my-link">
 | 
				
			||||||
 | 
					      <style>
 | 
				
			||||||
 | 
					        :host {
 | 
				
			||||||
 | 
					          --background-regular: hsla(196, 61%, 58%, 0.75);
 | 
				
			||||||
 | 
					          --background-active: red;
 | 
				
			||||||
 | 
					          text-decoration: none;
 | 
				
			||||||
 | 
					          color: #18272f;
 | 
				
			||||||
 | 
					          font-weight: 700;
 | 
				
			||||||
 | 
					          cursor: pointer;
 | 
				
			||||||
 | 
					          position: relative;
 | 
				
			||||||
 | 
					          display: flex;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :host span {
 | 
				
			||||||
 | 
					          width: 100%;
 | 
				
			||||||
 | 
					          height: 100%;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :host::before {
 | 
				
			||||||
 | 
					          content: "";
 | 
				
			||||||
 | 
					          background-color: var(--background-regular);
 | 
				
			||||||
 | 
					          position: absolute;
 | 
				
			||||||
 | 
					          left: 0;
 | 
				
			||||||
 | 
					          bottom: 3px;
 | 
				
			||||||
 | 
					          width: 100%;
 | 
				
			||||||
 | 
					          height: 8px;
 | 
				
			||||||
 | 
					          z-index: -1;
 | 
				
			||||||
 | 
					          transition: all 0.3s ease-in-out;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :host(:hover)::before {
 | 
				
			||||||
 | 
					          bottom: 0;
 | 
				
			||||||
 | 
					          height: 100%;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :host([active])::before {
 | 
				
			||||||
 | 
					          background-color: var(--background-active);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <span><slot /></span>
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					    <template id="my-menu">
 | 
				
			||||||
 | 
					      <style>
 | 
				
			||||||
 | 
					        :host ul,
 | 
				
			||||||
 | 
					        :host li {
 | 
				
			||||||
 | 
					          list-style: none;
 | 
				
			||||||
 | 
					          padding: 0;
 | 
				
			||||||
 | 
					          margin: 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        :host nav {
 | 
				
			||||||
 | 
					          display: flex;
 | 
				
			||||||
 | 
					          flex-direction: column;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      </style>
 | 
				
			||||||
 | 
					      <nav>
 | 
				
			||||||
 | 
					        <slot />
 | 
				
			||||||
 | 
					      </nav>
 | 
				
			||||||
 | 
					    </template>
 | 
				
			||||||
 | 
					    <my-menu id="menu">
 | 
				
			||||||
 | 
					      <my-link main href="d">Home</my-link>
 | 
				
			||||||
 | 
					      <h2>Articles</h2>
 | 
				
			||||||
 | 
					    </my-menu>
 | 
				
			||||||
 | 
					    <div id="App"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <script>
 | 
				
			||||||
 | 
					      //@ts-check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**********************************************************************
 | 
				
			||||||
 | 
					       *
 | 
				
			||||||
 | 
					       * UTILITIES
 | 
				
			||||||
 | 
					       *
 | 
				
			||||||
 | 
					       * A few common methods to use in the project
 | 
				
			||||||
 | 
					       *
 | 
				
			||||||
 | 
					       *********************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const Signal = () => {
 | 
				
			||||||
 | 
					        const listeners = new Set();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          remove: listeners.delete.bind(listeners),
 | 
				
			||||||
 | 
					          add(/** @type {(arg:any)=>void} */ listener) {
 | 
				
			||||||
 | 
					            listeners.add(listener);
 | 
				
			||||||
 | 
					            return listeners.delete.bind(listeners, listener);
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          emit(/** @type {any} */ data) {
 | 
				
			||||||
 | 
					            listeners.forEach((l) => l(data));
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const getText = (/** @type {string} */ file) =>
 | 
				
			||||||
 | 
					        fetch(`./${file}`)
 | 
				
			||||||
 | 
					          .then((response) => response.text())
 | 
				
			||||||
 | 
					          .catch((err) => {
 | 
				
			||||||
 | 
					            console.error(`could not find file "${file}"`);
 | 
				
			||||||
 | 
					            throw err;
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const parseMarkdown = (/** @type {string} */ text) =>
 | 
				
			||||||
 | 
					        text
 | 
				
			||||||
 | 
					          // lists
 | 
				
			||||||
 | 
					          .replace(
 | 
				
			||||||
 | 
					            /^\s*\n((?:\*\s.+\s*\n)+)([^\*])/gm,
 | 
				
			||||||
 | 
					            (_, bullets, next) =>
 | 
				
			||||||
 | 
					              `<ul>${bullets.replace(
 | 
				
			||||||
 | 
					                /^\*\s(.+)/gm,
 | 
				
			||||||
 | 
					                "<li>$1</li>"
 | 
				
			||||||
 | 
					              )}\n</ul>\n\n${next}`
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					          .replace(
 | 
				
			||||||
 | 
					            /^\s*\n((?:\d\..+\s*\n)+)([^\*])/gm,
 | 
				
			||||||
 | 
					            (_, bullets, next) =>
 | 
				
			||||||
 | 
					              `<ol>${bullets.replace(
 | 
				
			||||||
 | 
					                /^\d\.\s(.+)/gm,
 | 
				
			||||||
 | 
					                "<li>$1</li>"
 | 
				
			||||||
 | 
					              )}\n</ol>\n\n${next}`
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					          // blockquotes
 | 
				
			||||||
 | 
					          .replace(/^\>(.+)/gm, "<blockquote>$1</blockquote>")
 | 
				
			||||||
 | 
					          // headers
 | 
				
			||||||
 | 
					          .replace(/(#+)(.+)/g, (_, { length: l }, t) => `<h${l}>${t}</h${l}>`)
 | 
				
			||||||
 | 
					          .replace(/^(.+)\n\=+/gm, "<h1>$1</h1>")
 | 
				
			||||||
 | 
					          .replace(/^(.+)\n\-+/gm, "<h2>$1</h2>")
 | 
				
			||||||
 | 
					          //images
 | 
				
			||||||
 | 
					          .replace(/\!\[([^\]]+)\]\(([^\)]+)\)/g, '<img src="$2" alt="$1" />')
 | 
				
			||||||
 | 
					          //links
 | 
				
			||||||
 | 
					          .replace(
 | 
				
			||||||
 | 
					            /[\[]{1}([^\]]+)[\]]{1}[\(]{1}([^\)\"]+)(\"(.+)\")?[\)]{1}/g,
 | 
				
			||||||
 | 
					            '<a href="$2" title="$4">$1</a>'
 | 
				
			||||||
 | 
					          )
 | 
				
			||||||
 | 
					          //font styles
 | 
				
			||||||
 | 
					          .replace(/[\*\_]{2}([^\*\_]+)[\*\_]{2}/g, "<strong>$1</strong>")
 | 
				
			||||||
 | 
					          .replace(/[\*\_]{1}([^\*\_]+)[\*\_]{1}/g, "<em>$1</em>")
 | 
				
			||||||
 | 
					          .replace(/[\~]{2}([^\~]+)[\~]{2}/g, "<del>$1</del>")
 | 
				
			||||||
 | 
					          //pre
 | 
				
			||||||
 | 
					          .replace(/^\s*\n\`\`\`(([^\s]+))?/gm, '<pre class="$2">')
 | 
				
			||||||
 | 
					          .replace(/^\`\`\`\s*\n/gm, "</pre>\n\n")
 | 
				
			||||||
 | 
					          //code
 | 
				
			||||||
 | 
					          .replace(/[\`]{1}([^\`]+)[\`]{1}/g, "<code>$1</code>")
 | 
				
			||||||
 | 
					          //p
 | 
				
			||||||
 | 
					          .replace(/^\s*(\n)?(.+)/gm, (m) => {
 | 
				
			||||||
 | 
					            return /\<(\/)?(h\d|ul|ol|li|blockquote|pre|img)/.test(m)
 | 
				
			||||||
 | 
					              ? m
 | 
				
			||||||
 | 
					              : "<p>" + m + "</p>";
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          //strip p from pre
 | 
				
			||||||
 | 
					          .replace(/(\<pre.+\>)\s*\n\<p\>(.+)\<\/p\>/gm, "$1$2")
 | 
				
			||||||
 | 
					          .trim();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const getMarkdown = (/** @type {string} */ file) =>
 | 
				
			||||||
 | 
					        getText(file).then(parseMarkdown);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**
 | 
				
			||||||
 | 
					       *
 | 
				
			||||||
 | 
					       * @param {string} tag
 | 
				
			||||||
 | 
					       * @param {Record<string, any>} props
 | 
				
			||||||
 | 
					       * @param {string|Node[]} children
 | 
				
			||||||
 | 
					       * @returns
 | 
				
			||||||
 | 
					       */
 | 
				
			||||||
 | 
					      const el = (tag = "div", props = {}, children = []) => {
 | 
				
			||||||
 | 
					        const node = document.createElement(tag);
 | 
				
			||||||
 | 
					        Object.keys(props).forEach((key) => {
 | 
				
			||||||
 | 
					          node.setAttribute(key, props[key]);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        if (typeof children == "string") {
 | 
				
			||||||
 | 
					          children = [document.createTextNode(children)];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        children.forEach((child) => node.appendChild(child));
 | 
				
			||||||
 | 
					        return node;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const makeTitelize = (alwaysLowCaps = [], alwaysUpperCaps = []) => {
 | 
				
			||||||
 | 
					        const specials = [...alwaysLowCaps, ...alwaysUpperCaps].reduce(
 | 
				
			||||||
 | 
					          (result, word) =>
 | 
				
			||||||
 | 
					            result.set(new RegExp("\\b" + word + "\\b", "gi"), word),
 | 
				
			||||||
 | 
					          /** @type {Map<RegExp, string>}*/ (new Map())
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        const titelize = (/** @type {string} */ text) => {
 | 
				
			||||||
 | 
					          text = text
 | 
				
			||||||
 | 
					            .replace(/_-\//g, " ")
 | 
				
			||||||
 | 
					            .replace(/\.\w+$/, "")
 | 
				
			||||||
 | 
					            .replace(/\s+/, " ")
 | 
				
			||||||
 | 
					            .split(" ")
 | 
				
			||||||
 | 
					            .map((word) =>
 | 
				
			||||||
 | 
					              word.length > 1
 | 
				
			||||||
 | 
					                ? word[0].toUpperCase() + word.slice(1).toLowerCase()
 | 
				
			||||||
 | 
					                : word
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .join(" ");
 | 
				
			||||||
 | 
					          for (const [key, value] of specials) {
 | 
				
			||||||
 | 
					            text = text.replace(key, value);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return text;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        return titelize;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const titelize = makeTitelize(["the", "a"], ["TV", "ID", "AI"]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const Router = (() => {
 | 
				
			||||||
 | 
					        const onRouteChange = Signal();
 | 
				
			||||||
 | 
					        let route = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const set = (/** @type {string} */ newRoute) => {
 | 
				
			||||||
 | 
					          if (newRoute === route) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          window.location.hash = newRoute;
 | 
				
			||||||
 | 
					          route = newRoute;
 | 
				
			||||||
 | 
					          onRouteChange.emit(route);
 | 
				
			||||||
 | 
					          return true;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const get = () => window.location.hash.slice(1).replace(/\//gi, "/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const is = (href) => href === get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        window.addEventListener("popstate", () => set(get()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return { set, get, is, onRouteChange };
 | 
				
			||||||
 | 
					      })();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const getTemplateClone = (/** @type {string} */ id) => {
 | 
				
			||||||
 | 
					        const templateModel = /** @type {HTMLTemplateElement} */ (
 | 
				
			||||||
 | 
					          document.getElementById(id)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        const template = /** @type {HTMLElement} */ (
 | 
				
			||||||
 | 
					          templateModel.content.cloneNode(true)
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        return template;
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**********************************************************************
 | 
				
			||||||
 | 
					       * WEB COMPONENTS
 | 
				
			||||||
 | 
					       *
 | 
				
			||||||
 | 
					       * Sources:
 | 
				
			||||||
 | 
					       * https://web.dev/custom-elements-best-practices/
 | 
				
			||||||
 | 
					       * https://googlechromelabs.github.io/howto-components/
 | 
				
			||||||
 | 
					       *
 | 
				
			||||||
 | 
					       * A set of neat components to use in the page
 | 
				
			||||||
 | 
					       *
 | 
				
			||||||
 | 
					       *********************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      class CustomElement extends HTMLElement {
 | 
				
			||||||
 | 
					        /** @type {ShadowRoot} */
 | 
				
			||||||
 | 
					        shadow = this.attachShadow({ mode: "closed" });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /**
 | 
				
			||||||
 | 
					         * A user may set a property on an instance of an element, before its prototype has been connected to this class.
 | 
				
			||||||
 | 
					         * Will check for any instance properties and run them through the proper class setters.
 | 
				
			||||||
 | 
					         * @param {string} prop
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        _syncProperty(prop) {
 | 
				
			||||||
 | 
					          if (this.hasOwnProperty(prop)) {
 | 
				
			||||||
 | 
					            let value = this[prop];
 | 
				
			||||||
 | 
					            delete this[prop];
 | 
				
			||||||
 | 
					            this[prop] = value;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      class MyLink extends CustomElement {
 | 
				
			||||||
 | 
					        constructor() {
 | 
				
			||||||
 | 
					          super();
 | 
				
			||||||
 | 
					          this.shadow.append(getTemplateClone("my-link"));
 | 
				
			||||||
 | 
					          this.shadow.addEventListener("click", this._onClick.bind(this));
 | 
				
			||||||
 | 
					          Router.onRouteChange.add(this.updateActive.bind(this));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        static get observedAttributes() {
 | 
				
			||||||
 | 
					          return ["href", "active", "main"];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        _onClick() {
 | 
				
			||||||
 | 
					          if (this.href) {
 | 
				
			||||||
 | 
					            Router.set(this.href);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        attributeChangedCallback(property, oldValue, newValue) {
 | 
				
			||||||
 | 
					          if (oldValue === newValue) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          this[property] = newValue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        updateActive() {
 | 
				
			||||||
 | 
					          if (Router.is(this.href)) {
 | 
				
			||||||
 | 
					            this.setAttribute("active", "");
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            this.removeAttribute("active");
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        set href(/** @type {string}*/ value) {
 | 
				
			||||||
 | 
					          this.setAttribute("href", value);
 | 
				
			||||||
 | 
					          this.updateActive();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        get href() {
 | 
				
			||||||
 | 
					          return this.getAttribute("href");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        set main(/** @type {boolean}*/ value) {
 | 
				
			||||||
 | 
					          if (value) {
 | 
				
			||||||
 | 
					            this.setAttribute("main", "");
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            this.removeAttribute("main");
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        get main() {
 | 
				
			||||||
 | 
					          return this.hasAttribute("main");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        connectedCallback() {
 | 
				
			||||||
 | 
					          ["active", "main"].forEach((prop) => this._syncProperty(prop));
 | 
				
			||||||
 | 
					          this.updateActive();
 | 
				
			||||||
 | 
					          if (this.getAttribute("main")) {
 | 
				
			||||||
 | 
					            console.log("sdfsdff");
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      customElements.define("my-link", MyLink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      class MyMenu extends CustomElement {
 | 
				
			||||||
 | 
					        _handled = new Set();
 | 
				
			||||||
 | 
					        constructor() {
 | 
				
			||||||
 | 
					          super();
 | 
				
			||||||
 | 
					          this.shadow.append(getTemplateClone("my-menu"));
 | 
				
			||||||
 | 
					          const slot = this.shadow.querySelector("slot");
 | 
				
			||||||
 | 
					          slot.addEventListener("slotchange", (event) => {
 | 
				
			||||||
 | 
					            for (const child of slot.assignedElements()) {
 | 
				
			||||||
 | 
					              if (this._handled.has(child) || !(child instanceof MyLink)) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              this._handled.add(child);
 | 
				
			||||||
 | 
					              // TODO: pre-fetch
 | 
				
			||||||
 | 
					              //console.log("new child: ", child);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      customElements.define("my-menu", MyMenu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**********************************************************************
 | 
				
			||||||
 | 
					       * MARKDOWN PARSING
 | 
				
			||||||
 | 
					       *********************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const load = (/** @type {string} */ file) =>
 | 
				
			||||||
 | 
					        getMarkdown(file).then((md) => {
 | 
				
			||||||
 | 
					          app.innerHTML = md;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      /**********************************************************************
 | 
				
			||||||
 | 
					       * BOOSTRAPPING
 | 
				
			||||||
 | 
					       *********************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      getText("files.txt").then((lines) => {
 | 
				
			||||||
 | 
					        lines
 | 
				
			||||||
 | 
					          .split(`\n`)
 | 
				
			||||||
 | 
					          .map((line) => {
 | 
				
			||||||
 | 
					            const [file, maybeDate, ...rest] = line.split(/\s/);
 | 
				
			||||||
 | 
					            const href = file.trim();
 | 
				
			||||||
 | 
					            let date = maybeDate ? new Date(maybeDate) : new Date();
 | 
				
			||||||
 | 
					            if (isNaN(date.getTime())) {
 | 
				
			||||||
 | 
					              date = new Date();
 | 
				
			||||||
 | 
					              rest.unshift(maybeDate);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            const textContent = rest.length
 | 
				
			||||||
 | 
					              ? rest.join(" ").trim()
 | 
				
			||||||
 | 
					              : titelize(file);
 | 
				
			||||||
 | 
					            return { href, date, textContent };
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .sort(({ date: a }, { date: b }) => a.getTime() - b.getTime())
 | 
				
			||||||
 | 
					          .forEach(({ href, date, textContent }) => {
 | 
				
			||||||
 | 
					            const link = /** @type {MyLink} */ el(
 | 
				
			||||||
 | 
					              "my-link",
 | 
				
			||||||
 | 
					              { href },
 | 
				
			||||||
 | 
					              textContent
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            document.getElementById("menu").appendChild(link);
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const app = document.getElementById("App");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const BLOCKQUOTE = Symbol("blockquote");
 | 
				
			||||||
 | 
					      const PARAGRAPH = Symbol("paragraph");
 | 
				
			||||||
 | 
					      const LIST = Symbol("list");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Router.onRouteChange.add((route) => load(route));
 | 
				
			||||||
 | 
					    </script>
 | 
				
			||||||
 | 
					  </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										1
									
								
								server_files/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								server_files/index.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					# Title
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								server_files/picture.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								server_files/picture.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 1.0 MiB  | 
							
								
								
									
										35
									
								
								server_files/picture.png.import
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								server_files/picture.png.import
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					[remap]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					importer="texture"
 | 
				
			||||||
 | 
					type="StreamTexture"
 | 
				
			||||||
 | 
					path="res://.import/picture.png-f7b364942b19109d5768d9400167481e.stex"
 | 
				
			||||||
 | 
					metadata={
 | 
				
			||||||
 | 
					"vram_texture": false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[deps]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					source_file="res://server_files/picture.png"
 | 
				
			||||||
 | 
					dest_files=[ "res://.import/picture.png-f7b364942b19109d5768d9400167481e.stex" ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[params]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					compress/mode=0
 | 
				
			||||||
 | 
					compress/lossy_quality=0.7
 | 
				
			||||||
 | 
					compress/hdr_mode=0
 | 
				
			||||||
 | 
					compress/bptc_ldr=0
 | 
				
			||||||
 | 
					compress/normal_map=0
 | 
				
			||||||
 | 
					flags/repeat=0
 | 
				
			||||||
 | 
					flags/filter=true
 | 
				
			||||||
 | 
					flags/mipmaps=false
 | 
				
			||||||
 | 
					flags/anisotropic=false
 | 
				
			||||||
 | 
					flags/srgb=2
 | 
				
			||||||
 | 
					process/fix_alpha_border=true
 | 
				
			||||||
 | 
					process/premult_alpha=false
 | 
				
			||||||
 | 
					process/HDR_as_SRGB=false
 | 
				
			||||||
 | 
					process/invert_color=false
 | 
				
			||||||
 | 
					process/normal_map_invert_y=false
 | 
				
			||||||
 | 
					stream=false
 | 
				
			||||||
 | 
					size_limit=0
 | 
				
			||||||
 | 
					detect_3d=true
 | 
				
			||||||
 | 
					svg/scale=1.0
 | 
				
			||||||
							
								
								
									
										20
									
								
								server_files/second.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								server_files/second.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					# Testing markdown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is a test of **markdown** parsing. Again. Because why not?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Why:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Item1
 | 
				
			||||||
 | 
					2. Item2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> Blockquote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Image:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					code_block!
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`code not block`
 | 
				
			||||||
		Reference in New Issue
	
	Block a user