bsc

Comprehensive codebase and coursework for the 4-year B.Sc. Computer Science Honours degree (WBSU)

git clone https://github.com/notamitgamer/bsc.git
· rebuilt hourlyOpen on GitHub
root / docs / .vitepress / theme / components / DocFooterExtra.vue

DocFooterExtra.vue (9415B)


      1 <template>
      2   <footer class="doc-footer-extra" :class="{ 'is-home': isHome }">
      3     <!-- Decorative divider: rising entrance animation on scroll -->
      4     <div
      5       ref="dividerRef"
      6       class="footer-divider"
      7       :class="{ 'is-visible': isDividerVisible }"
      8       aria-hidden="true"
      9     >
     10       <img
     11         src="/skyline3.svg"
     12         alt=""
     13         class="footer-divider-img"
     14         width="1000"
     15         height="460"
     16         loading="lazy"
     17         decoding="async"
     18       />
     19     </div>
     20 
     21     <!-- Top Row -->
     22     <div class="footer-top-row">
     23       <a
     24         href="https://github.com/notamitgamer/bsc"
     25         target="_blank"
     26         rel="noopener noreferrer"
     27         class="gh-mark"
     28         aria-label="View BSc Repository on GitHub"
     29       >
     30         <svg viewBox="0 0 16 16" width="20" height="20" fill="currentColor">
     31           <path
     32             d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27 c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"
     33           />
     34         </svg>
     35       </a>
     36 
     37       <button class="back-to-top" type="button" @click="scrollTop">
     38         Back to top
     39         <svg
     40           viewBox="0 0 16 16"
     41           width="13"
     42           height="13"
     43           fill="none"
     44           stroke="currentColor"
     45           stroke-width="2"
     46         >
     47           <path
     48             d="M8 13V3M3 8l5-5 5 5"
     49             stroke-linecap="round"
     50             stroke-linejoin="round"
     51           />
     52         </svg>
     53       </button>
     54     </div>
     55 
     56     <!-- Plain Corporate Columns -->
     57     <div class="footer-columns">
     58       <div class="col">
     59         <h3 class="col-title">Help Improve</h3>
     60         <p class="col-text">
     61           Spotted an error, outdated syllabus item, or missing code? All coursework documentation is open source.
     62         </p>
     63         <a
     64           href="https://github.com/notamitgamer/bsc/issues/new/choose"
     65           target="_blank"
     66           rel="noopener noreferrer"
     67           class="col-link"
     68         >
     69           Suggest an edit &rarr;
     70         </a>
     71       </div>
     72 
     73       <div class="col">
     74         <h3 class="col-title">Automation & Scripts</h3>
     75         <p class="col-text">
     76           Review, run, or patch the Markdown scrapers, syllabus crawlers, and generator pipelines.
     77         </p>
     78         <a
     79           href="https://github.com/notamitgamer/bsc/tree/main/utils/bsc_md"
     80           target="_blank"
     81           rel="noopener noreferrer"
     82           class="col-link"
     83         >
     84           View scripts repository &rarr;
     85         </a>
     86       </div>
     87 
     88       <div class="col">
     89         <h3 class="col-title">Community & Support</h3>
     90         <ul class="help-links">
     91           <li>
     92             <a
     93               href="https://github.com/notamitgamer/bsc/discussions"
     94               target="_blank"
     95               rel="noopener noreferrer"
     96             >
     97               Ask a question
     98             </a>
     99           </li>
    100           <li>
    101             <a
    102               href="https://github.com/notamitgamer/bsc/issues"
    103               target="_blank"
    104               rel="noopener noreferrer"
    105             >
    106               Report an issue
    107             </a>
    108           </li>
    109           <li>
    110             <a href="/changelog">Changelog</a>
    111           </li>
    112         </ul>
    113       </div>
    114     </div>
    115 
    116     <!-- Corporate Legal Bottom Bar -->
    117     <div class="footer-bottom-bar">
    118       <div class="copyright-line">
    119         <span>&copy; 2025–2026 </span>
    120         <a
    121           href="https://github.com/notamitgamer"
    122           target="_blank"
    123           rel="noopener noreferrer"
    124           class="author-link"
    125         >
    126           notamitgamer
    127         </a>
    128         <span class="license-sep">•</span>
    129         <span>All content is licensed under the </span>
    130         <a
    131           href="https://github.com/notamitgamer/bsc/blob/main/LICENSE"
    132           target="_blank"
    133           rel="noopener noreferrer"
    134           class="license-link"
    135         >
    136           MIT License
    137         </a>
    138       </div>
    139 
    140       <div class="bottom-links">
    141         <a href="/terms">Terms</a>
    142         <a
    143           href="https://github.com/notamitgamer/bsc/blob/main/LICENSE"
    144           target="_blank"
    145           rel="noopener noreferrer"
    146         >
    147           License
    148         </a>
    149         <a
    150           href="https://github.com/notamitgamer/bsc"
    151           target="_blank"
    152           rel="noopener noreferrer"
    153         >
    154           GitHub
    155         </a>
    156       </div>
    157     </div>
    158   </footer>
    159 </template>
    160 
    161 <script setup>
    162 import { ref, computed, onMounted, onUnmounted } from 'vue'
    163 import { useData } from 'vitepress'
    164 
    165 const { page } = useData()
    166 const isHome = computed(() => page.value?.frontmatter?.layout === 'home')
    167 
    168 const dividerRef = ref(null)
    169 const isDividerVisible = ref(false)
    170 let observer = null
    171 
    172 function scrollTop() {
    173   window.scrollTo({ top: 0, behavior: 'smooth' })
    174 }
    175 
    176 onMounted(() => {
    177   if (typeof window === 'undefined' || !('IntersectionObserver' in window)) {
    178     isDividerVisible.value = true
    179     return
    180   }
    181 
    182   observer = new IntersectionObserver(
    183     (entries) => {
    184       const [entry] = entries
    185       if (entry.isIntersecting) {
    186         isDividerVisible.value = true
    187         if (dividerRef.value) observer.unobserve(dividerRef.value)
    188       }
    189     },
    190     { threshold: 0.15 }
    191   )
    192 
    193   if (dividerRef.value) {
    194     observer.observe(dividerRef.value)
    195   }
    196 })
    197 
    198 onUnmounted(() => {
    199   if (observer) observer.disconnect()
    200 })
    201 </script>
    202 
    203 <style scoped>
    204 .doc-footer-extra {
    205   margin-top: 3.5rem;
    206   border-top: 1px solid var(--vp-c-divider);
    207   padding-top: 0;
    208   font-family: var(--vp-font-family-base);
    209   clear: both;
    210   width: 100%;
    211   max-width: 688px;
    212   margin-left: auto;
    213   margin-right: auto;
    214   padding-left: 24px;
    215   padding-right: 24px;
    216   box-sizing: border-box;
    217 }
    218 
    219 .doc-footer-extra.is-home {
    220   max-width: 1152px;
    221   padding-left: 64px;
    222   padding-right: 64px;
    223 }
    224 
    225 @media (max-width: 960px) {
    226   .doc-footer-extra.is-home {
    227     padding-left: 32px;
    228     padding-right: 32px;
    229   }
    230 }
    231 
    232 @media (max-width: 640px) {
    233   .doc-footer-extra,
    234   .doc-footer-extra.is-home {
    235     padding-left: 16px;
    236     padding-right: 16px;
    237   }
    238 }
    239 
    240 .doc-footer-extra button,
    241 .doc-footer-extra a {
    242   font-family: inherit;
    243 }
    244 
    245 /* Decorative Divider with Smooth Scroll Elevation */
    246 .footer-divider {
    247   width: 100%;
    248   position: relative;
    249   display: flex;
    250   justify-content: center;
    251   align-items: flex-end;
    252   line-height: 0;
    253   margin-bottom: 0.5rem;
    254   opacity: 0;
    255   transform: translateY(28px);
    256   transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1),
    257               transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
    258   will-change: transform, opacity;
    259   overflow: hidden;
    260 }
    261 
    262 .footer-divider.is-visible {
    263   opacity: 0.95;
    264   transform: translateY(0);
    265 }
    266 
    267 @media (prefers-reduced-motion: reduce) {
    268   .footer-divider {
    269     transition: none !important;
    270     transform: none !important;
    271     opacity: 0.95 !important;
    272   }
    273 }
    274 
    275 .footer-divider-img {
    276   width: 100%;
    277   height: clamp(140px, 18vw, 240px);
    278   object-fit: contain;
    279   object-position: bottom center;
    280   display: block;
    281 }
    282 
    283 /* Top Action Row */
    284 .footer-top-row {
    285   display: flex;
    286   align-items: center;
    287   justify-content: space-between;
    288   padding: 0.85rem 0;
    289   border-bottom: 1px solid var(--vp-c-divider);
    290   color: var(--vp-c-text-2);
    291 }
    292 
    293 .gh-mark {
    294   color: var(--vp-c-text-2);
    295   display: flex;
    296 }
    297 
    298 .back-to-top {
    299   display: flex;
    300   align-items: center;
    301   gap: 6px;
    302   background: none;
    303   border: none;
    304   color: var(--vp-c-text-2);
    305   font-size: 13px;
    306   cursor: pointer;
    307   font-weight: 500;
    308 }
    309 
    310 /* Plain Corporate Columns */
    311 .footer-columns {
    312   display: grid;
    313   grid-template-columns: repeat(3, 1fr);
    314   gap: 2rem;
    315   padding: 1.75rem 0;
    316   border-bottom: 1px solid var(--vp-c-divider);
    317 }
    318 
    319 @media (max-width: 768px) {
    320   .footer-columns {
    321     grid-template-columns: 1fr;
    322     gap: 1.5rem;
    323   }
    324 }
    325 
    326 .col {
    327   display: flex;
    328   flex-direction: column;
    329 }
    330 
    331 .col-title {
    332   font-size: 13px;
    333   font-weight: 600;
    334   letter-spacing: 0.02em;
    335   color: var(--vp-c-text-1);
    336   margin: 0 0 0.5rem;
    337 }
    338 
    339 .col-text {
    340   font-size: 13px;
    341   color: var(--vp-c-text-2);
    342   line-height: 1.55;
    343   margin: 0 0 0.75rem;
    344 }
    345 
    346 .col-link {
    347   font-size: 13px;
    348   font-weight: 500;
    349   color: var(--vp-c-brand-1);
    350   text-decoration: none;
    351 }
    352 
    353 .help-links {
    354   list-style: none;
    355   margin: 0;
    356   padding: 0;
    357   display: flex;
    358   flex-direction: column;
    359   gap: 0.45rem;
    360 }
    361 
    362 .help-links a {
    363   font-size: 13px;
    364   color: var(--vp-c-text-2);
    365   text-decoration: none;
    366 }
    367 
    368 /* Plain Bottom Legal Bar */
    369 .footer-bottom-bar {
    370   display: flex;
    371   justify-content: space-between;
    372   align-items: center;
    373   flex-wrap: wrap;
    374   gap: 0.75rem;
    375   padding: 1.25rem 0;
    376   font-size: 12.5px;
    377   color: var(--vp-c-text-3, var(--vp-c-text-2));
    378 }
    379 
    380 .copyright-line {
    381   display: inline-flex;
    382   align-items: center;
    383   flex-wrap: wrap;
    384   gap: 4px;
    385 }
    386 
    387 .author-link {
    388   font-weight: 500;
    389   color: var(--vp-c-text-1);
    390   text-decoration: none;
    391 }
    392 
    393 .license-sep {
    394   margin: 0 4px;
    395   opacity: 0.6;
    396 }
    397 
    398 .license-link {
    399   color: var(--vp-c-text-2);
    400   text-decoration: underline;
    401   text-underline-offset: 2px;
    402 }
    403 
    404 .bottom-links {
    405   display: flex;
    406   gap: 1.25rem;
    407 }
    408 
    409 .bottom-links a {
    410   color: inherit;
    411   text-decoration: none;
    412 }
    413 </style>