diff options
Diffstat (limited to 'src/frontend/components')
-rw-r--r-- | src/frontend/components/BaseBackButton.vue | 25 | ||||
-rw-r--r-- | src/frontend/components/CommitPatch.vue | 149 | ||||
-rw-r--r-- | src/frontend/components/HomeHeader.vue | 39 | ||||
-rw-r--r-- | src/frontend/components/RepositoryHeader.vue | 50 | ||||
-rw-r--r-- | src/frontend/components/RepositoryNavbar.vue | 32 |
5 files changed, 295 insertions, 0 deletions
diff --git a/src/frontend/components/BaseBackButton.vue b/src/frontend/components/BaseBackButton.vue new file mode 100644 index 0000000..64b1286 --- /dev/null +++ b/src/frontend/components/BaseBackButton.vue @@ -0,0 +1,25 @@ +<template> + <div class="d-inline"> + <router-link :to="to"> + <svg + xmlns="http://www.w3.org/2000/svg" id="back" + height="24px" width="24px" + viewBox="0 0 24 24" fill="#ffffff"> + <path d="M0 0h24v24H0z" fill="none" /> + <path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" /> + </svg> + </router-link> + </div> +</template> + +<script> +export default { + name: "BaseBackButton", + props: { + to: { + type: String, + required: true + } + } +} +</script>
\ No newline at end of file diff --git a/src/frontend/components/CommitPatch.vue b/src/frontend/components/CommitPatch.vue new file mode 100644 index 0000000..53edeb9 --- /dev/null +++ b/src/frontend/components/CommitPatch.vue @@ -0,0 +1,149 @@ +<script> +import { h } from "vue"; +import hljs from "highlight.js"; +import hljs_languages from "../util/hljs-languages"; + +export default { + name: "CommitPatch", + props: { + patch: { + type: Object, + required: true + } + }, + setup(props) + { + const commit_patch = [ + h("div", { "class": "commit-file-header" }, [ + h("span", { "class": "fw-bold"}, (props.patch["to"] === "/dev/null") ? props.patch["from"] : props.patch["to"]), + h("span", (props.patch["to"] === "/dev/null") ? "Deleted" : "" ), + h("div", { class: "commit-file-add-del" }, [ + h("span", `+${ props.patch["additions"] }`), + h("span", `-${ props.patch["deletions"] }`) + ]) + ]) + ]; + + if(props.patch["too_large"] === false) { + let all_hunks = props.patch["hunks"].map((hunk) => hunk["hunk"]); + + const language = hljs_languages.find((lang) => lang["extensions"].some((extension) => props.patch["to"].endsWith(extension))); + let highlighted = language ? hljs.highlight(language["name"], all_hunks.join("\n")) : hljs.highlightAuto(all_hunks.join("\n")); + console.log(highlighted); + highlighted = highlighted["value"].split("\n"); + + const highlighted_hunks = []; + let hunk_start = 0; + all_hunks.forEach((hunk) => + { + const hunk_row_cnt = hunk.split("\n").length; + highlighted_hunks.push(highlighted.slice(hunk_start, hunk_start + hunk_row_cnt)); + hunk_start = hunk_start + hunk_row_cnt; + }); + + all_hunks = all_hunks.map((hunk) => hunk.split("\n")); + + commit_patch.push(h("table", { cellspacing: "0px" }, [ + h("tbody", [ + props.patch["hunks"].map((hunk, hunk_index) => + { + let new_offset = 0; + let deleted_offset = 0; + const multiline_comments = []; + + return highlighted_hunks[hunk_index].map((line, line_index) => + { + if(/^@@ -[0-9,]+ \+[0-9,]+ @@/.test(all_hunks[hunk_index][line_index])) { + new_offset++; + deleted_offset++; + return h("tr", { class: "commit-file-pos-change" }, [ + h("td", "..."), + h("td", "..."), + h("td", "..."), + h("td", [ + h("code", all_hunks[hunk_index][line_index]) + ]) + ]); + } + else if(/^\\ No newline at end of file$/.test(all_hunks[hunk_index][line_index])) { + new_offset++; + deleted_offset++; + return h("tr", { class: "commit-file-no-newline" }, [ + h("td", ""), + h("td", ""), + h("td", ""), + h("td", [ + h("code", all_hunks[hunk_index][line_index]) + ]) + ]); + } + else { + let first_td; + let second_td; + let third_td; + + if(hunk['new'].includes(line_index)) { + first_td = h("td", ""); + second_td = h("td", { class: "line-highlight-new" }, Number(hunk["new_start"]) + line_index - new_offset); + third_td = h("td", { class: "line-new" }, "+") + deleted_offset++; + } + else if(hunk['deleted'].includes(line_index)) { + first_td = h("td", Number(hunk["old_start"]) + line_index - deleted_offset); + second_td = h("td", { class: "line-highlight-deleted" }); + third_td = h("td", { class: "line-deleted" }, "-") + new_offset++; + } + else { + first_td = h("td", { class: "line-unchanged" }, Number(hunk["old_start"]) + line_index - deleted_offset); + second_td = h("td", { class: "line-unchanged" }, Number(hunk["new_start"]) + line_index - new_offset); + third_td = h("td", ""); + } + + let comment_open = line.match(/<span class="hljs-comment">/g); + const comment_open_cnt = (comment_open !== null) ? comment_open.length : 0; + comment_open = (comment_open !== null) ? comment_open[0] : ""; + + let comment_close = line.match(/<\/span>/g); + const comment_close_cnt = (comment_close !== null) ? comment_close.length : 0; + comment_close = (comment_close !== null) ? comment_close[0] : ""; + + if(comment_open_cnt > comment_close_cnt) { + line = line + "</span>"; + console.log("Öppning " + line); + multiline_comments.push(comment_open); + } + else if(comment_open_cnt < comment_close_cnt && multiline_comments.length !== 0) { + line = multiline_comments[multiline_comments.length - 1] + line; + console.log("Stängning " + line + " " + multiline_comments[multiline_comments.length - 1]); + multiline_comments.pop(); + } + else if(multiline_comments.length !== 0) { + line = multiline_comments[multiline_comments.length - 1] + line + "</span>"; + console.log("Mitt i " + line); + } + + return h("tr", [ + first_td, + second_td, + third_td, + h("td", [ + h("code", { innerHTML: line }) + ]) + ]); + } + }); + }) + ]) + ])); + } + else { + commit_patch.push(h("div", { class: "ps-3 pt-3 patch-too-large" }, [ + h("span", "Patch is too large to display.") + ])); + } + + return () => h("div", { class: "commit-file" }, commit_patch); + } +} +</script>
\ No newline at end of file diff --git a/src/frontend/components/HomeHeader.vue b/src/frontend/components/HomeHeader.vue new file mode 100644 index 0000000..f0366a3 --- /dev/null +++ b/src/frontend/components/HomeHeader.vue @@ -0,0 +1,39 @@ +<template> + <div class="row mx-0"> + <div id="header" class="col d-flex mt-3 ms-2"> + <div class="d-inline ms-3"> + <span id="title" class="fs-1">{{ title }}</span> + <p id="about" class="mb-3 fs-4"> + {{ about }} + </p> + </div> + </div> + </div> +</template> + +<script> +import { watch, reactive, toRefs } from "vue"; + +export default { + name: "HomeHeader", + setup() + { + const state = reactive({ title: String, about: String }); + + watch(() => + { + fetch(`http://localhost:1337/api/v1/info`) + .then((res) => res.json()) + .then((data) => + { + state.title = data["data"]["title"], + state.about = data["data"]["about"] + }); + }); + + return { + ... toRefs(state) + }; + } +} +</script>
\ No newline at end of file diff --git a/src/frontend/components/RepositoryHeader.vue b/src/frontend/components/RepositoryHeader.vue new file mode 100644 index 0000000..b0db4f9 --- /dev/null +++ b/src/frontend/components/RepositoryHeader.vue @@ -0,0 +1,50 @@ +<template> + <div class="row mx-0"> + <div id="header" class="col d-flex mt-3 ms-2"> + <BaseBackButton to="/" /> + <div class="d-inline ms-3"> + <span id="title" class="fs-1">{{ title }}</span> + <p id="about" class="mb-3 fs-4"> + {{ about }} + </p> + </div> + </div> + </div> +</template> + +<script> +import BaseBackButton from "./BaseBackButton"; +import { watch, reactive, toRefs } from "vue"; + +export default { + name: "RepositoryHeader", + components: { + BaseBackButton + }, + props: { + repository: { + type: String, + required: true + } + }, + setup(props) + { + const state = reactive({ title: "", about: "" }); + + watch(() => + { + fetch(`http://localhost:1337/api/v1/repos/${props.repository}`) + .then((res) => res.json()) + .then((data) => + { + state.title = data["data"]["name"]; + state.about = data["data"]["description"]; + }); + }); + + return { + ... toRefs(state) + }; + } +} +</script>
\ No newline at end of file diff --git a/src/frontend/components/RepositoryNavbar.vue b/src/frontend/components/RepositoryNavbar.vue new file mode 100644 index 0000000..a1e1002 --- /dev/null +++ b/src/frontend/components/RepositoryNavbar.vue @@ -0,0 +1,32 @@ +<template> + <div id="navbar" class="row mx-0"> + <div id="repo-navbar" class="col ms-4 ps-4"> + <nav class="navbar navbar-expand navbar-dark"> + <div class="container-fluid px-0"> + <div class="collapse navbar-collapse"> + <ul class="navbar-nav"> + <li v-for="(item, index) in nav_items" v-bind:key="index" class="nav-item"> + <a class="nav-link fs-4" :class="{ active: activePage === item }" :aria-current="(activePage === item) ? 'page' : ''" :href="item">{{ item }}</a> + </li> + </ul> + </div> + </div> + </nav> + </div> + </div> +</template> + +<script> +export default { + name: "RepositoryNavbar", + props: { + activePage: String + }, + data() + { + return { + nav_items: ["log", "refs", "tree"] + }; + } +} +</script>
\ No newline at end of file |