diff options
Diffstat (limited to 'packages/client/src/components')
-rw-r--r-- | packages/client/src/components/BaseBackButton.vue | 2 | ||||
-rw-r--r-- | packages/client/src/components/BaseBreadcrumb.vue | 25 | ||||
-rw-r--r-- | packages/client/src/components/BaseButton.vue | 29 | ||||
-rw-r--r-- | packages/client/src/components/CommitPatch.vue | 6 | ||||
-rw-r--r-- | packages/client/src/components/HomeHeader.vue | 24 | ||||
-rw-r--r-- | packages/client/src/components/HomeProjectsHeader.vue | 27 | ||||
-rw-r--r-- | packages/client/src/components/RepositoryCloneDropdown.vue | 215 | ||||
-rw-r--r-- | packages/client/src/components/RepositoryHeader.vue | 21 | ||||
-rw-r--r-- | packages/client/src/components/RepositoryNavbar.vue | 97 | ||||
-rw-r--r-- | packages/client/src/components/RepositoryTreeBlob.vue | 9 | ||||
-rw-r--r-- | packages/client/src/components/RepositoryTreeTree.vue | 62 |
11 files changed, 386 insertions, 131 deletions
diff --git a/packages/client/src/components/BaseBackButton.vue b/packages/client/src/components/BaseBackButton.vue index e1191f9..2de0c77 100644 --- a/packages/client/src/components/BaseBackButton.vue +++ b/packages/client/src/components/BaseBackButton.vue @@ -1,5 +1,5 @@ <template> - <div class="d-inline"> + <div> <router-link :to="to"> <svg xmlns="http://www.w3.org/2000/svg" id="back" diff --git a/packages/client/src/components/BaseBreadcrumb.vue b/packages/client/src/components/BaseBreadcrumb.vue index 91c0109..65dffd4 100644 --- a/packages/client/src/components/BaseBreadcrumb.vue +++ b/packages/client/src/components/BaseBreadcrumb.vue @@ -33,7 +33,28 @@ export default { <style lang="scss" scoped> @use "../scss/colors"; -@import "../scss/bootstrap"; -@import "~bootstrap/scss/breadcrumb"; +.breadcrumb { + display: flex; + flex-wrap: wrap; + padding: 0 0; + margin-bottom: 1rem; + list-style: none; + a { + color: colors.$text; + text-decoration: none; + } + .active { + color: #6c757d; + } + .breadcrumb-item { + padding-left: 0.5rem; + } + .breadcrumb-item + .active::before { + float: left; + padding-right: 0.5rem; + color: #6c757d; + content: "/"; + } +} </style> diff --git a/packages/client/src/components/BaseButton.vue b/packages/client/src/components/BaseButton.vue new file mode 100644 index 0000000..2a528b0 --- /dev/null +++ b/packages/client/src/components/BaseButton.vue @@ -0,0 +1,29 @@ +<template> + <button :type="type ? type : ''"> + {{ value }} + </button> +</template> + +<script> +export default { + name: "BaseButton", + props: { + type: { + type: String, + required: true + }, + value: { + type: String, + required: true + } + } +}; +</script> + +<style lang="scss" scoped> +@use "../scss/mixins"; + +button { + @include mixins.button; +} +</style> diff --git a/packages/client/src/components/CommitPatch.vue b/packages/client/src/components/CommitPatch.vue index cf15eda..fdeb28d 100644 --- a/packages/client/src/components/CommitPatch.vue +++ b/packages/client/src/components/CommitPatch.vue @@ -15,17 +15,17 @@ export default { let commit_patch; if(props.patch.too_large === false) { - let all_hunks = props.patch.hunks.map((hunk) => hunk.hunk); + let all_hunks = props.patch.hunks.map((hunk) => hunk.hunk.split("\n").slice(1).join("\n")); const language = hljs_languages.find((lang) => lang.extensions.some((extension) => props.patch.to.endsWith(extension))); let highlighted = language ? hljs.highlight(all_hunks.join("\n"), { language: language.name }) : 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) => { + all_hunks.forEach((hunk, index) => { const hunk_row_cnt = hunk.split("\n").length; + all_hunks[index] = props.patch.hunks[index].hunk.split("\n")[0] + all_hunks[index]; highlighted_hunks.push(highlighted.slice(hunk_start, hunk_start + hunk_row_cnt)); hunk_start = hunk_start + hunk_row_cnt; }); diff --git a/packages/client/src/components/HomeHeader.vue b/packages/client/src/components/HomeHeader.vue index 24afd5b..b108b9b 100644 --- a/packages/client/src/components/HomeHeader.vue +++ b/packages/client/src/components/HomeHeader.vue @@ -1,11 +1,9 @@ <template> - <div id="header" class="d-flex mt-3 mb-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 id="header"> + <span id="title" class="fs-1">{{ title }}</span> + <p id="about" class="fs-4"> + {{ about }} + </p> </div> </template> @@ -33,11 +31,17 @@ export default { }; </script> -<style lang="scss"> -@import "../scss/fonts"; +<style lang="scss" scoped> +@use "../scss/mixins"; +@use "../scss/fonts"; + +#header { + @include mixins.header; + flex-direction: column; +} #title { - font-family: $font-title; + font-family: fonts.$title; font-weight: 300; line-height: 0.6; } diff --git a/packages/client/src/components/HomeProjectsHeader.vue b/packages/client/src/components/HomeProjectsHeader.vue index 5966e99..f9aeb20 100644 --- a/packages/client/src/components/HomeProjectsHeader.vue +++ b/packages/client/src/components/HomeProjectsHeader.vue @@ -1,34 +1,39 @@ <template> - <div class="d-flex align-items-center flex-wrap"> - <div id="projects-header" class="ms-4"> + <div id="projects"> + <div id="projects-header"> <span class="fs-1"> Projects </span> </div> - <div id="projects-search" class="d-flex"> + <div id="projects-search"> <form> <input type="search" name="q"> - <input - type="submit" value="Search" - class="btn btn-primary"> + <BaseButton type="submit" value="Search" /> </form> </div> </div> </template> <script> +import BaseButton from "@/components/BaseButton"; + export default { - name: "HomeProjectsHeader" + name: "HomeProjectsHeader", + components: { + BaseButton + } }; </script> <style lang="scss" scoped> -@use "../scss/colors"; -@import "../scss/bootstrap"; - -@import "~bootstrap/scss/buttons"; +#projects { + display: flex; + align-items: center; + flex-wrap: wrap; +} #projects-search { + display: flex; align-items: center; margin-left: auto; margin-right: 15px; diff --git a/packages/client/src/components/RepositoryCloneDropdown.vue b/packages/client/src/components/RepositoryCloneDropdown.vue index ed565ef..a46d569 100644 --- a/packages/client/src/components/RepositoryCloneDropdown.vue +++ b/packages/client/src/components/RepositoryCloneDropdown.vue @@ -1,36 +1,41 @@ <template> - <div id="clone" class="d-flex align-items-center"> - <div class="dropdown"> - <button - class="btn btn-primary btn-sm dropdown-toggle" type="button" - id="dropdownMenuButton1" data-bs-toggle="dropdown" - data-bs-auto-close="outside" aria-expanded="false"> - Clone - </button> - <ul class="dropdown-menu dropdown-menu-end dropdown-menu-dark" aria-labelledby="dropdownMenuButton1"> - <li class="pt-2"> - <span class="ms-2 fs-5 fw-bold">Clone with HTTP</span> - <label id="clone-url-copy"> - <input - type="text" :value="getURL()" - class="form-control form-control-sm ms-2 me-2" readonly> - <svg - xmlns="http://www.w3.org/2000/svg" height="18px" - viewBox="0 0 24 24" width="18px" - fill="#FFFFFF" @click="copyToClipboard"> - <path d="M0 0h24v24H0z" fill="none" /> - <path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" /> - </svg> - </label> - </li> - </ul> + <div id="clone"> + <button + id="dropdown-button" aria-describedby="dropdown-menu" + type="button"> + Clone + </button> + <div id="dropdown-menu" role="dropdown-menu"> + <div> + <p id="dropdown-title" class="fs-5"> + Clone with HTTP + </p> + <div + id="copied-tooltip" role="copied-tooltip" + class="fs-5"> + <div id="tooltip-arrow" /> + Copied! + </div> + <label id="clone-url-copy"> + <input + type="text" :value="getURL()" + readonly> + <svg + xmlns="http://www.w3.org/2000/svg" height="18px" + viewBox="0 0 24 24" width="18px" + fill="#FFFFFF" @click="copyToClipboard" + id="copy"> + <path d="M0 0h24v24H0z" fill="none" /> + <path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" /> + </svg> + </label> + </div> </div> </div> </template> <script> -import { Tooltip } from "bootstrap/dist/js/bootstrap.esm"; -// Import Fan from "../util/sleep.worker"; +import { createPopper } from "@popperjs/core"; export default { name: "RepositoryCloneDropdown", @@ -48,41 +53,74 @@ export default { url_box.setSelectionRange(0, 99999); document.execCommand("copy"); - event.stopPropagation(); + const copied_tooltip = document.querySelector("#copied-tooltip"); + copied_tooltip.classList.add("show"); - const exampleEl = document.getElementById("clone-url-copy").getElementsByTagName("svg")[0]; - const tooltip = new Tooltip(exampleEl, { title: "Copied the URL", trigger: "manual" }); - console.log(tooltip); - tooltip.show(); - - await new Promise(resolve => setTimeout(resolve, 1700)); - tooltip.hide(); + await new Promise(resolve => setTimeout(resolve, 2000)); + copied_tooltip.classList.remove("show"); }, getURL() { return `${window.location.protocol}//${window.location.host}/${this.repository}`; } + }, + mounted() { + const dropdown_button = document.querySelector("#dropdown-button"); + const dropdown_menu = document.querySelector("#dropdown-menu"); + + const copied_tooltip = document.querySelector("#copied-tooltip"); + const copy = document.querySelector("#copy"); + const tooltip_arrow = document.querySelector("#tooltip-arrow"); + createPopper(dropdown_button, dropdown_menu, { + placement: "bottom-end", + modifiers: [ + { + name: "offset", + options: { offset: [ 0, 2 ] } + } + ] + }); + createPopper(copy, copied_tooltip, { + placement: "top", + modifiers: [ + { + name: "offset", + options: { offset: [ 0, 10 ] } + }, + { + name: "arrow", + options: { element: tooltip_arrow } + } + ] + }); + + const clickOutsideDropdown = (event) => { + if(!dropdown_menu.contains(event.target) && event.target !== dropdown_button) { + dropdown_menu.classList.remove("show"); + document.removeEventListener("click", clickOutsideDropdown); + } + }; + + dropdown_button.addEventListener("click", () => { + if(dropdown_menu.classList.contains("show")) { + dropdown_menu.classList.remove("show"); + document.removeEventListener("click", clickOutsideDropdown); + } else { + dropdown_menu.classList.add("show"); + document.addEventListener("click", clickOutsideDropdown); + } + }); } }; </script> <style lang="scss" scoped> @use "../scss/colors"; -@import "../scss/bootstrap"; - -$dropdown-dark-bg: lighten(#000000, 10%); - -@import "~bootstrap/scss/buttons"; -@import "~bootstrap/scss/dropdown"; -@import "~bootstrap/scss/forms"; -@import "~bootstrap/scss/tooltip"; - -.form-control { - width: auto; -} +@use "../scss/mixins"; +@use "../scss/fonts"; #clone { - margin-left: auto; - margin-right: 40px; + display: flex; + align-items: center; } #clone-url-copy { @@ -95,6 +133,14 @@ $dropdown-dark-bg: lighten(#000000, 10%); display: inline-block; padding-right: 30px; min-height: 0; + background: lighten(#000000, 15%); + border: 1px solid lighten(#000000, 28%); + color: colors.$text; + border-radius: 2px; + height: 25px; + margin-left: 0.5rem; + margin-right: 0.5rem; + font-family: fonts.$primary; } svg { content: ""; @@ -109,4 +155,75 @@ $dropdown-dark-bg: lighten(#000000, 10%); } } } + +#dropdown-button { + @include mixins.button; + padding: 3px 5px 3px 6px; + font-size: 15px; + font-family: fonts.$primary; + &::after { + display: inline-block; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; + } +} + +#dropdown-menu { + visibility: hidden; + pointer-events: none; + background-color: lighten(#000000, 12%); + opacity: 0; + transition:visibility 0.08s linear,opacity 0.08s linear; + border-radius: 5px; + z-index: 1000; + position: absolute; +} + +#copied-tooltip { + visibility: hidden; + pointer-events: none; + position: absolute; + background-color: #000000; + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + padding-bottom: 2px; + border-radius: 3px; + z-index: 99999; + opacity: 0; + transition:visibility 0.4s linear,opacity 0.4s linear; +} + +.show { + visibility: visible !important; + pointer-events: all !important; + opacity: 1 !important; +} + +#tooltip-arrow { + bottom: -4px; +} + +#tooltip-arrow, +#tooltip-arrow::before { + position: absolute; + width: 8px; + height: 8px; + z-index: -1; +} + +#tooltip-arrow::before { + content: ''; + transform: rotate(45deg); + background: #000000; +} + +#dropdown-title { + margin-left: 0.5rem; + font-weight: 700; +} </style> diff --git a/packages/client/src/components/RepositoryHeader.vue b/packages/client/src/components/RepositoryHeader.vue index 50a1db9..8059809 100644 --- a/packages/client/src/components/RepositoryHeader.vue +++ b/packages/client/src/components/RepositoryHeader.vue @@ -1,7 +1,7 @@ <template> - <div id="header" class="mx-0 d-flex mt-3 ms-2"> + <div id="header"> <BaseBackButton to="/" /> - <div class="d-inline ms-3"> + <div id="header-content"> <span id="title" class="fs-1">{{ name }}</span> <p id="about" class="fs-4"> {{ description }} @@ -33,12 +33,23 @@ export default { <style lang="scss" scoped> @use "../scss/colors"; +@use "../scss/mixins"; +@use "../scss/fonts"; -@import "../scss/bootstrap"; -@import "../scss/fonts"; +#header { + @include mixins.header; + flex-direction: row; + div { + display: inline; + } +} + +#header-content { + margin-left: 1rem; +} #title { - font-family: $font-title; + font-family: fonts.$title; font-weight: 300; line-height: 0.6; } diff --git a/packages/client/src/components/RepositoryNavbar.vue b/packages/client/src/components/RepositoryNavbar.vue index f709976..08fa179 100644 --- a/packages/client/src/components/RepositoryNavbar.vue +++ b/packages/client/src/components/RepositoryNavbar.vue @@ -1,27 +1,24 @@ <template> <div id="navbar"> - <div id="repo-navbar" class="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 align-items-center flex-fill"> - <li - v-for="(item, index) in nav_items" :key="index" - class="nav-item"> - <router-link - class="nav-link fs-4" :class="{ active: activePage === item }" - :aria-current="(activePage === item) ? 'page' : ''" :to="'/' + repository + '/' + item"> - {{ item }} - </router-link> - </li> - <li class="nav-item ms-auto me-4"> - <RepositoryCloneDropdown :repository="repository" class="d-block" /> - </li> - </ul> - </div> + <nav class="navbar"> + <div class="navbar-container"> + <div class="nav"> + <ul> + <li + v-for="(item, index) in nav_items" :key="index"> + <router-link + class="nav-link fs-4" :class="{ active: activePage === item }" + :aria-current="(activePage === item) ? 'page' : ''" :to="'/' + repository + '/' + item"> + {{ item }} + </router-link> + </li> + <li id="clone-dropdown"> + <RepositoryCloneDropdown :repository="repository" class="d-block" /> + </li> + </ul> </div> - </nav> - </div> + </div> + </nav> </div> </template> @@ -54,7 +51,6 @@ export default { }, watch: { hasReadme() { - console.log("HEEEJ"); this.nav_items = [ "about" ].concat(this.nav_items); } } @@ -63,12 +59,59 @@ export default { <style lang="scss" scoped> @use "../scss/colors"; -@import "../scss/bootstrap"; - -@import "~bootstrap/scss/nav"; -@import "~bootstrap/scss/navbar"; #navbar { - line-height: 0; + margin-left: 3rem; +} + +.navbar { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding-top: 0.5rem; + padding-bottom: 0.5rem; + flex-wrap: nowrap; + justify-content: flex-start; + .navbar-container { + display: flex; + flex-wrap: inherit; + align-items: center; + justify-content: space-between; + width: 100%; + .nav { + display: flex; + flex-basis: auto; + flex-grow: 1; + align-items: center; + ul { + display: flex; + flex-direction: row; + padding-left: 0; + margin-bottom: 0; + list-style: none; + align-items: center; + flex: 1 1 auto; + .nav-link { + color: darken(#ffffff, 50%); + padding-right: 0.5rem; + padding-left: 0.5rem; + transition: color .15s ease-in-out; + &:hover { + color: darken(#ffffff, 20%); + } + } + #clone-dropdown { + margin-left: auto; + margin-right: 40px; + } + .active { + color: darken(#ffffff, 20%); + } + } + } + } } + </style> diff --git a/packages/client/src/components/RepositoryTreeBlob.vue b/packages/client/src/components/RepositoryTreeBlob.vue index 2a5a6dc..ac4ee32 100644 --- a/packages/client/src/components/RepositoryTreeBlob.vue +++ b/packages/client/src/components/RepositoryTreeBlob.vue @@ -10,7 +10,8 @@ </tbody> </table> <span - v-else v-html="content_lines" /> + v-else v-html="content_lines" + id="markdown-blob" /> </template> <script> @@ -81,9 +82,9 @@ export default { <style lang="scss"> @use "../scss/colors"; +@use "../scss/fonts"; @import "~highlight.js/scss/srcery.scss"; -@import "../scss/fonts"; ul { padding-left: 30px; @@ -99,10 +100,10 @@ code { white-space: pre-wrap; word-wrap: anywhere; background-color: lighten(#000000, 8%); - font-family: $font-primary; + font-family: fonts.$primary; } -span { +#markdown-blob { word-wrap: anywhere; a { color: colors.$primary-light; diff --git a/packages/client/src/components/RepositoryTreeTree.vue b/packages/client/src/components/RepositoryTreeTree.vue index 376cafc..21f9570 100644 --- a/packages/client/src/components/RepositoryTreeTree.vue +++ b/packages/client/src/components/RepositoryTreeTree.vue @@ -10,7 +10,7 @@ <tbody> <tr v-if="path !== ''" @click="$router.push(`/${repository}/tree/${path.split('/').slice(0, -1).join('/') }`)"> <td - class="d-flex align-items-center"> + class="flex-center"> <div class="tree-entry-padding" /> .. </td> @@ -20,7 +20,7 @@ <tr v-for="(entry, entry_name, index) in tree" :key="index" @click="$router.push(`/${repository}/tree${path ? '/' + path : ''}/${entry_name}`)"> - <td class="d-flex align-items-center"> + <td class="flex-center"> <svg xmlns="http://www.w3.org/2000/svg" height="18px" viewBox="0 0 24 24" width="18px" @@ -82,33 +82,57 @@ export default { <style lang="scss" scoped> @use "../scss/colors"; -@import "../scss/bootstrap"; -#tree { +table { border-spacing: 0; + width: 100%; + margin-bottom: 1rem; + tbody { + vertical-align: inherit; + tr { + &:hover { + background-color: lighten(colors.$background, 5%); + } + td { + padding-bottom: 1em; + &:nth-child(2) a, &:nth-child(3) { + font-weight: 300; + } + padding-top: 5px; + padding-bottom: 5px; + padding-right: 2vw; + } + } + } + thead { + vertical-align: bottom; + } th { - padding-bottom: 5px; - color: colors.$secondary; text-align: start; - padding-right: 20px; - } - tbody tr:hover { - background-color: lighten(colors.$background, 10%); + padding-bottom: 1em; + color: colors.$secondary; } - td { - padding-top: 5px; - padding-bottom: 5px; - padding-right: 2vw; - &:nth-child(2) a, &:nth-child(3) { - font-weight: 300; - } + > :not(caption) > * > * { + padding: 0.2rem 1rem; + border-bottom-width: 1px; } .tree-entry-padding, svg { width: 18px; padding-right: 5px; } - a { - padding-right: 18px; +} + +#log { + padding-left: 0; +} + +@media (max-width: 576px) { + table > :not(caption) > * > * { + padding: 0.1rem; } } +.flex-center { + display: flex; + align-items: center; +} </style> |