Skip to content

Commit 58e21cd

Browse files
committedFeb 20, 2024·
Solving assets issue and adding search by title page
1 parent 0fa740a commit 58e21cd

File tree

8 files changed

+617
-393
lines changed

8 files changed

+617
-393
lines changed
 

‎frontend/components/home/Highlighter.vue

+258-256
Large diffs are not rendered by default.

‎frontend/layouts/default.vue

+66-60
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,87 @@
11
<template>
2-
<div>
3-
<nav class="bg-[#181818] inset-0 h-20 w-full border-b-2 border-white">
4-
<div
5-
class="bg-[#181818] font-bold h-18 pt-5 flex py-2 text-white float-left text-2xl pl-2.5"
6-
>
7-
Navbar
8-
</div>
9-
<div class="flex justify-end py-3 bg-[#181818]">
10-
<button
11-
class="w-[50px] bg-black text-white font-bold flex-row flex-nowrap rounded-xl mr-5 border-2 h-[45px] mt-[5px]"
12-
@click="toggle"
13-
>
14-
<i class="material-icons">menu</i>
15-
</button>
16-
</div>
17-
<div class="flex navbar-list flex-col w-full h-0">
18-
<button
19-
v-for="item in navigation"
20-
v-bind:key="item.name"
21-
class="text-white font-bold rounded-xl h-0 bg-slate-900 hover:bg-indigo-950 cursor-pointer decoration-transparent navbar-nav hidden"
22-
>
23-
<NuxtLink
24-
class="underline-none"
25-
v-bind:active="item.active"
26-
v-bind:to="item.href"
27-
>
28-
{{ item.name }}
29-
</NuxtLink>
30-
</button>
31-
</div>
32-
</nav>
33-
<slot />
34-
</div>
2+
<div>
3+
<nav class="bg-[#181818] inset-0 h-20 w-full border-b-2 border-white">
4+
<div
5+
class="bg-[#181818] font-bold h-18 pt-5 flex py-2 text-white float-left text-2xl pl-2.5"
6+
>
7+
Navbar
8+
</div>
9+
<div class="flex justify-end py-3 bg-[#181818]">
10+
<button
11+
class="w-[50px] bg-black text-white font-bold flex-row flex-nowrap rounded-xl mr-5 border-2 h-[45px] mt-[5px]"
12+
@click="toggle"
13+
>
14+
<i class="material-icons">menu</i>
15+
</button>
16+
</div>
17+
<div class="flex flex-col w-full h-0 navbar-list">
18+
<button
19+
v-for="item in navigation"
20+
v-bind:key="item.name"
21+
class="hidden h-0 font-bold text-white cursor-pointer rounded-xl bg-slate-900 hover:bg-indigo-950 decoration-transparent navbar-nav"
22+
>
23+
<NuxtLink
24+
class="underline-none"
25+
v-bind:active="item.active"
26+
v-bind:to="item.href"
27+
>
28+
{{ item.name }}
29+
</NuxtLink>
30+
</button>
31+
</div>
32+
</nav>
33+
<slot />
34+
</div>
3535
</template>
3636

3737
<script setup lang="ts">
3838
import "./../app.css";
3939
import { ref } from "vue";
4040
4141
let navigation = ref<{ name: string; href: string; active: boolean }[]>([
42-
{ name: "Home", href: "/", active: true },
43-
{ name: "About", href: "/about", active: false },
44-
{ name: "Create", href: "/create", active: false },
42+
{ name: "Home", href: "/", active: true },
43+
{ name: "About", href: "/about", active: false },
44+
{ name: "Create", href: "/create", active: false },
4545
]);
4646
4747
function toggle() {
48-
if (
49-
document.getElementsByClassName("navbar-list")[0].classList.contains("h-0")
50-
) {
51-
document
52-
.getElementsByClassName("navbar-list")[0]
53-
.classList.replace("h-0", "h-{165px}");
54-
document.querySelectorAll("button.navbar-nav").forEach((node) => {
55-
node.classList.replace("h-0", "h-[55px]");
56-
node.classList.replace("hidden", "block");
57-
});
58-
document.getElementsByTagName("nav")[0].classList.replace("h-20", "h-50");
59-
} else {
60-
document
61-
.getElementsByClassName("navbar-list")[0]
62-
.classList.replace("h-{165px}", "h-0");
63-
document.querySelectorAll("button.navbar-nav").forEach((node) => {
64-
node.classList.replace("h-[55px]", "h-0");
65-
node.classList.replace("block", "hidden");
66-
});
67-
document.getElementsByTagName("nav")[0].classList.replace("h-50", "h-20");
68-
}
48+
if (
49+
document
50+
.getElementsByClassName("navbar-list")[0]
51+
.classList.contains("h-0")
52+
) {
53+
document
54+
.getElementsByClassName("navbar-list")[0]
55+
.classList.replace("h-0", "h-{165px}");
56+
document.querySelectorAll("button.navbar-nav").forEach((node) => {
57+
node.classList.replace("h-0", "h-[55px]");
58+
node.classList.replace("hidden", "block");
59+
});
60+
document
61+
.getElementsByTagName("nav")[0]
62+
.classList.replace("h-20", "h-50");
63+
} else {
64+
document
65+
.getElementsByClassName("navbar-list")[0]
66+
.classList.replace("h-{165px}", "h-0");
67+
document.querySelectorAll("button.navbar-nav").forEach((node) => {
68+
node.classList.replace("h-[55px]", "h-0");
69+
node.classList.replace("block", "hidden");
70+
});
71+
document
72+
.getElementsByTagName("nav")[0]
73+
.classList.replace("h-50", "h-20");
74+
}
6975
}
7076
</script>
7177

7278
<style scoped>
7379
nav > div:nth-child(2) > button:nth-child(1) {
74-
@apply bg-indigo-950;
80+
@apply bg-indigo-950;
7581
}
7682
7783
button > i.material-icons {
78-
font-size: 30px !important;
79-
padding-top: 5px;
84+
font-size: 30px !important;
85+
padding-top: 5px;
8086
}
8187
</style>

‎frontend/package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎frontend/pages/about/index.vue

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
<script setup lang="ts">
22
import { ref } from "vue";
33
import { definePageMeta } from "#imports";
4+
import tsLogo from "@/assets/ts-logo.png";
5+
import vite from "@/assets/vite.png";
6+
import vue from "@/assets/vue.png";
7+
48
definePageMeta({
59
layout: "default",
610
});
11+
12+
useHead({
13+
title: "About Page",
14+
});
715
interface pageModule {
816
name: string;
917
link: string;
@@ -15,17 +23,17 @@ let homeList = ref<pageModule[]>([
1523
{
1624
name: "Vue",
1725
link: "vuejs.org",
18-
img: "~/assets/vue.png",
26+
img: vue,
1927
},
2028
{
2129
name: "TypeScript",
2230
link: "typescriptlang.org",
23-
img: "~/assets/ts-logo.png",
31+
img: tsLogo,
2432
},
2533
{
2634
name: "Vite",
2735
link: "vitejs.dev",
28-
img: "~/assets/vite.png",
36+
img: vite,
2937
},
3038
{
3139
name: "tailwindcss",

‎frontend/pages/create/index.vue

+14-12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ definePageMeta({
77
layout: "default",
88
});
99
10+
useHead({
11+
title: "Create Page",
12+
});
13+
1014
let langNames = ref<Array<string>>([]);
1115
onMounted(async () => {
1216
let res = await fetch("http://localhost:3300", {
@@ -16,9 +20,7 @@ onMounted(async () => {
1620
Accept: "application/json",
1721
},
1822
body: JSON.stringify({
19-
query: `query {
20-
langNames
21-
}`,
23+
query: `query { langNames }`,
2224
}),
2325
});
2426
let data = await res.json();
@@ -86,14 +88,14 @@ function update() {
8688

8789
<template>
8890
<h1>Create Page</h1>
89-
<div class="text-center flex flex-row select-container h-6 flex-nowrap">
91+
<div class="flex flex-row h-6 text-center select-container flex-nowrap">
9092
<div class="">Select a language</div>
9193
<div class="w-20">
9294
<select
9395
name="lang-select"
9496
v-model="langSelect"
9597
@change="selectValChange"
96-
class="bg-slate-800 text-white"
98+
class="text-white bg-slate-800"
9799
>
98100
<option
99101
v-for="(langname, index) in langNames"
@@ -108,7 +110,7 @@ function update() {
108110
</div>
109111

110112
<input
111-
class="rounded-lg bg-slate-800 code-title text-white"
113+
class="text-white rounded-lg bg-slate-800 code-title"
112114
placeholder="Enter title"
113115
v-model="inputTitle"
114116
required
@@ -117,19 +119,19 @@ function update() {
117119
<textarea
118120
id="code-input"
119121
v-model="defaultSnip"
120-
class="bg-slate-800 rounded-lg"
122+
class="rounded-lg bg-slate-800"
121123
placeholder="enter code here"
122124
autocapitalize="off"
123125
v-on:keydown="update"
124126
required
125127
></textarea>
126-
<div class="text-black mt-2">
128+
<div class="mt-2 text-black">
127129
<div
128-
class="flex flex-row overflow-none mb-0 bg-gray-200 float-left circle-box"
130+
class="flex flex-row float-left mb-0 bg-gray-200 overflow-none circle-box"
129131
>
130-
<div class="bg-red-500 rounded-full mt-2 circle"></div>
131-
<div class="bg-yellow-500 rounded-full mt-2 circle"></div>
132-
<div class="bg-green-500 rounded-full mt-2 circle"></div>
132+
<div class="mt-2 bg-red-500 rounded-full circle"></div>
133+
<div class="mt-2 bg-yellow-500 rounded-full circle"></div>
134+
<div class="mt-2 bg-green-500 rounded-full circle"></div>
133135
<div class="overflow-y-scroll snip-title">{{ inputTitle }}</div>
134136
</div>
135137
</div>

‎frontend/pages/index.vue

+123-61
Original file line numberDiff line numberDiff line change
@@ -6,85 +6,147 @@ import hljs from "highlight.js";
66
import "./vs-dark.css";
77
import { definePageMeta } from "#imports";
88
9+
const state = reactive({ search: "" });
10+
911
const LangList = ref<
10-
{
11-
id: string;
12-
langName: string;
13-
codeBoxes: { title: string; code: string }[];
14-
}[]
12+
{
13+
id: string;
14+
langName: string;
15+
codeBoxes: { title: string; code: string }[];
16+
}[]
1517
>([]);
1618
19+
function goto() {
20+
console.log(state.search);
21+
navigateTo("/search/" + state.search);
22+
}
23+
1724
definePageMeta({
18-
layout: "default",
25+
layout: "default",
1926
});
2027
21-
onMounted(async () => {
22-
let data = await fetch("http://localhost:3300/", {
23-
method: "POST",
24-
headers: {
25-
"Content-Type": "application/json",
26-
Accept: "application/json",
27-
},
28-
body: JSON.stringify({
29-
query: "{langList{langName, codeBoxes {title, code}}}",
30-
}),
31-
});
32-
let res = await data.json();
33-
34-
LangList.value = res.data.langList;
35-
setTimeout(() => {
36-
hljs.highlightAll();
37-
}, 100);
28+
onMounted(async function () {
29+
document
30+
.getElementById("search")!
31+
.addEventListener("keydown", function (event) {
32+
event.preventDefault();
33+
event.key == "Enter" && goto();
34+
});
35+
let data = await fetch("http://localhost:3300/", {
36+
method: "POST",
37+
headers: {
38+
"Content-Type": "application/json",
39+
Accept: "application/json",
40+
},
41+
body: JSON.stringify({
42+
query: "{langList{langName, codeBoxes {title, code}}}",
43+
}),
44+
});
45+
let res = await data.json();
46+
47+
LangList.value = res.data.langList;
48+
setTimeout(function () {
49+
hljs.highlightAll();
50+
}, 100);
3851
});
3952
</script>
4053
<template>
41-
<div id="home">
42-
<div v-if="!LangList.length">
43-
<div id="loading"></div>
44-
</div>
45-
<div v-else>
46-
<div v-for="(langBox, index) in LangList" :key="index">
47-
<h2 class="text-center">
48-
{{
49-
langBox.langName.charAt(0).toUpperCase() + langBox.langName.slice(1)
50-
}}
51-
</h2>
52-
<HomeHighlighter
53-
v-for="(codeBox, index2) in langBox.codeBoxes"
54-
:key="index2"
55-
v-bind:langName="langBox.langName"
56-
v-bind:snipTitle="codeBox.title"
57-
v-bind:snipCode="codeBox.code"
58-
/>
59-
</div>
60-
</div>
61-
</div>
54+
<div id="home">
55+
<div class="flex justify-center">
56+
<div class="flex flex-row search-box">
57+
<input
58+
type="text"
59+
id="search"
60+
placeholder="Search title"
61+
v-model="state.search"
62+
class="search"
63+
/>
64+
<button class="appearance-none h-min" @click="goto">
65+
<i class="material-icons search-icon">search</i>
66+
</button>
67+
</div>
68+
</div>
69+
<div v-if="!LangList.length">
70+
<div id="loading"></div>
71+
</div>
72+
<div v-else>
73+
<div v-for="(langBox, index) in LangList" :key="index">
74+
<h2 class="text-center">
75+
{{
76+
langBox.langName.charAt(0).toUpperCase() +
77+
langBox.langName.slice(1)
78+
}}
79+
</h2>
80+
<HomeHighlighter
81+
v-for="(codeBox, index2) in langBox.codeBoxes"
82+
:key="index2"
83+
v-bind:langName="langBox.langName"
84+
v-bind:snipTitle="codeBox.title"
85+
v-bind:snipCode="codeBox.code"
86+
/>
87+
</div>
88+
</div>
89+
</div>
6290
</template>
6391
<style scoped>
92+
@tailwind components;
93+
@layer components {
94+
.search-box {
95+
@apply my-10;
96+
}
97+
98+
.search-box i.search-icon {
99+
@apply border-gray-500;
100+
}
101+
102+
.search-box:hover .search-icon {
103+
@apply border-sky-500;
104+
}
105+
106+
.search-box button {
107+
@apply h-10;
108+
}
109+
110+
.search {
111+
@apply w-[100%] outline-none border-gray-500 border-2 h-10 rounded-bl-full rounded-tl-full pl-5;
112+
}
113+
114+
.search:focus {
115+
@apply w-[120%] outline-none border-sky-500;
116+
}
117+
118+
.search-icon {
119+
@apply text-white bg-gray-500 rounded-tr-full rounded-br-full pt-2.5 w-10 h-10;
120+
}
121+
122+
.search:focus + button .search-icon {
123+
background-color: skyblue;
124+
}
125+
}
64126
button > i.material-icons {
65-
font-size: 30px !important;
66-
padding-top: 5px;
127+
font-size: 30px !important;
128+
padding-top: 5px;
67129
}
68130
69131
#loading {
70-
margin-top: 45vh;
71-
margin-left: 50vw;
72-
width: 48px;
73-
height: 48px;
74-
border: 5px solid #3498db;
75-
border-radius: 50%;
76-
border-bottom-color: transparent;
77-
box-sizing: border-box;
78-
animation: rotate 1s linear infinite;
132+
margin-top: 45vh;
133+
margin-left: 50vw;
134+
width: 48px;
135+
height: 48px;
136+
border: 5px solid #3498db;
137+
border-radius: 50%;
138+
border-bottom-color: transparent;
139+
box-sizing: border-box;
140+
animation: rotate 1s linear infinite;
79141
}
80142
81143
@keyframes rotate {
82-
0% {
83-
transform: rotate(0deg);
84-
}
144+
0% {
145+
transform: rotate(0deg);
146+
}
85147
86-
100% {
87-
transform: rotate(360deg);
88-
}
148+
100% {
149+
transform: rotate(360deg);
150+
}
89151
}
90152
</style>

‎frontend/pages/search/[title].vue

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<script lang="ts" setup>
2+
import { ref } from "vue";
3+
import "./../../app.css";
4+
import { onMounted } from "vue";
5+
import hljs from "highlight.js";
6+
import "./../vs-dark.css";
7+
8+
let route = useRoute();
9+
let title = route.params.title;
10+
11+
const titleFind = ref<
12+
{
13+
langName: string;
14+
codeBoxes: { title: string; code: string }[];
15+
}[]
16+
>([]);
17+
18+
onMounted(async function () {
19+
let data = await fetch("http://localhost:3300/", {
20+
method: "POST",
21+
headers: {
22+
"Content-Type": "application/json",
23+
Accept: "application/json",
24+
},
25+
body: JSON.stringify({
26+
query: `#graphql
27+
{
28+
titleFind(title: "${title}") {
29+
langName,
30+
codeBoxes {
31+
title, code
32+
}
33+
}
34+
}`,
35+
}),
36+
});
37+
let res = await data.json();
38+
39+
titleFind.value = res.data.titleFind;
40+
setTimeout(function () {
41+
hljs.highlightAll();
42+
}, 100);
43+
});
44+
</script>
45+
46+
<template>
47+
<div v-if="!titleFind.length">
48+
<div id="loading"></div>
49+
</div>
50+
<div v-else>
51+
<div class="flex justify-center my-10">
52+
<div
53+
class="p-5 border-4 border-b-0 border-l-0 shadow-lg border-sky-400 shadow-black rounded-xl"
54+
>
55+
<button @click="() => navigateTo('/')">
56+
<h4 class="font-bold text-center text-sky-600">
57+
<i class="text-2xl font-bold material-icons"
58+
>arrow_back_ios_new</i
59+
>
60+
Go to Home Page
61+
</h4>
62+
</button>
63+
</div>
64+
</div>
65+
<div v-for="(langBox, index) in titleFind" :key="index">
66+
<h2 class="text-center">
67+
{{
68+
langBox.langName.charAt(0).toUpperCase() +
69+
langBox.langName.slice(1)
70+
}}
71+
</h2>
72+
<HomeHighlighter
73+
v-for="(codeBox, index2) in langBox.codeBoxes"
74+
:key="index2"
75+
v-bind:langName="langBox.langName"
76+
v-bind:snipTitle="codeBox.title"
77+
v-bind:snipCode="codeBox.code"
78+
/>
79+
</div>
80+
</div>
81+
</template>
82+
<style scoped>
83+
#loading {
84+
margin-top: 45vh;
85+
margin-left: 50vw;
86+
width: 48px;
87+
height: 48px;
88+
border: 5px solid #3498db;
89+
border-radius: 50%;
90+
border-bottom-color: transparent;
91+
box-sizing: border-box;
92+
animation: rotate 1s linear infinite;
93+
}
94+
95+
@keyframes rotate {
96+
0% {
97+
transform: rotate(0deg);
98+
}
99+
100+
100% {
101+
transform: rotate(360deg);
102+
}
103+
}
104+
</style>

‎frontend/searchbar.html

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<link
5+
href="https://fonts.googleapis.com/icon?family=Material+Icons"
6+
rel="stylesheet"
7+
/>
8+
<style>
9+
.search-container {
10+
display: flex;
11+
align-items: center;
12+
border: 1px solid #ccc;
13+
padding: 5px;
14+
width: 200px;
15+
}
16+
.search-container:focus-within {
17+
border-color: skyblue;
18+
}
19+
.search-container:focus-within .search-icon {
20+
background-color: skyblue;
21+
}
22+
.search-icon {
23+
margin-right: 5px;
24+
background-color: #fff;
25+
transition: background-color 0.3s;
26+
}
27+
.search-input {
28+
border: none;
29+
outline: none;
30+
width: 100%;
31+
}
32+
</style>
33+
</head>
34+
<body>
35+
<div class="search-container">
36+
<i class="material-icons search-icon">search</i>
37+
<input type="text" class="search-input" placeholder="Search..." />
38+
</div>
39+
</body>
40+
</html>

0 commit comments

Comments
 (0)
Please sign in to comment.