Skip to content

Commit 60a6310

Browse files
committed
feat: First public release of redGPT
1 parent ef89932 commit 60a6310

File tree

19 files changed

+814
-8884
lines changed

19 files changed

+814
-8884
lines changed

app.config.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
export default defineAppConfig({
22
ui: {
3-
primary: 'red',
4-
gray: 'cool',
3+
colors: {
4+
primary: 'red',
5+
gray: 'cool',
6+
}
57
}
68
})
79

app.vue

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,37 @@
11
<template>
2-
<NuxtPage />
2+
<UApp>
3+
<NuxtPage />
4+
</UApp>
35
</template>
6+
7+
<style>
8+
@import "tailwindcss";
9+
@import "@nuxt/ui";
10+
11+
@theme {
12+
--font-family-sans: Poppins, sans-serif;
13+
}
14+
15+
body {
16+
background: #fdf9e9;
17+
}
18+
19+
::-webkit-scrollbar {
20+
width: 20px;
21+
}
22+
23+
::-webkit-scrollbar-track {
24+
background-color: transparent;
25+
}
26+
27+
::-webkit-scrollbar-thumb {
28+
background-color: #e6a89d;
29+
border-radius: 20px;
30+
border: 6px solid transparent;
31+
background-clip: content-box;
32+
}
33+
34+
::-webkit-scrollbar-thumb:hover {
35+
background-color: #c00007;
36+
}
37+
</style>

bun.lockb

18.9 KB
Binary file not shown.

components/ArticleModal.vue

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
<script lang="ts" setup>
2+
const props = defineProps<{
3+
query: string
4+
}>()
5+
6+
const userPrefs = useUserPrefsStore()
7+
const searchQuery = ref('')
8+
const isLoading = ref(false)
9+
const modal = useModal()
10+
11+
onMounted(() => {
12+
searchQuery.value = props.query
13+
})
14+
15+
const languages_list = ref([
16+
"Afrikaans",
17+
"Albanian - shqip",
18+
"Amharic - አማርኛ",
19+
"Arabic - العربية",
20+
"Aragonese - aragonés",
21+
"Armenian - հայերեն",
22+
"Asturian - asturianu",
23+
"Azerbaijani - azərbaycan dili",
24+
"Basque - euskara",
25+
"Belarusian - беларуская",
26+
"Bengali - বাংলা",
27+
"Bosnian - bosanski",
28+
"Breton - brezhoneg",
29+
"Bulgarian - български",
30+
"Catalan - català",
31+
"Central Kurdish - کوردی (دەستنوسی عەرەبی)",
32+
"Chinese - 中文",
33+
"Chinese (Hong Kong) - 中文(香港)",
34+
"Chinese (Simplified) - 中文(简体)",
35+
"Chinese (Traditional) - 中文(繁體)",
36+
"Corsican",
37+
"Croatian - hrvatski",
38+
"Czech - čeština",
39+
"Danish - dansk",
40+
"Dutch - Nederlands",
41+
"English",
42+
"Esperanto - esperanto",
43+
"Estonian - eesti",
44+
"Faroese - føroyskt",
45+
"Filipino",
46+
"Finnish - suomi",
47+
"French",
48+
"Galician - galego",
49+
"Georgian - ქართული",
50+
"German - Deutsch",
51+
"German (Austria) - Deutsch (Österreich)",
52+
"German (Germany) - Deutsch (Deutschland)",
53+
"German (Liechtenstein) - Deutsch (Liechtenstein)",
54+
"German (Switzerland) - Deutsch (Schweiz)",
55+
"Greek - Ελληνικά",
56+
"Guarani",
57+
"Gujarati - ગુજરાતી",
58+
"Hausa",
59+
"Hawaiian - ʻŌlelo Hawaiʻi",
60+
"Hebrew - עברית",
61+
"Hindi - हिन्दी",
62+
"Hungarian - magyar",
63+
"Icelandic - íslenska",
64+
"Indonesian - Indonesia",
65+
"Interlingua",
66+
"Irish - Gaeilge",
67+
"Italian - italiano",
68+
"Italian (Italy) - italiano (Italia)",
69+
"Italian (Switzerland) - italiano (Svizzera)",
70+
"Japanese - 日本語",
71+
"Kannada - ಕನ್ನಡ",
72+
"Kazakh - қазақ тілі",
73+
"Khmer - ខ្មែរ",
74+
"Korean - 한국어",
75+
"Kurdish - Kurdî",
76+
"Kyrgyz - кыргызча",
77+
"Lao - ລາວ",
78+
"Latin",
79+
"Latvian - latviešu",
80+
"Lingala - lingála",
81+
"Lithuanian - lietuvių",
82+
"Macedonian - македонски",
83+
"Malay - Bahasa Melayu",
84+
"Malayalam - മലയാളം",
85+
"Maltese - Malti",
86+
"Marathi - मराठी",
87+
"Mongolian - монгол",
88+
"Nepali - नेपाली",
89+
"Norwegian - norsk",
90+
"Norwegian Bokmål - norsk bokmål",
91+
"Norwegian Nynorsk - nynorsk",
92+
"Occitan",
93+
"Oriya - ଓଡ଼ିଆ",
94+
"Oromo - Oromoo",
95+
"Pashto - پښتو",
96+
"Persian - فارسی",
97+
"Polish - polski",
98+
"Portuguese - português",
99+
"Portuguese (Brazil) - português (Brasil)",
100+
"Portuguese (Portugal) - português (Portugal)",
101+
"Punjabi - ਪੰਜਾਬੀ",
102+
"Quechua",
103+
"Romanian - română",
104+
"Romanian (Moldova) - română (Moldova)",
105+
"Romansh - rumantsch",
106+
"Russian - русский",
107+
"Scottish Gaelic",
108+
"Serbian - српски",
109+
"Serbo - Croatian",
110+
"Shona - chiShona",
111+
"Sindhi",
112+
"Sinhala - සිංහල",
113+
"Slovak - slovenčina",
114+
"Slovenian - slovenščina",
115+
"Somali - Soomaali",
116+
"Southern Sotho",
117+
"Spanish - español",
118+
"Spanish (Argentina) - español (Argentina)",
119+
"Spanish (Latin America) - español (Latinoamérica)",
120+
"Spanish (Mexico) - español (México)",
121+
"Spanish (Spain) - español (España)",
122+
"Spanish (United States) - español (Estados Unidos)",
123+
"Sundanese",
124+
"Swahili - Kiswahili",
125+
"Swedish - svenska",
126+
"Tajik - тоҷикӣ",
127+
"Tamil - தமிழ்",
128+
"Tatar",
129+
"Telugu - తెలుగు",
130+
"Thai - ไทย",
131+
"Tigrinya - ትግርኛ",
132+
"Tongan - lea fakatonga",
133+
"Turkish - Türkçe",
134+
"Turkmen",
135+
"Twi",
136+
"Ukrainian - українська",
137+
"Urdu - اردو",
138+
"Uyghur",
139+
"Uzbek - o‘zbek",
140+
"Vietnamese - Tiếng Việt",
141+
"Walloon - wa",
142+
"Welsh - Cymraeg",
143+
"Western Frisian",
144+
"Xhosa",
145+
"Yiddish",
146+
"Yoruba - Èdè Yorùbá",
147+
"Zulu - isiZulu"
148+
]);
149+
150+
151+
const article_lengths = ref([
152+
{
153+
label: "Short",
154+
value: "short",
155+
icon: 'i-lucide-file-text'
156+
},
157+
{
158+
label: "Medium",
159+
value: "medium",
160+
icon: 'i-lucide-newspaper',
161+
},
162+
{
163+
label: "Long",
164+
value: "long",
165+
icon: 'i-lucide-book',
166+
}
167+
]);
168+
169+
const navigateToArticle = async () => {
170+
return new Promise<void>(async (resolve, reject) => {
171+
try {
172+
await navigateTo('/article?q=' + searchQuery.value + '&searchLang=' + userPrefs.language + '&articleLang=' + userPrefs.articleLanguage + '&articleLength=' + userPrefs.articleLength)
173+
modal.close()
174+
resolve()
175+
} catch (error) {
176+
reject(error)
177+
} finally {
178+
}
179+
})
180+
}
181+
</script>
182+
183+
<template>
184+
<UModal title="Deep dive" close-icon="i-tabler-x">
185+
<template #body>
186+
<div class="flex flex-col gap-4">
187+
<h3 class="text-xl font-bold">
188+
Search settings
189+
</h3>
190+
<UFormField label="Query" description="Your search query" class="w-full">
191+
<UInput icon="i-tabler-search" v-model="searchQuery" placeholder="Genesis of the modern State"
192+
class="w-full" />
193+
</UFormField>
194+
<UFormField label="Languages" description="List of languages allowed in the search results" class="w-full">
195+
<UInputMenu icon="i-tabler-language" v-model="userPrefs.searchLanguage" multiple="true" :items="languages_list"
196+
class="w-full" />
197+
</UFormField>
198+
</div>
199+
<USeparator class="my-4" />
200+
<div class="flex flex-col gap-4">
201+
<h3 class="text-xl font-bold">
202+
Article settings
203+
</h3>
204+
<UFormField label="Article length" description="The length of the article to be written" class="w-full">
205+
<UTabs v-model="userPrefs.articleLength" :content="false" :items="article_lengths" class="w-full" />
206+
</UFormField>
207+
<UFormField label="Article language" description="The language of the article to be written" class="w-full">
208+
<UInputMenu icon="i-tabler-language" v-model="userPrefs.articleLanguage" :items="languages_list"
209+
class="w-full" />
210+
</UFormField>
211+
</div>
212+
</template>
213+
<template #footer>
214+
<div class="flex gap-4">
215+
<UButton loading-auto @click="navigateToArticle" icon="i-tabler-article">
216+
Deep dive
217+
</UButton>
218+
</div>
219+
</template>
220+
</UModal>
221+
</template>
222+
<style></style>

components/Header.vue

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<script setup>
2+
const apiKeysStore = useApiKeysStore();
3+
const { apiKeys, apiKeysUnset } = storeToRefs(apiKeysStore);
4+
const showLogin = ref(false)
5+
const { signIn, status: userStatus, data: userAccount } = useAuth()
6+
7+
onMounted(async () => {
8+
if (apiKeysUnset.value && userStatus.value !== 'authenticated') {
9+
showLogin.value = true
10+
}
11+
})
12+
13+
const login = async () => {
14+
signIn('google')
15+
}
16+
17+
</script>
18+
19+
<template>
20+
<div class="flex justify-between items-end w-full pb-4 my-8">
21+
<nuxt-link to="/">
22+
<h1 class="text-5xl font-bold leading-8 text-black">
23+
redGPT<span class="text-red-700 text-8xl leading-8">.</span>
24+
</h1>
25+
</nuxt-link>
26+
<div class="flex bg-[var(--ui-primary)] text-[var(--ui-bg)] rounded-md px-4 py-2 font-bold items-center gap-1"
27+
v-if="userAccount">
28+
<UIcon name="i-tabler-user-filled" />
29+
{{ userAccount.user.name }}
30+
</div>
31+
</div>
32+
<UModal v-model:open="showLogin" title="Login or use your API keys" close-icon="i-tabler-x">
33+
<template #body class="flex">
34+
<UButton icon="i-tabler-brand-google" class="mb-4 sm:mb-6 w-max mx-auto self-center flex" @click="login">
35+
Login with Google
36+
</UButton>
37+
<USeparator label="OR" />
38+
<div class="flex flex-col gap-4">
39+
<UFormField label="OpenAI">
40+
<UInput class="w-full" v-model="apiKeys.OpenAI"
41+
placeholder="sk-feaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" icon="i-tabler-brand-openai" />
42+
</UFormField>
43+
<UFormField label="ExaAI">
44+
<UInput class="w-full" v-model="apiKeys.exa" placeholder="xxxxxxxxxxxxxxxxxxxxxxxx"
45+
icon="i-tabler-world-search" />
46+
</UFormField>
47+
<UButton @click="apiKeysUnset = false; showLogin = false" class="w-max">
48+
Save
49+
</UButton>
50+
</div>
51+
52+
</template>
53+
</UModal>
54+
</template>
55+
56+
<style>
57+
.userAvatar span {
58+
color: #FFF;
59+
}
60+
</style>

components/SearchBar.vue

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<script setup>
2+
import { LazyArticleModal, LazySearchModal } from '#components';
3+
4+
const props = defineProps({
5+
query: {
6+
type: String,
7+
required: true
8+
},
9+
inline: {
10+
type: Boolean,
11+
default: false
12+
}
13+
})
14+
15+
const userQuery = ref('')
16+
userQuery.value = props.query
17+
18+
const modal = useModal()
19+
const openSearchModal = () => {
20+
modal.open(LazySearchModal, {
21+
query: userQuery.value
22+
})
23+
}
24+
25+
const openArticleModal = () => {
26+
modal.open(LazyArticleModal, {
27+
query: userQuery.value
28+
})
29+
}
30+
</script>
31+
32+
<template>
33+
<div :class="['mb-4', 'flex', 'gap-4', 'justify-center', 'items-center', { 'flex-wrap': !inline, 'flex-nowrap': inline }]">
34+
<UInput v-model="userQuery" icon="i-tabler-search" class="w-full" />
35+
<UButton @click="openSearchModal()" class="w-max text-nowrap" icon="i-tabler-world-search">
36+
Search
37+
</UButton>
38+
<UButton @click="openArticleModal()" class="w-max text-nowrap" icon="i-tabler-article">
39+
Deep dive
40+
</UButton>
41+
</div>
42+
<SearchModal />
43+
<ArticleModal />
44+
</template>

0 commit comments

Comments
 (0)