├── assets ├── topic_filter.json ├── data │ ├── contributors.json │ └── team.json └── config.js ├── .npmrc ├── .DS_Store ├── .env.sample ├── .firebaserc ├── server ├── tsconfig.json ├── api │ ├── gemini.post.ts │ └── openai.post.ts ├── services │ ├── openai.ts │ └── gemini.ts └── utils │ └── prompt.ts ├── public ├── logo.png ├── .DS_Store ├── favicon.ico ├── authors │ ├── .DS_Store │ ├── abhinav.jpg │ ├── vrijraj.jpeg │ └── default-avatar-author.jpg ├── donotremove │ ├── .DS_Store │ ├── team │ │ ├── .DS_Store │ │ ├── abhinav.jpg │ │ ├── shivam.jpg │ │ └── vrijraj.jpeg │ ├── gradus-social.png │ ├── ai-logo.svg │ ├── gradus-background.svg │ ├── build-with-gradus.svg │ └── logo.svg └── codelabs │ └── getting-started-with-gradus │ └── hero.png ├── .gitignore ├── tsconfig.json ├── app.vue ├── utils ├── date.ts └── getReadTIme.ts ├── components ├── content │ ├── MdButton.vue │ ├── ProseBlockquote.vue │ ├── MdAlert.vue │ └── GTeam.vue ├── Core │ ├── Header.vue │ ├── AppBar.vue │ ├── AppFooter.vue │ ├── HeroCard.vue │ ├── BottomNav.vue │ ├── AppBanner.vue │ ├── SocialMedia.vue │ ├── LeftSideBar.vue │ ├── AuthorCard.vue │ ├── LabCard.vue │ ├── GTeam.vue │ └── shareBtn.vue ├── AIChat.vue └── Sidebar │ └── Chips.vue ├── plugins └── vuetify.ts ├── composables └── states.ts ├── scripts ├── index.js └── build_tags.js ├── .github └── workflows │ ├── firebase-hosting-merge.yml │ └── firebase-hosting-pull-request.yml ├── package.json ├── LICENSE ├── firebase.json ├── nuxt.config.ts ├── pages ├── about.vue ├── index.vue └── [...slug].vue ├── tokens.config.ts ├── README.md ├── CODE_OF_CONDUCT.md └── content └── getting-started-with-gradus.md /assets/topic_filter.json: -------------------------------------------------------------------------------- 1 | ["GRADUS","WEB","SETUP"] -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/.DS_Store -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY="YOUR-API-KEY" 2 | GEMINI_API_KEY="YOUR-API-KEY" -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "trygradus" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/logo.png -------------------------------------------------------------------------------- /public/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/.DS_Store -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | .nuxt 4 | .nitro 5 | .cache 6 | .output 7 | .data 8 | .env 9 | dist -------------------------------------------------------------------------------- /public/authors/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/authors/.DS_Store -------------------------------------------------------------------------------- /public/authors/abhinav.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/authors/abhinav.jpg -------------------------------------------------------------------------------- /public/authors/vrijraj.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/authors/vrijraj.jpeg -------------------------------------------------------------------------------- /public/donotremove/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/donotremove/.DS_Store -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://v3.nuxtjs.org/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /public/donotremove/team/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/donotremove/team/.DS_Store -------------------------------------------------------------------------------- /public/donotremove/team/abhinav.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/donotremove/team/abhinav.jpg -------------------------------------------------------------------------------- /public/donotremove/team/shivam.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/donotremove/team/shivam.jpg -------------------------------------------------------------------------------- /public/donotremove/gradus-social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/donotremove/gradus-social.png -------------------------------------------------------------------------------- /public/donotremove/team/vrijraj.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/donotremove/team/vrijraj.jpeg -------------------------------------------------------------------------------- /public/authors/default-avatar-author.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/authors/default-avatar-author.jpg -------------------------------------------------------------------------------- /public/codelabs/getting-started-with-gradus/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sidagarwal04/codelabs/main/public/codelabs/getting-started-with-gradus/hero.png -------------------------------------------------------------------------------- /app.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /utils/date.ts: -------------------------------------------------------------------------------- 1 | export const getFormatedDate = (dateString: any)=>{ 2 | const options = { month: "long", day: "numeric", year: "2-digit" }; 3 | const date = new Date(dateString); 4 | return date.toLocaleDateString("en-US", options); 5 | } -------------------------------------------------------------------------------- /assets/data/contributors.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Sonakshi Panday", 4 | "link": "https://github.com/sonakshi1501" 5 | }, 6 | { 7 | "name": "Nishant Kumar Singh", 8 | "link": "https://github.com/NishaantKrSingh" 9 | } 10 | ] -------------------------------------------------------------------------------- /server/api/gemini.post.ts: -------------------------------------------------------------------------------- 1 | import getData from "../services/gemini"; 2 | 3 | export default defineEventHandler(async (event) => { 4 | const body = await readBody(event); 5 | 6 | try { 7 | const response = await getData(body.prompt); 8 | return { response }; 9 | } catch (error) { 10 | return { error: error }; 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /server/api/openai.post.ts: -------------------------------------------------------------------------------- 1 | import fetchOpenAIResponse from "../services/openai"; 2 | 3 | export default defineEventHandler(async (event) => { 4 | const body = await readBody(event); 5 | 6 | try { 7 | const response = await fetchOpenAIResponse(body.prompt); 8 | return { response }; 9 | } catch (error) { 10 | return { error: error }; 11 | } 12 | }); 13 | -------------------------------------------------------------------------------- /components/content/MdButton.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | -------------------------------------------------------------------------------- /plugins/vuetify.ts: -------------------------------------------------------------------------------- 1 | // import this after install `@mdi/font` package 2 | import '@mdi/font/css/materialdesignicons.css' 3 | import { VFab } from 'vuetify/labs/VFab' 4 | 5 | import 'vuetify/styles' 6 | import { createVuetify } from 'vuetify' 7 | 8 | export default defineNuxtPlugin((app) => { 9 | const vuetify = createVuetify({ 10 | components: { 11 | VFab, 12 | }, 13 | // ... your configuration 14 | }) 15 | app.vueApp.use(vuetify) 16 | }) -------------------------------------------------------------------------------- /components/content/ProseBlockquote.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /composables/states.ts: -------------------------------------------------------------------------------- 1 | // For expanding main section 2 | export const useIsExpanded = () => useState("isExpanded", () => false); 3 | 4 | // For setting current section of markdown to render 5 | // export const useCurrentNode = () => useState("currentNode", () => 0); 6 | 7 | // export const useFilter = () => useState("filter", () => []); 8 | 9 | export const useAIChat = () => useState("aiDrawer", () => false); 10 | 11 | export const useAppLoading = () => useState("appLoading", () => false); 12 | 13 | export const useSideBar = () => useState("sideBar", () => true); 14 | -------------------------------------------------------------------------------- /components/Core/Header.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 23 | -------------------------------------------------------------------------------- /scripts/index.js: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import { fileURLToPath } from 'url'; 3 | import path from 'path'; 4 | 5 | const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file 6 | const __dirname = path.dirname(__filename); 7 | 8 | fs.readdirSync(__dirname) 9 | .filter((file) => { 10 | return ( 11 | file.indexOf(".") !== 0 && 12 | file !== "index.js" && 13 | file.slice(-3) === ".js" && 14 | file.indexOf(".test.js") === -1 15 | ); 16 | }) 17 | .forEach(async (file) => { 18 | const data = await import("./" + file); 19 | data.default(); 20 | }); 21 | -------------------------------------------------------------------------------- /.github/workflows/firebase-hosting-merge.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on merge 5 | on: 6 | push: 7 | branches: 8 | - main 9 | jobs: 10 | build_and_deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - run: npm ci && npm run generate 15 | - uses: FirebaseExtended/action-hosting-deploy@v0 16 | with: 17 | repoToken: ${{ secrets.GITHUB_TOKEN }} 18 | firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_TRYGRADUS }} 19 | channelId: live 20 | projectId: trygradus 21 | -------------------------------------------------------------------------------- /components/content/MdAlert.vue: -------------------------------------------------------------------------------- 1 | 11 | 29 | -------------------------------------------------------------------------------- /server/services/openai.ts: -------------------------------------------------------------------------------- 1 | import OpenAI from "openai"; 2 | import { getGeminiPrompt, getOpenAIPrompt } from "../utils/prompt"; 3 | 4 | async function fetchOpenAIResponse(prompt: string) { 5 | try { 6 | const openai = new OpenAI({ 7 | apiKey: process.env["OPENAI_API_KEY"], // This is the default and can be omitted 8 | }); 9 | const completion = await openai.chat.completions.create({ 10 | messages: [ 11 | { role: "user", content: getOpenAIPrompt(JSON.stringify(prompt)) }, 12 | ], 13 | model: "gpt-3.5-turbo", 14 | }); 15 | return completion.choices[0].message; 16 | } catch (error) { 17 | console.error("Error calling OpenAI API:", error); 18 | throw error; 19 | } 20 | } 21 | 22 | export default fetchOpenAIResponse; 23 | -------------------------------------------------------------------------------- /.github/workflows/firebase-hosting-pull-request.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on PR 5 | on: pull_request 6 | permissions: 7 | checks: write 8 | contents: read 9 | pull-requests: write 10 | jobs: 11 | build_and_preview: 12 | if: ${{ github.event.pull_request.head.repo.full_name == github.repository }} 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | - run: npm ci && npm run generate 17 | - uses: FirebaseExtended/action-hosting-deploy@v0 18 | with: 19 | repoToken: ${{ secrets.GITHUB_TOKEN }} 20 | firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_TRYGRADUS }} 21 | projectId: trygradus 22 | -------------------------------------------------------------------------------- /public/donotremove/ai-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "type": "module", 4 | "scripts": { 5 | "preBuild": "node scripts/index.js", 6 | "build": "npm run preBuild && nuxt build", 7 | "dev": "npm run preBuild && nuxt dev", 8 | "generate": "npm run preBuild && nuxt generate", 9 | "preview": "npm run preBuild && nuxt preview", 10 | "staticbuild": "npm run preBuild && npx nuxi generate" 11 | }, 12 | "dependencies": { 13 | "@google/generative-ai": "^0.8.0", 14 | "@mdi/font": "^7.4.47", 15 | "@nuxt-themes/typography": "^1.0.1", 16 | "@nuxt/content": "^2.12.1", 17 | "@nuxt/image": "^1.7.0", 18 | "@nuxtjs/robots": "^3.0.0", 19 | "@nuxtjs/sitemap": "^5.2.0", 20 | "@tailwindcss/typography": "^0.5.12", 21 | "@vueuse/core": "^10.9.0", 22 | "nuxt": "^3.11.2", 23 | "openai": "^4.38.5" 24 | }, 25 | "devDependencies": { 26 | "nuxt-gtag": "^2.0.5", 27 | "vite-plugin-vuetify": "^2.0.3", 28 | "vuetify": "^3.5.17" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /components/Core/AppBar.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 35 | -------------------------------------------------------------------------------- /components/Core/AppFooter.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 35 | 36 | -------------------------------------------------------------------------------- /components/Core/HeroCard.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 30 | 31 | -------------------------------------------------------------------------------- /server/utils/prompt.ts: -------------------------------------------------------------------------------- 1 | export const getGeminiPrompt = (content: String) => { 2 | const text = ` 3 | You are a Markdown Content Expert. 4 | Your task is extract content from the markdown file and answers according to user queries. 5 | 6 | Give me a exact content from this markdown code without explaining anything, make sure to provide it in the paragraph format only 7 | 8 | ${content} 9 | 10 | Please deliver the response in proper formated text. 11 | `; 12 | 13 | return text; 14 | }; 15 | 16 | export const getOpenAIPrompt = (content: String) => { 17 | const text = ` 18 | Given the structured content below, which contains detailed descriptions and information on a specific topic, please provide a concise summary of the key points and main features described. 19 | The ${content} includes sections with headings, paragraphs, 20 | and various elements detailing aspects of the subject. 21 | Summarize the primary functionalities, usage, and any specific methods or instructions highlighted within the content. 22 | `; 23 | 24 | return text; 25 | }; 26 | -------------------------------------------------------------------------------- /assets/config.js: -------------------------------------------------------------------------------- 1 | export const config = { 2 | name: "Gradus Codelab", 3 | dsec: "Developer Hub, where you can access labs for various tech stacks to delve into detailed use cases of technologies.", 4 | thumbnail: "donotremove/gradus-social.png", 5 | hostUrl: "https://gradus.dev", 6 | favicon: "/favicon.ico", 7 | social: { 8 | linkedin: "https://www.linkedin.com/in/trygradus/", 9 | twitter: "https://twitter.com/trygradus", 10 | instagram: "https://www.instagram.com/trygradus/", 11 | github: "https://github.com/oss-labs/gradus", 12 | youtube: "", 13 | web: "https://grauds.dev", 14 | }, 15 | config: { 16 | aiFlag: false, 17 | aiFlagType: "gemini", // openai or gemini 18 | theme: "light", // dark or light 19 | banner: { 20 | status: true, 21 | title: "We're at Product Hunt 🚀", 22 | content: "Show some ❤️ and support the Gradus", 23 | link: "https://www.producthunt.com/products/gradus", 24 | }, 25 | }, 26 | seo: { 27 | keywords: 'Gradus Codelab, Gradus, Codelab, oss-lab, oss', 28 | author: "Oss Labs", 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /assets/data/team.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Vrijraj Singh", 4 | "img": "vrijraj.jpeg", 5 | "social": { 6 | "linkedin": "https://www.linkedin.com/in/vrijrajsingh/", 7 | "twitter": "https://twitter.com/SVrijraj", 8 | "github": "https://github.com/vrijraj", 9 | "website": "https://vrijraj.xyz/" 10 | } 11 | }, 12 | { 13 | "name": "Shivam Singh", 14 | "img": "shivam.jpg", 15 | "social": { 16 | "linkedin": "https://www.linkedin.com/in/s-shivam/", 17 | "twitter": "https://twitter.com/Shivamc504?t=Vc1j2jeHDLkS1-cSM1LSkg&s=09", 18 | "github": "", 19 | "website": "https://shivam.live/" 20 | } 21 | }, 22 | { 23 | "name": "Abhinav Verma", 24 | "img": "abhinav.jpg", 25 | "social": { 26 | "linkedin": "https://www.linkedin.com/in/abhinavv9/", 27 | "twitter": "https://twitter.com/sudoboink", 28 | "github": "https://github.com/abhinavv9", 29 | "website": "https://www.sudoboink.me/" 30 | } 31 | } 32 | ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Vrijraj 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /components/Core/BottomNav.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /utils/getReadTIme.ts: -------------------------------------------------------------------------------- 1 | interface Node { 2 | tag: string; 3 | type: string; 4 | value: string; 5 | children?: Node[]; 6 | } 7 | 8 | // Function to get read time 9 | const getReadTime = (content: Node[]): number => { 10 | try { 11 | let words = 0; 12 | const avgWordsPerMinute = 200; 13 | 14 | const extractText = (node: Node): string => { 15 | if (node.type === "text") { 16 | return node.value.trim(); 17 | } else if (node.children && Array.isArray(node.children)) { 18 | return node.children.map(extractText).join(" "); 19 | } else { 20 | return ""; 21 | } 22 | }; 23 | 24 | // Traverse content and calculate word count 25 | for (const node of content) { 26 | if (node.tag !== "style") { 27 | const text = extractText(node); 28 | words += text.split(/\s+/).length; // Count words 29 | } 30 | } 31 | 32 | const time = Math.ceil(words / avgWordsPerMinute); 33 | return time; 34 | } catch (error) { 35 | console.error(`Error processing markdown content: ${error}`); 36 | return 0; 37 | } 38 | }; 39 | 40 | export default getReadTime; 41 | -------------------------------------------------------------------------------- /scripts/build_tags.js: -------------------------------------------------------------------------------- 1 | import * as fs from "fs"; 2 | import * as path from "path"; 3 | import { parseMarkdown } from "@nuxtjs/mdc/runtime"; 4 | 5 | const DIR_FOR_CONTENTS = "./content/"; 6 | 7 | const run = async () => { 8 | const tagSet = new Set(); 9 | const files = []; 10 | fs.readdirSync(DIR_FOR_CONTENTS) 11 | .filter((file) => { 12 | return ( 13 | file.indexOf(".") !== 0 && 14 | file.slice(-3) === ".md" 15 | ); 16 | }) 17 | .forEach((file) => { 18 | files.push(path.join(DIR_FOR_CONTENTS, file)); 19 | }); 20 | 21 | for await (const file of files) { 22 | const data = fs.readFileSync(file, "utf8"); 23 | const a = await parseMarkdown(data); 24 | if (a.data.tags != undefined) { 25 | a.data.tags.forEach((tag) => tagSet.add(tag)); 26 | } 27 | } 28 | 29 | const tags = [...tagSet]; 30 | 31 | console.log("Tags to be used", tags); 32 | fs.writeFileSync( 33 | "./assets/topic_filter.json", 34 | JSON.stringify(tags), 35 | "utf8" 36 | ); 37 | }; 38 | 39 | export default run; 40 | -------------------------------------------------------------------------------- /components/Core/AppBanner.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 33 | 34 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": ".output/public", 4 | "cleanUrls": true, 5 | "ignore": [ 6 | "firebase.json", 7 | "**/.*", 8 | "**/node_modules/**" 9 | ], 10 | "rewrites": [ 11 | { 12 | "source": "**", 13 | "destination": "/index.html" 14 | } 15 | ], 16 | "headers": [ 17 | { 18 | "source": "**/*.np@(eot|otf|ttf|ttc|woff|font.css)", 19 | "headers": [ 20 | { 21 | "key": "Access-Control-Allow-Origin", 22 | "value": "*" 23 | } 24 | ] 25 | }, 26 | { 27 | "source": "**/*.@(jpg|jpeg|gif|png)", 28 | "headers": [ 29 | { 30 | "key": "Cache-Control", 31 | "value": "max-age=31557600" 32 | } 33 | ] 34 | }, 35 | { 36 | "source": "**/*.@(css|js)", 37 | "headers": [ 38 | { 39 | "key": "Cache-Control", 40 | "value": "max-age=31557600" 41 | } 42 | ] 43 | }, 44 | { 45 | "source": "**/*.@(woff2|svg|min.css)", 46 | "headers": [ 47 | { 48 | "key": "Cache-Control", 49 | "value": "max-age=31557600" 50 | } 51 | ] 52 | } 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /components/Core/SocialMedia.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 59 | 60 | -------------------------------------------------------------------------------- /components/Core/LeftSideBar.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 50 | -------------------------------------------------------------------------------- /components/Core/AuthorCard.vue: -------------------------------------------------------------------------------- 1 | 48 | 61 | -------------------------------------------------------------------------------- /components/Core/LabCard.vue: -------------------------------------------------------------------------------- 1 | 48 | 49 | 60 | 61 | -------------------------------------------------------------------------------- /nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | import vuetify, { transformAssetUrls } from "vite-plugin-vuetify"; 3 | import { config } from "./assets/config"; 4 | export default defineNuxtConfig({ 5 | ssr: true, 6 | build: { 7 | transpile: ["vuetify"], 8 | }, 9 | site: { 10 | url: config.hostUrl, 11 | }, 12 | devtools: { enabled: false }, 13 | modules: [ 14 | "@nuxt/content", 15 | (_options, nuxt) => { 16 | nuxt.hooks.hook("vite:extendConfig", (config) => { 17 | // @ts-expect-error 18 | config.plugins.push(vuetify({ autoImport: true })); 19 | }); 20 | }, 21 | "nuxt-gtag", 22 | "@nuxt/image", 23 | "@nuxtjs/sitemap", 24 | [ 25 | "@nuxtjs/robots", 26 | { 27 | rules: [ 28 | { UserAgent: "*" }, 29 | { Disallow: "" }, 30 | { BlankLine: true }, 31 | { Sitemap: `${config.hostUrl}sitemap.xml` }, 32 | ], 33 | }, 34 | ], 35 | //... 36 | ], 37 | vite: { 38 | vue: { 39 | template: { 40 | transformAssetUrls, 41 | }, 42 | }, 43 | }, 44 | content: { 45 | documentDriven: true, 46 | experimental: { 47 | clientDb: true, 48 | search: { 49 | fields: ["title", "description", "tags"], 50 | }, 51 | }, 52 | highlight: { 53 | theme: "light-plus", 54 | }, 55 | markdown: { 56 | anchorLinks: { 57 | depth: 0, 58 | }, 59 | // tags: { 60 | // p: 'MyCustomParagraph' 61 | // } 62 | }, 63 | }, 64 | extends: "@nuxt-themes/typography", 65 | nitro: { 66 | prerender: { 67 | crawlLinks: true, 68 | failOnError: false, 69 | }, 70 | // firebase: { 71 | // gen: 2 72 | // } 73 | }, 74 | gtag: { 75 | id: "G-JC8BJZ2R1G", 76 | }, 77 | }); 78 | -------------------------------------------------------------------------------- /server/services/gemini.ts: -------------------------------------------------------------------------------- 1 | import { 2 | GoogleGenerativeAI, 3 | HarmCategory, 4 | HarmBlockThreshold, 5 | } from "@google/generative-ai"; 6 | 7 | const MODEL_NAME = "gemini-1.5-pro-latest"; 8 | const API_KEY = process.env["GEMINI_API_KEY"]; 9 | const genAI = new GoogleGenerativeAI(API_KEY!); 10 | const model = genAI.getGenerativeModel({ model: MODEL_NAME }); 11 | const generationConfig = { 12 | temperature: 0.9, 13 | topK: 1, 14 | topP: 1, 15 | maxOutputTokens: 30720, 16 | }; 17 | 18 | const safetySettings = [ 19 | { 20 | category: HarmCategory.HARM_CATEGORY_HARASSMENT, 21 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 22 | }, 23 | { 24 | category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, 25 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 26 | }, 27 | { 28 | category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, 29 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 30 | }, 31 | { 32 | category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, 33 | threshold: HarmBlockThreshold.BLOCK_MEDIUM_AND_ABOVE, 34 | }, 35 | ]; 36 | // // Provide me a summary from the below MD file content in the paragraph format only 37 | 38 | const getData = async (content: Object) => { 39 | 40 | const parts = [ 41 | { 42 | text: ` 43 | You are a Markdown Content Expert. 44 | Your task is extract content from the markdown file and answers according to user queries. 45 | 46 | Give me a exact content from this markdown code without explaining anything, make sure to provide it in the paragraph format only 47 | 48 | ${JSON.stringify(content)} 49 | 50 | Please deliver the response in propert formated text. 51 | `, 52 | }, 53 | ]; 54 | 55 | try { 56 | const result = await model.generateContent({ 57 | contents: [{ role: "user", parts }], 58 | generationConfig, 59 | safetySettings, 60 | }); 61 | 62 | return { response: result.response.text() }; 63 | } catch (error) { 64 | return { error: error }; 65 | } 66 | }; 67 | 68 | export default getData; 69 | -------------------------------------------------------------------------------- /components/AIChat.vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /pages/about.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 61 | 62 | -------------------------------------------------------------------------------- /components/Sidebar/Chips.vue: -------------------------------------------------------------------------------- 1 | 62 | 76 | 79 | -------------------------------------------------------------------------------- /components/Core/GTeam.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | 74 | 75 | -------------------------------------------------------------------------------- /components/content/GTeam.vue: -------------------------------------------------------------------------------- 1 | 79 | 80 | 84 | 85 | -------------------------------------------------------------------------------- /tokens.config.ts: -------------------------------------------------------------------------------- 1 | import { defineTheme } from 'pinceau' 2 | 3 | export default defineTheme({ 4 | typography: { 5 | // This will change the general line-break size 6 | letterSpacings: { 7 | tight: '-0.0035em', 8 | wide: '0.-0035em' 9 | }, 10 | // lead:'0px', 11 | 12 | }, 13 | prose: { 14 | // This will change the fontSize of the `` component 15 | h1: { 16 | fontSize: '28px', 17 | fontWeight: '600', 18 | margin: '0px 0px 5px 0px' 19 | }, 20 | h2: { 21 | fontSize: '20px', 22 | margin: '30px 0px 10px 0px' 23 | }, 24 | h3: { 25 | fontSize: '20px', 26 | margin: '30px 0px 5px 0px' 27 | }, 28 | h4: { 29 | fontSize: '18px', 30 | margin: '30px 0px 5px 0px' 31 | }, 32 | h5: { 33 | fontSize: '15px', 34 | margin: '35px 0px 5px 0px', 35 | }, 36 | h6: { 37 | fontSize: '12px', 38 | margin: '30px 0px 5px 0px' 39 | }, 40 | ul: { 41 | fontSize: '90%', 42 | margin: '4px', 43 | li: { 44 | margin: '2px', 45 | fontSize: '90%', 46 | } 47 | }, 48 | li: { 49 | margin: '0px', 50 | fontSize: '90%' 51 | }, 52 | ol: { 53 | margin: '4px', 54 | fontSize: '90%', 55 | li: { 56 | margin: '2px', 57 | fontSize: '90%' 58 | } 59 | }, 60 | p: { 61 | margin: '2px 0', 62 | // fontSize: '90%' 63 | }, 64 | img: { 65 | borderRadius: '12px' 66 | }, 67 | 68 | code: { 69 | block: { 70 | fontSize: '15px', 71 | margin: '20px 0', 72 | borderWidth: '1px', 73 | borderStyle: 'solid', 74 | borderColor: { 75 | initial: '#e0e0e0', 76 | dark: '{typography.color.secondary.800}' 77 | }, 78 | borderRadius: '10px', 79 | // color: { 80 | // initial: '#F8F9FA', 81 | // dark: '{typography.color.secondary.200}' 82 | // }, 83 | backgroundColor: { 84 | initial: '#F8F9FA', 85 | dark: '{typography.color.secondary.900}' 86 | }, 87 | backdropFilter: { 88 | initial: 'contrast(1)', 89 | dark: 'contrast(1)' 90 | }, 91 | pre: { 92 | // padding: '15px' 93 | } 94 | }, 95 | inline: { 96 | borderRadius: '{typography.radii.3xs}', 97 | padding: '0.2rem 0.375rem 0.2rem 0.375rem', 98 | // fontSize: '{typography.fontSize.sm}', 99 | fontWeight: '{typography.fontWeight.normal}', 100 | color: { 101 | initial: '{typography.color.secondary.700}', 102 | dark: '{typography.color.secondary.200}' 103 | }, 104 | backgroundColor: { 105 | initial: '#E7EAED', 106 | dark: '{typography.color.secondary.700}' 107 | } 108 | } 109 | } 110 | } 111 | }) 112 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Gradus 4 | Gradus is an open-source tool that enables you to create codelabs using both markdown and rich markdown components. It offers the flexibility to operate either server-side or client-side, depending on your preference. Additionally, Gradus is experimenting with AI-enabled features to enhance its capabilities. 5 | 6 | ### Show some :heart: and :star: the repo to support the project 7 | 8 | ## Features 9 | - Gradus is user-friendly, allowing you to effortlessly create codelabs with markdown and its rich components. 10 | - Features a mobile-friendly user interface. 11 | - SEO-optimized to ensure all content is indexed, boosting visibility in search results. 12 | - Equipped with experimental AI-enabled functionalities. 13 | - Suitable for both individual developers and tech communities. 14 | - Fast and optimized for performance. 15 | 16 | # Setup Guide 17 | 18 | [Follow this Codelab on Gradus](https://trygradus.web.app/getting-started-with-gradus) 19 | 20 | 21 | ## Prerequisites 22 | 23 | Ensure you have the following installed: 24 | 25 | - Node.js (version 18 or later) 26 | - NUXT 3 (a modern Vue.js framework) 27 | - Vuetify 3 (a Vue UI Library) 28 | 29 | > [!IMPORTANT] 30 | > **Note on AI Features:** Currently, AI features are only supported in SSR deployments. 31 | 32 | # Contributors 33 | 34 | ## Maintainers: 35 | 1. [Vrijraj Singh](https://vrijraj.xyz/) 36 | 1. [Abhinav Verma](https://github.com/abhinavv9) 37 | 1. [Shivam Singh](https://shivam.live/) 38 | 1. [Bharat Agarwal](https://github.com/agarwalbharat) 39 | 40 | # Contribution 41 | 42 | Awesome! We greatly appreciate contributions of all kinds. To make the process smoother, here are some guidelines that should help you get started quickly. 43 | 44 | ### Using GitHub Issues 45 | 46 | - **What to Use Issues For:** Feel free to use GitHub issues for questions, bug reports, and feature requests. 47 | - **Searching:** Before creating a new issue, use the search feature to check if there is already an existing discussion about it. 48 | - **Information and Resources:** Include as much information as possible when creating an issue. Relevant resources like screenshots are very helpful. 49 | - **Bug Reports:** For bug reports, ensure you provide a reproducible test case. A pull request with a failing test is ideal, though not required. 50 | 51 | ### Submitting a Pull Request 52 | 53 | - **Commit Management:** Squash your commits to keep the history clean. 54 | - **Code Quality:** Lint your code with eslint, using the provided configuration, to maintain code quality. 55 | - **Tests:** Include updates or additions to tests relevant to your changes. 56 | - **Branch Policy:** Make pull requests against the `dev-contribution` branch. Pull requests to other branches will be rejected unless specified by the maintainers. 57 | 58 | 59 | # List Your Project 60 | 61 | You can highlight your project in the `readme.md` file and also fill out the provided [Google form](https://bit.ly/gradus-directory) to share more about what you’ve built. 62 | 63 | ## View codelabs Build with Gradus 64 | 65 | 1. [Vrijraj Codelabs](https://codelab.vrijraj.xyz) 66 | 1. [Nishant Codelabs](https://codelab.nishants.me/) 67 | 1. [Abhinav Codelabs](https://gradus.sudoboink.me/) 68 | 1. [GDG Baku](https://codelabs.gdgbaku.az/) 69 | 1. [GDG Prayagraj](https://codelab-gdgprayagraj.web.app) 70 | 1. [Neha Codelabs](http://codelab.nehas.xyz) 71 | 72 | 73 | # Technology Stack 74 | 75 | * [Nuxt 3](https://nuxt.com/) 76 | * [Vuetify](https://vuetifyjs.com/en/) 77 | * [Nuxt Content](https://content.nuxt.com/) 78 | 79 | # Team and Support 80 | If you encounter any issues or have queries, post them in the issues section. Our dedicated team will strive to address your concerns within 10-12 hours. 81 | -------------------------------------------------------------------------------- /components/Core/shareBtn.vue: -------------------------------------------------------------------------------- 1 | 108 | 109 | 174 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /pages/index.vue: -------------------------------------------------------------------------------- 1 | 121 | 122 | 207 | 208 | 209 | -------------------------------------------------------------------------------- /public/donotremove/gradus-background.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /pages/[...slug].vue: -------------------------------------------------------------------------------- 1 | 181 | 182 | 367 | -------------------------------------------------------------------------------- /content/getting-started-with-gradus.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Getting Started With Gradus" 3 | description: "This CodeLab demonstrates how to setup gradus for yourself" 4 | slug: "getting-started-with-gradus" 5 | authors: 6 | [ 7 | { 8 | name: "Vrijraj Singh", 9 | image: "/authors/vrijraj.jpeg", 10 | socials: 11 | { 12 | linkedin: "https://www.linkedin.com/in/vrijrajsingh/", 13 | github: "https://github.com/vrijraj", 14 | web: "https://vrijraj.xyz", 15 | } 16 | }, 17 | { 18 | name: "Abhinav Verma", 19 | image: "/authors/abhinav.jpg", 20 | socials: 21 | { 22 | linkedin: "https://www:linkedin.com/in/abhinavv9", 23 | github: "https://github.com/abhinavv9", 24 | web: "https://sudoboink.me", 25 | } 26 | } 27 | ] 28 | date: 2024-05-07 29 | categories: "Technology" 30 | duration: 30 31 | image: "/codelabs/getting-started-with-gradus/hero.png" 32 | tags: ["GRADUS", "WEB", "SETUP"] 33 | draft: false 34 | --- 35 | 36 | # Introduction 37 | 38 | Gradus is an open-source tool that enables you to create codelabs using both markdown and rich markdown components. It offers the flexibility to operate either server-side or client-side, depending on your preference. Additionally, Gradus is experimenting with AI-enabled features to enhance its capabilities. 39 | 40 | hero 41 | 42 | ## Features 43 | 44 | - Gradus is user-friendly, allowing you to effortlessly create codelabs with markdown and its rich components. 45 | - Features a mobile-friendly user interface. 46 | - SEO-optimized to ensure all content is indexed, boosting visibility in search results. 47 | - Equipped with experimental AI-enabled functionalities. 48 | - Suitable for both individual developers and tech communities. 49 | - Fast and optimized for performance. 50 | 51 | ## Contributing 52 | 53 | Awesome! Contributions of all kinds are greatly appreciated. To help smoothen the process we have a few non-exhaustive guidelines to follow which should get you going in no time. 54 | 55 | # Setup Guide 56 | 57 | ## Prerequisites 58 | 59 | Ensure you have the following installed: 60 | 61 | - [Node.js](https://nodejs.org/en){:target="_blank"} (version 18 or later) 62 | 65 | 66 | ## Installing Gradus 67 | 68 | Follow these steps to set up the GRADUS project on your local machine: 69 | 70 | 1. **Fork and Clone the Repository:** Start by forking [this repository](https://github.com/oss-labs/gradus){:target="_blank"} from GitHub and then clone it to your local machine. 71 | 74 | 75 | 2. **Install Dependencies:** Navigate to the project directory and run the following command to install all the required dependencies. 76 | ```bash 77 | npm install 78 | ``` 79 | 3. **Run Locally:** Execute the following command to start the development server and view the project in your browser. 80 | ```bash 81 | npm run dev 82 | ``` 83 | 84 | 85 | :::md-alert{type="success"} 86 | #title 87 | ✨ Your development server should be up and running at [localhost:300](http://localhost:3000/). 88 | 89 | ::: 90 | 91 |
92 | 93 | :::md-alert{type="failure"} 94 | #title 95 | Note: 96 | #content 97 | In case localhost:3000 is pre-occupied it will automtically be mapped to another port visible in terminal while running the project. 98 | ::: 99 | 4. **Setup Complete:** Your setup is now complete, and you're ready to start using GRADUS! 100 | 101 |
102 | 103 | 5. **Prepare for Production:** When you're ready to build for production, use the following command. This will create a `./output` directory containing the production build of your project. 104 | ```bash 105 | npm run staticbuild 106 | ``` 107 | 108 | 109 | 110 | # Customization 111 | Gradus is highly customizeable, you can customize ever aspect of it according to your needs. 112 | 113 | ## Project Structure Overview 114 | 115 | Here’s a breakdown of the project's file structure: 116 | 117 | ```text 118 | └── 📁gradus-app 119 | ├── .env 120 | ├── nuxt.config.ts # Main configuration file for Nuxt.js. 121 | ├── 📁.output # This directory is generated during production builds, containing the server and client code. 122 | ├── 📁assets 123 | │ └── config.js # Stores configuration for project metadata, AI settings, and other customization options. 124 | ├── 📁components 125 | │ ├── 📁core # Core reusable Vue components. 126 | │ └── 📁content # Content-specific components like custom Markdown components used in codelabs. 127 | ├── 📁content 128 | │ └── getting-started-with-gradus.md # Markdown file for the codelab content, where users start their learning journey. 129 | ├── 📁pages 130 | │ ├── index.vue # The main landing page of the application. 131 | │ └── [...slug].vue # Dynamic route handler for Vue.js, handles all the slugs and displays corresponding content. 132 | ├── 📁public 133 | │ ├── favicon.ico 134 | │ ├── logo.png # General logo for the project, used across the site. 135 | │ └── 📁authors # Contains images and other static content related to authors contributing to the codelabs. 136 | │ └── 📁codelabs 137 | | └── 📁getting-started-with-gradus # Codelab specific folder to store images and assets 138 | | └── image.png 139 | └── 📁server # Server-side scripts and configuration files, possibly including API endpoints or server middleware. 140 | 141 | 142 | ``` 143 |
144 | 145 | #### Following files can be modified to make Gradus truly yours: 146 | 147 | 1. **Project Meta Information:** Navigate to `assets/config.js` to customize your codelab’s metadata, such as the project name, description, and social media links, along with SEO and AI-related settings. 148 | 2. **Images:** Upload thumbnail images and favicon to the `public` directory. 149 | 150 | 151 | 152 | # Configuration 153 | 154 | Customize your project to suit your needs with the following configuration options: 155 | 156 | ## Google Analytics Integration 157 | 158 | To add Google Analytics to your project: 159 | 160 | - **File Location:** Open the `nuxt.config.ts` file. 161 | - **Configuration:** Insert your Google Analytics tracking code here to start monitoring your application's traffic. 162 | 163 | ```ts[nuxt.config.ts] 164 | gtag: { 165 | id: "G-your-tag" 166 | } 167 | ``` 168 | 169 | ## Banner Management 170 | 171 | Manage the display banner easily: 172 | 173 | - **File Location:** Navigate to the `config.js` file. 174 | - **Toggle Banner:** You can easily enable or disable the banner. Additionally, you can modify the content of the banner directly within this file. 175 | 176 | ## Enabling AI Features 177 | 178 | To leverage AI functionalities within your project: 179 | 180 | - **Configuration Steps:** 181 | 182 | 1. Go to the `config.js` file. 183 | 2. Set `aiFlag` to `true` to enable AI features. 184 | 3. Adjust `aiFlagType` to specify the type of AI you want to activate ([openai](https://platform.openai.com/api-keys){:target="_blank"} or [gemini](https://aistudio.google.com/)){:target="_blank"}. 185 | 4. Create a `.env` file in the project root to securely store API keys. 186 | 187 | - **Environment File Setup:** Provide your API keys in the `.env` file as follows: 188 | 189 | ``` 190 | OPENAI_API_KEY="YOUR-API-KEY" 191 | GEMINI_API_KEY="YOUR-API-KEY" 192 | ``` 193 | 194 | # Create Your First Codelab 195 | 196 | Start by creating a new codelab using Markdown. This will guide you through setting up your first interactive tutorial. 197 | 198 | ## Step 1: Create a Markdown File 199 | 200 | - **Location:** Place your new Markdown file inside the `/content` folder. 201 | - **Example:** Name the file `hello-world.md`. 202 | 203 | ## Step 2: Define Metadata for the Codelab 204 | 205 | Metadata plays a vital role not only in informing users about your codelab but also in configuring how it interacts with the system’s user interface and functionalities: 206 | 207 | - **Purpose:** Metadata sets up the codelab's user interface and enables crucial functionalities like search and filtering. It ensures that the codelab is properly categorized and accessible, enhancing user engagement and organization. 208 | - **Syntax:** Insert the following JavaScript object at the top of your Markdown file to include metadata: 209 | 210 | ```js 211 | --- 212 | title: "Share Your Thought with Firebase"; 213 | description: "This Codelab demonstrates the use of Firebase for web developers."; 214 | slug: "share-your-thought-with-firebase"; 215 | authors: [ 216 | { 217 | name: "Abhinav Verma", 218 | image: "/authors/abhinav.png", 219 | socials: { 220 | linkedin: "https://linkedin.com/in/abhinavv9", 221 | github: "", 222 | twitter: "", 223 | web: "", 224 | }, 225 | }, 226 | ]; 227 | date: 2024 - 04 - 28; 228 | categories: "Setup"; 229 | image: "/codelabs/getting-started-with-gradus/hero.png"; 230 | tags: ["GRADUS"]; 231 | draft: false; 232 | --- 233 | ``` 234 | 235 | 236 | - **Details Explained:** 237 | - `title`: The name of your codelab. 238 | - `description`: A brief summary of what the codelab is about. 239 | - `slug`: A URL-friendly version of the title for navigation. 240 | - `authors`: Details about the author(s), including social media links. 241 | - `date`: The publication date. 242 | - `categories`: The category under which the codelab falls. 243 | - `image`: A path to an image file related to the codelab. 244 | - `tags`: Keywords associated with the codelab to help in search and organization. 245 | - `draft`: A boolean indicating if the codelab is a draft or ready for publication. 246 | 247 | ## Step 3: Define the Structure of Your Codelab 248 | 249 | Organize your codelab content using H1 tags to define major sections. **Each H1 tag will automatically start a new step** in the codelab, making it easy to follow. 250 | 251 | ```md 252 | # Introduction 253 | 254 | Introduce the goals and background of your codelab here. 255 | 256 | # Resources 257 | 258 | List resources or additional reading materials here. 259 | ``` 260 | 261 | 262 | # Markdown Components 263 | 264 | We currently support specific custom components in markdown such as `md-alert` and `md-button`. 265 | 266 | ## Using Markdown Components 267 | 268 | To incorporate markdown components into your document, use the custom component syntax `::::::`. 269 | 270 | ### Alert 271 | 272 | For adding an alert message: 273 | 274 | ```md 275 | :::md-alert 276 | #content 277 | This is an alert 278 | ::: 279 | ``` 280 | :::md-alert 281 | #content 282 | This is an alert 283 | ::: 284 | 285 | #### Customization 286 | 287 | Customizing these components allows you to tailor their appearance and behavior to better fit your content's needs. 288 | 289 | - **Customize `md-alert`** 290 | - **Purpose:** Modify the appearance and information of alert boxes. 291 | - **Properties:** 292 | - `type`: Specifies the style of the alert (e.g., success, error). 293 | 294 |
295 | 296 | - **Example:** 297 | 298 | 299 | 300 | ```md 301 | :::md-alert{type="success" } 302 | #title 303 | This is the title 304 | #content 305 | This is the content 306 | ::: 307 | ``` 308 | 309 | :::md-alert{type="success"} 310 | 311 | #title 312 | This is titile 313 | 314 | #content 315 | This is content 316 | 317 | ::: 318 | 319 |
320 | 321 | 322 | 323 |
324 | 325 | ### Button 326 | 327 | For adding a button. 328 | - **Customize `md-button`** 329 | - **Purpose:** Adjust the look and functionality of buttons. 330 | - **Properties:** 331 | - **type:** Defines the button style (e.g. `elevated`, `flat`, `tonal`, `outlined`, `text`, `plain`). 332 | - **color:** Sets the button color (e.g., primary, secondary). 333 | - **text:** Specifies the text displayed on the button. 334 | - **link:** Specifies the link for the action on the button. 335 | 336 | ```md 337 | :::md-button{type="tonal" color="primary" link="https://trygradus.web.app/"} 338 | Click me! 339 | ::: 340 | ``` 341 | 342 | 343 | :::md-button{type="tonal" color="primary" link="https://trygradus.web.app/"} 344 | Click me! 345 | ::: 346 | 347 | 348 | # Deployment 349 | 350 | This codelab can be deployed using one of two methods, each suited to different hosting environments and use cases. 351 | 352 | ## Server Side Rendering (SSR) 353 | 354 | Server Side Rendering (SSR) enhances SEO and improves performance for users by serving pre-rendered pages from the server. 355 | 356 | - **How to Generate Server-Side Code:** 357 | - Run the command `npm run build` in your project directory. This builds the application and prepares it for deployment. 358 | - **Hosting Options:** 359 | 360 | - **Netlify:** Follow Netlify’s documentation to deploy your SSR application. 361 | - **Vercel:** Use Vercel for advanced server-side rendering capabilities. Both platforms support automatic deployment from your git repository. 362 | 363 |
364 | 365 | :::md-alert{type="error"} 366 | #content 367 | **Note on AI Features:** Currently, AI features are only supported in SSR deployments. 368 | ::: 369 | 370 | ## Static Site Generation (SSG) 371 | 372 | Static Site Generation (SSG) offers fast loading times and reliable performance by generating HTML files at build time, which can be hosted on any static hosting service. 373 | 374 | - **How to Generate Static Code:** 375 | - Execute the command `npm run staticbuild`. This command will produce a fully static version of your site, which can be deployed without needing a server. 376 | - **Hosting Options:** 377 | - **Firebase:** Ideal for hosting static files with benefits like integrated security features and easy scaling. 378 | - **GitHub Pages:** A straightforward option for hosting static websites, especially if your project is already managed in a GitHub repository. 379 | 380 |
381 | 382 | Choose the deployment method that best fits your project needs and the expected traffic. SSR is generally better for dynamic sites with heavy user interaction, while SSG is excellent for sites with fewer updates and high performance requirements. 383 | 384 | # Contribution 385 | 386 | Awesome! We greatly appreciate contributions of all kinds. To make the process smoother, here are some guidelines that should help you get started quickly. 387 | 388 | ### Using GitHub Issues 389 | 390 | - **What to Use Issues For:** Feel free to use GitHub issues for questions, bug reports, and feature requests. 391 | - **Searching:** Before creating a new issue, use the search feature to check if there is already an existing discussion about it. 392 | - **Information and Resources:** Include as much information as possible when creating an issue. Relevant resources like screenshots are very helpful. 393 | - **Bug Reports:** For bug reports, ensure you provide a reproducible test case. A pull request with a failing test is ideal, though not required. 394 | 395 | ### Submitting a Pull Request 396 | 397 | - **Commit Management:** Squash your commits to keep the history clean. 398 | - **Code Quality:** Lint your code with eslint, using the provided configuration, to maintain code quality. 399 | - **Tests:** Include updates or additions to tests relevant to your changes. 400 | - **Branch Policy:** Make pull requests against the `dev-contribution` branch. Pull requests to other branches will be rejected unless specified by the maintainers. 401 | 402 | # List Your Project 403 | 404 | You can highlight your project in the `readme.md` file and also fill out the provided [Google form](https://bit.ly/gradus-directory){:target="_blank"} to share more about what you’ve built. 405 | 406 | # Future Roadmap 407 | 408 | Our future enhancements include exciting features such as: 409 | 410 | - **Dark Theme Mode:** A user-friendly option for better night-time viewing. 411 | - **Internationalization:** To make our project accessible in multiple languages. 412 | - **Progressive Web App (PWA):** For a near-native app experience on mobile and desktop devices. 413 | - **AI Integration:** Implementing AI to enhance functionality and user experience. 414 | 415 | # Team and Support 416 | 417 | :::g-team 418 | ::: 419 | 420 | If you encounter any issues or have queries, post them in the issues section. Our dedicated team will strive to address your concerns within 10-12 hours. 421 | -------------------------------------------------------------------------------- /public/donotremove/build-with-gradus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/donotremove/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | --------------------------------------------------------------------------------