Files
csgowtf/src/components/NavComponent.vue
vikingowl afed42de49
Some checks failed
CSGOWTF/csgowtf/pipeline/head There was a failure building this commit
updated Nav-Search + removed string-sanitizer + added csgo-sharecode
2022-03-27 21:11:18 +02:00

406 lines
9.3 KiB
Vue

<template>
<nav class="navbar navbar-expand-md navbar-dark fixed-top">
<div class="container">
<router-link class="navbar-brand" to="/" @click="closeNav('mainNav')">
<img alt="logo-nav" class="logo-nav" src="/images/logo.svg" />
</router-link>
<button
aria-controls="mainNav"
aria-expanded="false"
aria-label="Toggle navigation"
class="navbar-toggler"
data-bs-target="#mainNav"
data-bs-toggle="collapse"
type="button"
>
<span class="navbar-toggler-icon"></span>
</button>
<div
id="mainNav"
class="collapse navbar-collapse navbar-nav justify-content-between"
>
<ul class="list-unstyled">
<li class="nav-item">
<router-link
class="nav-link"
to="/matches"
@click="closeNav('mainNav')"
>
Matches
</router-link>
</li>
</ul>
<form
id="search-form"
class="d-flex"
@keydown.enter.prevent="parseSearch"
@submit.prevent="parseSearch"
>
<label for="search">
<i class="fa fa-search"></i>
</label>
<input
id="search"
v-model="data.searchInput"
aria-label="Search"
autocomplete="off"
class="form-control bg-transparent border-0"
placeholder="SteamID, Profile Link or ShareCode"
title="SteamID, Profile Link or ShareCode"
type="search"
/>
<button
id="search-button"
class="btn border-2 btn-outline-info"
type="button"
@click="parseSearch"
>
Search!
</button>
</form>
</div>
</div>
</nav>
</template>
<script setup lang="ts">
import { reactive } from "vue";
import {
closeNav,
closeNavEventListener,
GetMatchDetails,
GetUser,
GoToMatch,
GoToPlayer,
ParseMatch,
parseShareCode,
sleep,
stringSanitizer,
} from "@/utils";
import {
CUSTOM_URL_BASE,
ID64_PATTERN,
MATCH_SHARE_URL_BASE,
PROFILE_URL_BASE,
SHARECODE_REGEX,
VANITY_PATTERN,
} from "@/constants";
import { StatusCodes as STATUS } from "http-status-codes";
import { useSearchParamsStore } from "@/stores/searchParams";
import type { infoState } from "@/stores/infoState";
import { useInfoStateStore } from "@/stores/infoState";
import { usePlayerDetailsStore } from "@/stores/playerDetails";
const searchParamsStore = useSearchParamsStore();
const infoStateStore = useInfoStateStore();
const playerDetailsStore = usePlayerDetailsStore();
const data = reactive({
searchInput: "",
});
const parseSearch = async () => {
let input = data.searchInput;
searchParamsStore.$reset();
if (data.searchInput !== "") {
// remove various base-urls + cut excess parameters
input = input
.replace(MATCH_SHARE_URL_BASE, "")
.replace(CUSTOM_URL_BASE, "")
.replace(PROFILE_URL_BASE, "")
.split("/")[0]
.split("?")[0];
// process shareCode
const tmpShareCode = Array.from(input.matchAll(SHARECODE_REGEX));
const inputShareCode = tmpShareCode.length > 0 ? tmpShareCode[0][0] : "";
searchParamsStore.shareCode = SHARECODE_REGEX.test(inputShareCode)
? inputShareCode
: "";
// process id64
const tmpId64 = Array.from(input.matchAll(ID64_PATTERN));
const inputId64 = tmpId64.length > 0 ? tmpId64[0][0] : "";
searchParamsStore.id64 = ID64_PATTERN.test(inputId64) ? inputId64 : "";
// process vanityUrl
if (searchParamsStore.shareCode === "" && searchParamsStore.id64 === "") {
if (input.includes(CUSTOM_URL_BASE)) {
input = input.replace(CUSTOM_URL_BASE, "");
}
if (VANITY_PATTERN.test(input)) {
searchParamsStore.vanityUrl = stringSanitizer(input);
} else {
const info: infoState = {
statusCode: STATUS.NOT_ACCEPTABLE,
message:
'Only alphanumeric symbols, "_", and "-", between 3-32 characters',
type: "warning",
};
infoStateStore.addInfo(info);
}
}
// GetUser
if (searchParamsStore.id64 !== "" || searchParamsStore.vanityUrl !== "") {
const [resData, info] = await GetUser(
searchParamsStore.vanityUrl || searchParamsStore.id64
);
if (info.message !== "") infoStateStore.addInfo(info);
if (resData !== null) {
data.searchInput = "";
const activeElem = document.activeElement as HTMLInputElement;
activeElem.blur();
playerDetailsStore.playerDetails = resData;
if (searchParamsStore.vanityUrl) {
closeNav("mainNav");
GoToPlayer(searchParamsStore.vanityUrl);
} else if (searchParamsStore.id64) {
closeNav("mainNav");
GoToPlayer(searchParamsStore.id64);
}
}
}
// ParseMatch
if (searchParamsStore.shareCode !== "") {
data.searchInput = "";
const matchId = parseShareCode(searchParamsStore.shareCode);
let info = await ParseMatch(searchParamsStore.shareCode);
if (info.message !== "") infoStateStore.addInfo(info);
if (info.statusCode === STATUS.OK) GoToMatch(matchId);
if (info.statusCode === STATUS.ACCEPTED) {
let [res, info] = await GetMatchDetails(matchId);
for (let i = 0; i < 10; i++) {
if (res !== null && res.parsed) break;
[res, info] = await GetMatchDetails(matchId);
sleep(2000);
}
GoToMatch(matchId);
}
}
}
};
closeNavEventListener("mainNav");
</script>
<style lang="scss" scoped>
.navbar-dark .navbar-brand:hover,
.navbar-dark .navbar-brand:focus {
color: var(--bs-warning);
}
nav {
max-width: 100vw;
width: 100vw;
height: 70px;
background: rgba(16, 18, 26, 0.9);
box-shadow: 0 1px 10px 0 #111;
z-index: 2;
vertical-align: center !important;
.navbar-brand {
img {
width: 75px;
height: auto;
}
&:focus-visible {
outline: none;
box-shadow: 0 4px 2px -2px var(--bs-warning);
}
&:hover {
color: var(--bs-warning);
}
}
ul li {
font-size: 1.5rem;
font-weight: lighter;
margin: 22px 0 0 10px;
cursor: pointer;
transition: 100ms ease-in-out;
.nav-link {
text-decoration: none;
color: white !important;
.router-link-exact-active {
box-shadow: 0 4px 2px -2px var(--bs-warning);
}
&:focus-visible {
outline: none;
box-shadow: 0 4px 2px -2px var(--bs-warning);
}
&:hover {
color: #bdbdbd !important;
transition: 250ms ease-in-out;
cursor: pointer;
box-shadow: 0 4px 2px -2px var(--bs-warning);
}
}
}
form {
position: relative;
svg {
width: 24px;
height: 24px;
fill: currentColor;
}
label {
padding-top: 6px;
font-size: 1.4rem;
}
input[type="search"] {
min-width: 300px;
max-width: 300px;
&:focus {
box-shadow: 0 4px 2px -2px rgba(95, 120, 146, 0.59);
transition: 0.2s ease-in-out;
transform: scale(0.975);
}
&::placeholder {
color: #aaa;
font-size: 0.9rem;
}
}
.alert {
position: absolute;
right: 0;
top: 55px;
}
}
}
@media screen and (max-width: 410px) {
form {
margin-left: auto !important;
margin-right: auto !important;
input[type="search"] {
margin-left: 0 !important;
max-width: 60vw !important;
min-width: 60vw !important;
}
}
}
@media screen and (max-width: 455px) and (min-width: 410px) {
form {
margin-left: auto !important;
margin-right: auto !important;
input[type="search"] {
margin-left: 0 !important;
max-width: 65vw !important;
min-width: 65vw !important;
}
}
}
@media screen and (max-width: 610px) and (min-width: 456px) {
form {
margin-left: auto !important;
margin-right: auto !important;
input[type="search"] {
margin-left: 0 !important;
max-width: 68vw !important;
min-width: 68vw !important;
}
}
}
@media screen and (max-width: 768px) {
nav {
button {
outline: 1px solid var(--bs-primary);
margin-left: auto;
float: right;
&:focus {
box-shadow: none;
outline: 1px solid var(--bs-primary);
}
}
.navbar-collapse {
background: var(--bs-secondary);
border-radius: 5px;
border: 1px solid var(--bs-primary);
}
#mainNav {
ul {
display: flex;
flex-direction: column;
text-align: center;
width: 100%;
li {
line-height: 1;
padding: 0 0 20px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
}
form {
max-width: 87vw;
margin-left: -40px;
label {
display: none;
}
input[type="search"] {
margin-bottom: 15px;
margin-left: 37px;
max-width: 400px;
min-width: 400px;
font-size: 1rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&::placeholder {
background: var(--bs-body-bg);
}
}
button {
margin-left: 10px;
display: block;
margin-top: -2px;
height: 40px;
}
}
}
}
}
</style>