About Me
115 |Goals
121 |Education
124 |Experience
127 |Thanks for checking out my web site!
133 | 134 | 135 | 136 | 137 |├── .gitignore ├── .nojekyll ├── README.md ├── _quarto.yml ├── docs ├── img │ └── profile.png ├── index.html ├── projects.html ├── search.json └── site_libs │ ├── bootstrap │ ├── bootstrap-icons.css │ ├── bootstrap-icons.woff │ ├── bootstrap.min.css │ └── bootstrap.min.js │ ├── clipboard │ └── clipboard.min.js │ ├── quarto-html │ ├── anchor.min.js │ ├── popper.min.js │ ├── quarto-syntax-highlighting.css │ ├── quarto.js │ ├── tippy.css │ └── tippy.umd.min.js │ ├── quarto-nav │ ├── headroom.min.js │ └── quarto-nav.js │ └── quarto-search │ ├── autocomplete.umd.js │ ├── fuse.min.js │ └── quarto-search.js ├── img └── profile.png ├── index.qmd ├── projects.qmd └── website-template.Rproj /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /.nojekyll: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # website-template 2 | 3 | [Video tutorial](https://youtu.be/YN75YXaLFGM) 4 | 5 | This is a template for creating a Quarto web site using RStudio. 6 | 7 | To use it effectively you need to know how to push and pull from GitHub to RStudio using the Git panel buttons, which requires a working GitHub personal access token (PAT). If you don't have one setup, following [these instructions](https://happygitwithr.com/https-pat.html#tldr) in *Happy Git and GitHub for the useR* to set one up. (In short you will create a token for HTTPS and store it using **gitcreds**.) 8 | 9 | In addition open RStudio and update to the latest version by clicking "Help" "Check for Updates". (This is necessary to ensure that Quarto is installed.) 10 | 11 | ## ABSOLUTE ESSENTIALS 12 | 13 | *If you have any difficulties or have feedback of any kind, please file an issue or communicate through [Discussions](https://github.com/jtr13/website-template/discussions).* 14 | 15 | ### Copy this template (GitHub) 16 | 17 | - [ ] 1. Click the green "Use this template" button above. (You need to login to GitHub to see this option). Choose the "Create a new repository" option. DO NOT FORK THE REPO. Choose a descriptive name for your repo based on your content. (Unlike when you fork a repo, you get to choose the name. If you change your mind before you do any work, delete your new repo and start over.) Leave the "Public" option checked or else GitHub Pages won't work. 18 | 19 | ### Set up Pages (GitHub) 20 | 21 | - [ ] 1. You've now left the template page and are viewing your new repo on GitHub. On the home page, click Settings. Click the "Pages" section on the left. In the **Build and Deployment** section, set **Source** to "Deploy from a branch" (Classic Pages experience) and **Branch** to **main** with **/docs** folder. Click Save. 22 | 23 | - [ ] 2. Click the little gear button near "About" on the top right side of the home page of the repo and check the "Use your Github Pages website" box under "Website". Click "Save changes". Test the link and you should see a web site with a stick figure on it. It may take a few minutes to build so if it's not working do a few more steps and then come back to check. 24 | 25 | ### Copy the repo link (GitHub) 26 | 27 | - [ ] 1. Click the green Code button, choose "HTTPS" and copy the link below. It should have the format: `https://github.com/[USERNAME]/[REPO NAME].git` 28 | 29 | ### Clone the repo (RStudio) 30 | 31 | - [ ] 1. Clone your new repo with *File, New Project..., Version Control, Git* in RStudio. You will need to paste the link from the previous step in the Repository URL box. If it's not automatically populated, enter the repo name in the "Project directory name:" box. Choose the location of the project 32 | 33 | ### Edit `_quarto.yml` (RStudio) 34 | 35 | Tip: From the file pane in RStudio, open `README.md`, which contains these instructions. You can delete steps as you complete them. 36 | 37 | - [ ] 1. Edit the all caps info in `_quarto.yml` to your info. It's very important to maintain the indenting structure in this file precisely as is -- be careful! 38 | 39 | ### Render the web site (RStudio) 40 | 41 | - [ ] 1. If you haven't already, click "Help" "Check for Updates" to make sure you have the latest version of RStudio (and thus have Quarto installed.) 42 | 43 | - [ ] 2. Render the web site locally by clicking the "Build" tap on the right and then "Render Website". 44 | 45 | - [ ] 3. Use `browseURL("docs/index.html")` to view your site locally (or just open `docs/index.html` in a browser). 46 | 47 | - [ ] 4. If it looks good, commit and push all changed files to GitHub. 48 | 49 | (You will need to repeat steps 2 and 4 every time you wish to update the book online.) 50 | 51 | ### Next steps 52 | 53 | - Add content to `index.qmd` as desired. 54 | 55 | - Add content to `projects.qmd` as desired. 56 | 57 | - Change the photo in the `img` folder to your photo. 58 | 59 | - Choose a theme from [https://bootswatch.com/](https://bootswatch.com/) and replace "cerulean" in `_quarto.yml` with your prefered theme. 60 | 61 | - Add additional tabs/sections by creating new `.qmd` files and listing them in `_quarto.yml` under `projects.qmd`. 62 | 63 | ### Additional features 64 | 65 | Please consult the official guide to **quarto** web sites: [https://quarto.org/docs/websites/](https://quarto.org/docs/websites/) 66 | 67 | ### Last but not least 68 | 69 | Once you've completed these steps, delete the content of this **README** and add a short description of your project with a link to the book URL. It would be appreciated if you add the following to the end: 70 | 71 | *This repo was initially generated from a Quarto template available here: https://github.com/jtr13/website-template.* 72 | 73 | (If you found this helpful, please let us know by starring the repo. ⭐ 😄) 74 | 75 | -------------------------------------------------------------------------------- /_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: website 3 | output-dir: docs 4 | 5 | website: 6 | title: "MY WEB SITE" 7 | navbar: 8 | left: 9 | - href: index.qmd 10 | text: Home 11 | - projects.qmd 12 | tools: 13 | - icon: twitter 14 | href: https://twitter.com/ 15 | - icon: github 16 | href: https://github.com/YOURUSERNAME/YOURREPO 17 | page-footer: 18 | right: "Built with [Quarto](https://quarto.org/)" 19 | left: "© Copyright 2023, YOUR NAME" 20 | 21 | format: 22 | html: 23 | theme: cerulean 24 | toc: true 25 | 26 | editor: source 27 | 28 | -------------------------------------------------------------------------------- /docs/img/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jtr13/website-template/c3eb589322c282087bd8d3b466a997bd1abd207b/docs/img/profile.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |${missingFields[0]} field.`,
528 | message: `The items being returned for this search do not include all the required fields. Please ensure that your index items include the ${missingFields[0]} field or use index-fields in your _quarto.yml file to specify the field names.`,
529 | };
530 | } else if (missingFields.length > 1) {
531 | const missingFieldList = missingFields
532 | .map((field) => {
533 | return `${field}`;
534 | })
535 | .join(", ");
536 |
537 | throw {
538 | name: `Error: Search index is missing the following fields: ${missingFieldList}.`,
539 | message: `The items being returned for this search do not include all the required fields. Please ensure that your index items includes the following fields: ${missingFieldList}, or use index-fields in your _quarto.yml file to specify the field names.`,
540 | };
541 | }
542 | }
543 | }
544 |
545 | let lastQuery = null;
546 | function showCopyLink(query, options) {
547 | const language = options.language;
548 | lastQuery = query;
549 | // Insert share icon
550 | const inputSuffixEl = window.document.body.querySelector(
551 | ".aa-Form .aa-InputWrapperSuffix"
552 | );
553 |
554 | if (inputSuffixEl) {
555 | let copyButtonEl = window.document.body.querySelector(
556 | ".aa-Form .aa-InputWrapperSuffix .aa-CopyButton"
557 | );
558 |
559 | if (copyButtonEl === null) {
560 | copyButtonEl = window.document.createElement("button");
561 | copyButtonEl.setAttribute("class", "aa-CopyButton");
562 | copyButtonEl.setAttribute("type", "button");
563 | copyButtonEl.setAttribute("title", language["search-copy-link-title"]);
564 | copyButtonEl.onmousedown = (e) => {
565 | e.preventDefault();
566 | e.stopPropagation();
567 | };
568 |
569 | const linkIcon = "bi-clipboard";
570 | const checkIcon = "bi-check2";
571 |
572 | const shareIconEl = window.document.createElement("i");
573 | shareIconEl.setAttribute("class", `bi ${linkIcon}`);
574 | copyButtonEl.appendChild(shareIconEl);
575 | inputSuffixEl.prepend(copyButtonEl);
576 |
577 | const clipboard = new window.ClipboardJS(".aa-CopyButton", {
578 | text: function (_trigger) {
579 | const copyUrl = new URL(window.location);
580 | copyUrl.searchParams.set(kQueryArg, lastQuery);
581 | copyUrl.searchParams.set(kResultsArg, "1");
582 | return copyUrl.toString();
583 | },
584 | });
585 | clipboard.on("success", function (e) {
586 | // Focus the input
587 |
588 | // button target
589 | const button = e.trigger;
590 | const icon = button.querySelector("i.bi");
591 |
592 | // flash "checked"
593 | icon.classList.add(checkIcon);
594 | icon.classList.remove(linkIcon);
595 | setTimeout(function () {
596 | icon.classList.remove(checkIcon);
597 | icon.classList.add(linkIcon);
598 | }, 1000);
599 | });
600 | }
601 |
602 | // If there is a query, show the link icon
603 | if (copyButtonEl) {
604 | if (lastQuery && options["copy-button"]) {
605 | copyButtonEl.style.display = "flex";
606 | } else {
607 | copyButtonEl.style.display = "none";
608 | }
609 | }
610 | }
611 | }
612 |
613 | /* Search Index Handling */
614 | // create the index
615 | var fuseIndex = undefined;
616 | async function readSearchData() {
617 | // Initialize the search index on demand
618 | if (fuseIndex === undefined) {
619 | // create fuse index
620 | const options = {
621 | keys: [
622 | { name: "title", weight: 20 },
623 | { name: "section", weight: 20 },
624 | { name: "text", weight: 10 },
625 | ],
626 | ignoreLocation: true,
627 | threshold: 0.1,
628 | };
629 | const fuse = new window.Fuse([], options);
630 |
631 | // fetch the main search.json
632 | const response = await fetch(offsetURL("search.json"));
633 | if (response.status == 200) {
634 | return response.json().then(function (searchDocs) {
635 | searchDocs.forEach(function (searchDoc) {
636 | fuse.add(searchDoc);
637 | });
638 | fuseIndex = fuse;
639 | return fuseIndex;
640 | });
641 | } else {
642 | return Promise.reject(
643 | new Error(
644 | "Unexpected status from search index request: " + response.status
645 | )
646 | );
647 | }
648 | }
649 | return fuseIndex;
650 | }
651 |
652 | function inputElement() {
653 | return window.document.body.querySelector(".aa-Form .aa-Input");
654 | }
655 |
656 | function focusSearchInput() {
657 | setTimeout(() => {
658 | const inputEl = inputElement();
659 | if (inputEl) {
660 | inputEl.focus();
661 | }
662 | }, 50);
663 | }
664 |
665 | /* Panels */
666 | const kItemTypeDoc = "document";
667 | const kItemTypeMore = "document-more";
668 | const kItemTypeItem = "document-item";
669 | const kItemTypeError = "error";
670 |
671 | function renderItem(
672 | item,
673 | createElement,
674 | state,
675 | setActiveItemId,
676 | setContext,
677 | refresh
678 | ) {
679 | switch (item.type) {
680 | case kItemTypeDoc:
681 | return createDocumentCard(
682 | createElement,
683 | "file-richtext",
684 | item.title,
685 | item.section,
686 | item.text,
687 | item.href
688 | );
689 | case kItemTypeMore:
690 | return createMoreCard(
691 | createElement,
692 | item,
693 | state,
694 | setActiveItemId,
695 | setContext,
696 | refresh
697 | );
698 | case kItemTypeItem:
699 | return createSectionCard(
700 | createElement,
701 | item.section,
702 | item.text,
703 | item.href
704 | );
705 | case kItemTypeError:
706 | return createErrorCard(createElement, item.title, item.text);
707 | default:
708 | return undefined;
709 | }
710 | }
711 |
712 | function createDocumentCard(createElement, icon, title, section, text, href) {
713 | const iconEl = createElement("i", {
714 | class: `bi bi-${icon} search-result-icon`,
715 | });
716 | const titleEl = createElement("p", { class: "search-result-title" }, title);
717 | const titleContainerEl = createElement(
718 | "div",
719 | { class: "search-result-title-container" },
720 | [iconEl, titleEl]
721 | );
722 |
723 | const textEls = [];
724 | if (section) {
725 | const sectionEl = createElement(
726 | "p",
727 | { class: "search-result-section" },
728 | section
729 | );
730 | textEls.push(sectionEl);
731 | }
732 | const descEl = createElement("p", {
733 | class: "search-result-text",
734 | dangerouslySetInnerHTML: {
735 | __html: text,
736 | },
737 | });
738 | textEls.push(descEl);
739 |
740 | const textContainerEl = createElement(
741 | "div",
742 | { class: "search-result-text-container" },
743 | textEls
744 | );
745 |
746 | const containerEl = createElement(
747 | "div",
748 | {
749 | class: "search-result-container",
750 | },
751 | [titleContainerEl, textContainerEl]
752 | );
753 |
754 | const linkEl = createElement(
755 | "a",
756 | {
757 | href: offsetURL(href),
758 | class: "search-result-link",
759 | },
760 | containerEl
761 | );
762 |
763 | const classes = ["search-result-doc", "search-item"];
764 | if (!section) {
765 | classes.push("document-selectable");
766 | }
767 |
768 | return createElement(
769 | "div",
770 | {
771 | class: classes.join(" "),
772 | },
773 | linkEl
774 | );
775 | }
776 |
777 | function createMoreCard(
778 | createElement,
779 | item,
780 | state,
781 | setActiveItemId,
782 | setContext,
783 | refresh
784 | ) {
785 | const moreCardEl = createElement(
786 | "div",
787 | {
788 | class: "search-result-more search-item",
789 | onClick: (e) => {
790 | // Handle expanding the sections by adding the expanded
791 | // section to the list of expanded sections
792 | toggleExpanded(item, state, setContext, setActiveItemId, refresh);
793 | e.stopPropagation();
794 | },
795 | },
796 | item.title
797 | );
798 |
799 | return moreCardEl;
800 | }
801 |
802 | function toggleExpanded(item, state, setContext, setActiveItemId, refresh) {
803 | const expanded = state.context.expanded || [];
804 | if (expanded.includes(item.target)) {
805 | setContext({
806 | expanded: expanded.filter((target) => target !== item.target),
807 | });
808 | } else {
809 | setContext({ expanded: [...expanded, item.target] });
810 | }
811 |
812 | refresh();
813 | setActiveItemId(item.__autocomplete_id);
814 | }
815 |
816 | function createSectionCard(createElement, section, text, href) {
817 | const sectionEl = createSection(createElement, section, text, href);
818 | return createElement(
819 | "div",
820 | {
821 | class: "search-result-doc-section search-item",
822 | },
823 | sectionEl
824 | );
825 | }
826 |
827 | function createSection(createElement, title, text, href) {
828 | const descEl = createElement("p", {
829 | class: "search-result-text",
830 | dangerouslySetInnerHTML: {
831 | __html: text,
832 | },
833 | });
834 |
835 | const titleEl = createElement("p", { class: "search-result-section" }, title);
836 | const linkEl = createElement(
837 | "a",
838 | {
839 | href: offsetURL(href),
840 | class: "search-result-link",
841 | },
842 | [titleEl, descEl]
843 | );
844 | return linkEl;
845 | }
846 |
847 | function createErrorCard(createElement, title, text) {
848 | const descEl = createElement("p", {
849 | class: "search-error-text",
850 | dangerouslySetInnerHTML: {
851 | __html: text,
852 | },
853 | });
854 |
855 | const titleEl = createElement("p", {
856 | class: "search-error-title",
857 | dangerouslySetInnerHTML: {
858 | __html: ` ${title}`,
859 | },
860 | });
861 | const errorEl = createElement("div", { class: "search-error" }, [
862 | titleEl,
863 | descEl,
864 | ]);
865 | return errorEl;
866 | }
867 |
868 | function positionPanel(pos) {
869 | const panelEl = window.document.querySelector(
870 | "#quarto-search-results .aa-Panel"
871 | );
872 | const inputEl = window.document.querySelector(
873 | "#quarto-search .aa-Autocomplete"
874 | );
875 |
876 | if (panelEl && inputEl) {
877 | panelEl.style.top = `${Math.round(panelEl.offsetTop)}px`;
878 | if (pos === "start") {
879 | panelEl.style.left = `${Math.round(inputEl.left)}px`;
880 | } else {
881 | panelEl.style.right = `${Math.round(inputEl.offsetRight)}px`;
882 | }
883 | }
884 | }
885 |
886 | /* Highlighting */
887 | // highlighting functions
888 | function highlightMatch(query, text) {
889 | if (text) {
890 | const start = text.toLowerCase().indexOf(query.toLowerCase());
891 | if (start !== -1) {
892 | const startMark = "";
893 | const endMark = "";
894 |
895 | const end = start + query.length;
896 | text =
897 | text.slice(0, start) +
898 | startMark +
899 | text.slice(start, end) +
900 | endMark +
901 | text.slice(end);
902 | const startInfo = clipStart(text, start);
903 | const endInfo = clipEnd(
904 | text,
905 | startInfo.position + startMark.length + endMark.length
906 | );
907 | text =
908 | startInfo.prefix +
909 | text.slice(startInfo.position, endInfo.position) +
910 | endInfo.suffix;
911 |
912 | return text;
913 | } else {
914 | return text;
915 | }
916 | } else {
917 | return text;
918 | }
919 | }
920 |
921 | function clipStart(text, pos) {
922 | const clipStart = pos - 50;
923 | if (clipStart < 0) {
924 | // This will just return the start of the string
925 | return {
926 | position: 0,
927 | prefix: "",
928 | };
929 | } else {
930 | // We're clipping before the start of the string, walk backwards to the first space.
931 | const spacePos = findSpace(text, pos, -1);
932 | return {
933 | position: spacePos.position,
934 | prefix: "",
935 | };
936 | }
937 | }
938 |
939 | function clipEnd(text, pos) {
940 | const clipEnd = pos + 200;
941 | if (clipEnd > text.length) {
942 | return {
943 | position: text.length,
944 | suffix: "",
945 | };
946 | } else {
947 | const spacePos = findSpace(text, clipEnd, 1);
948 | return {
949 | position: spacePos.position,
950 | suffix: spacePos.clipped ? "…" : "",
951 | };
952 | }
953 | }
954 |
955 | function findSpace(text, start, step) {
956 | let stepPos = start;
957 | while (stepPos > -1 && stepPos < text.length) {
958 | const char = text[stepPos];
959 | if (char === " " || char === "," || char === ":") {
960 | return {
961 | position: step === 1 ? stepPos : stepPos - step,
962 | clipped: stepPos > 1 && stepPos < text.length,
963 | };
964 | }
965 | stepPos = stepPos + step;
966 | }
967 |
968 | return {
969 | position: stepPos - step,
970 | clipped: false,
971 | };
972 | }
973 |
974 | // removes highlighting as implemented by the mark tag
975 | function clearHighlight(searchterm, el) {
976 | const childNodes = el.childNodes;
977 | for (let i = childNodes.length - 1; i >= 0; i--) {
978 | const node = childNodes[i];
979 | if (node.nodeType === Node.ELEMENT_NODE) {
980 | if (
981 | node.tagName === "MARK" &&
982 | node.innerText.toLowerCase() === searchterm.toLowerCase()
983 | ) {
984 | el.replaceChild(document.createTextNode(node.innerText), node);
985 | } else {
986 | clearHighlight(searchterm, node);
987 | }
988 | }
989 | }
990 | }
991 |
992 | function escapeRegExp(string) {
993 | return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
994 | }
995 |
996 | // highlight matches
997 | function highlight(term, el) {
998 | const termRegex = new RegExp(term, "ig");
999 | const childNodes = el.childNodes;
1000 |
1001 | // walk back to front avoid mutating elements in front of us
1002 | for (let i = childNodes.length - 1; i >= 0; i--) {
1003 | const node = childNodes[i];
1004 |
1005 | if (node.nodeType === Node.TEXT_NODE) {
1006 | // Search text nodes for text to highlight
1007 | const text = node.nodeValue;
1008 |
1009 | let startIndex = 0;
1010 | let matchIndex = text.search(termRegex);
1011 | if (matchIndex > -1) {
1012 | const markFragment = document.createDocumentFragment();
1013 | while (matchIndex > -1) {
1014 | const prefix = text.slice(startIndex, matchIndex);
1015 | markFragment.appendChild(document.createTextNode(prefix));
1016 |
1017 | const mark = document.createElement("mark");
1018 | mark.appendChild(
1019 | document.createTextNode(
1020 | text.slice(matchIndex, matchIndex + term.length)
1021 | )
1022 | );
1023 | markFragment.appendChild(mark);
1024 |
1025 | startIndex = matchIndex + term.length;
1026 | matchIndex = text.slice(startIndex).search(new RegExp(term, "ig"));
1027 | if (matchIndex > -1) {
1028 | matchIndex = startIndex + matchIndex;
1029 | }
1030 | }
1031 | if (startIndex < text.length) {
1032 | markFragment.appendChild(
1033 | document.createTextNode(text.slice(startIndex, text.length))
1034 | );
1035 | }
1036 |
1037 | el.replaceChild(markFragment, node);
1038 | }
1039 | } else if (node.nodeType === Node.ELEMENT_NODE) {
1040 | // recurse through elements
1041 | highlight(term, node);
1042 | }
1043 | }
1044 | }
1045 |
1046 | /* Link Handling */
1047 | // get the offset from this page for a given site root relative url
1048 | function offsetURL(url) {
1049 | var offset = getMeta("quarto:offset");
1050 | return offset ? offset + url : url;
1051 | }
1052 |
1053 | // read a meta tag value
1054 | function getMeta(metaName) {
1055 | var metas = window.document.getElementsByTagName("meta");
1056 | for (let i = 0; i < metas.length; i++) {
1057 | if (metas[i].getAttribute("name") === metaName) {
1058 | return metas[i].getAttribute("content");
1059 | }
1060 | }
1061 | return "";
1062 | }
1063 |
1064 | function algoliaSearch(query, limit, algoliaOptions) {
1065 | const { getAlgoliaResults } = window["@algolia/autocomplete-preset-algolia"];
1066 |
1067 | const applicationId = algoliaOptions["application-id"];
1068 | const searchOnlyApiKey = algoliaOptions["search-only-api-key"];
1069 | const indexName = algoliaOptions["index-name"];
1070 | const indexFields = algoliaOptions["index-fields"];
1071 | const searchClient = window.algoliasearch(applicationId, searchOnlyApiKey);
1072 | const searchParams = algoliaOptions["params"];
1073 | const searchAnalytics = !!algoliaOptions["analytics-events"];
1074 |
1075 | return getAlgoliaResults({
1076 | searchClient,
1077 | queries: [
1078 | {
1079 | indexName: indexName,
1080 | query,
1081 | params: {
1082 | hitsPerPage: limit,
1083 | clickAnalytics: searchAnalytics,
1084 | ...searchParams,
1085 | },
1086 | },
1087 | ],
1088 | transformResponse: (response) => {
1089 | if (!indexFields) {
1090 | return response.hits.map((hit) => {
1091 | return hit.map((item) => {
1092 | return {
1093 | ...item,
1094 | text: highlightMatch(query, item.text),
1095 | };
1096 | });
1097 | });
1098 | } else {
1099 | const remappedHits = response.hits.map((hit) => {
1100 | return hit.map((item) => {
1101 | const newItem = { ...item };
1102 | ["href", "section", "title", "text"].forEach((keyName) => {
1103 | const mappedName = indexFields[keyName];
1104 | if (
1105 | mappedName &&
1106 | item[mappedName] !== undefined &&
1107 | mappedName !== keyName
1108 | ) {
1109 | newItem[keyName] = item[mappedName];
1110 | delete newItem[mappedName];
1111 | }
1112 | });
1113 | newItem.text = highlightMatch(query, newItem.text);
1114 | return newItem;
1115 | });
1116 | });
1117 | return remappedHits;
1118 | }
1119 | },
1120 | });
1121 | }
1122 |
1123 | function fuseSearch(query, fuse, fuseOptions) {
1124 | return fuse.search(query, fuseOptions).map((result) => {
1125 | const addParam = (url, name, value) => {
1126 | const anchorParts = url.split("#");
1127 | const baseUrl = anchorParts[0];
1128 | const sep = baseUrl.search("\\?") > 0 ? "&" : "?";
1129 | anchorParts[0] = baseUrl + sep + name + "=" + value;
1130 | return anchorParts.join("#");
1131 | };
1132 |
1133 | return {
1134 | title: result.item.title,
1135 | section: result.item.section,
1136 | href: addParam(result.item.href, kQueryArg, query),
1137 | text: highlightMatch(query, result.item.text),
1138 | };
1139 | });
1140 | }
1141 |
--------------------------------------------------------------------------------
/img/profile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jtr13/website-template/c3eb589322c282087bd8d3b466a997bd1abd207b/img/profile.png
--------------------------------------------------------------------------------
/index.qmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "About Me"
3 | about:
4 | id: me
5 | template: broadside
6 | image: img/profile.png
7 | ---
8 |
9 | :::{#me}
10 |
11 | ## Goals
12 |
13 | ## Education
14 |
15 | ## Experience
16 |
17 | :::
18 |
19 | Thanks for checking out my web site!
20 |
--------------------------------------------------------------------------------
/projects.qmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Projects"
3 | ---
4 |
5 | ## Project 1
6 |
7 | ## Project 2
8 |
9 | ## Project 3
10 |
--------------------------------------------------------------------------------
/website-template.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
--------------------------------------------------------------------------------