├── .npmrc
├── bun.lockb
├── src
├── lib
│ ├── index.ts
│ ├── components
│ │ └── ui
│ │ │ ├── label
│ │ │ ├── index.ts
│ │ │ └── label.svelte
│ │ │ ├── dialog
│ │ │ ├── dialog-portal.svelte
│ │ │ ├── dialog-header.svelte
│ │ │ ├── dialog-footer.svelte
│ │ │ ├── dialog-title.svelte
│ │ │ ├── dialog-description.svelte
│ │ │ ├── dialog-overlay.svelte
│ │ │ ├── index.ts
│ │ │ └── dialog-content.svelte
│ │ │ ├── select
│ │ │ ├── select-separator.svelte
│ │ │ ├── select-label.svelte
│ │ │ ├── index.ts
│ │ │ ├── select-trigger.svelte
│ │ │ ├── select-content.svelte
│ │ │ └── select-item.svelte
│ │ │ ├── button
│ │ │ ├── button.svelte
│ │ │ └── index.ts
│ │ │ └── input
│ │ │ ├── index.ts
│ │ │ └── input.svelte
│ ├── db
│ │ └── db.ts
│ ├── constants.ts
│ └── utils.ts
├── routes
│ ├── +layout.svelte
│ ├── +layout.server.ts
│ ├── +page.server.ts
│ ├── api
│ │ ├── get-communities
│ │ │ └── +server.ts
│ │ ├── get-community
│ │ │ └── +server.ts
│ │ └── create-community
│ │ │ └── +server.ts
│ ├── [username]
│ │ ├── +page.server.ts
│ │ └── +page.svelte
│ └── +page.svelte
├── app.d.ts
├── store
│ └── store.ts
├── app.css
├── components
│ ├── socials.svelte
│ ├── signInButton.svelte
│ ├── header.svelte
│ ├── footer.svelte
│ ├── eachCommunity.svelte
│ ├── radioComponent.svelte
│ └── addCommunity.svelte
├── models
│ └── community.model.ts
├── hooks.server.ts
└── app.html
├── static
├── favicon.png
├── favicon0.png
└── Screenshot.jpg
├── .prettierignore
├── postcss.config.js
├── .dockerignore
├── vite.config.ts
├── .gitignore
├── .eslintignore
├── .prettierrc
├── .env.example
├── components.json
├── .vscode
└── extensions.json
├── Dockerfile
├── .eslintrc.cjs
├── svelte.config.js
├── tsconfig.json
├── LICENSE
├── package.json
├── tailwind.config.js
└── README.md
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 |
--------------------------------------------------------------------------------
/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagmawibabi/TelegramCommunityGallery/HEAD/bun.lockb
--------------------------------------------------------------------------------
/src/lib/index.ts:
--------------------------------------------------------------------------------
1 | // place files you want to import through the `$lib` alias in this folder.
2 |
--------------------------------------------------------------------------------
/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagmawibabi/TelegramCommunityGallery/HEAD/static/favicon.png
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | # Ignore files for PNPM, NPM and YARN
2 | pnpm-lock.yaml
3 | package-lock.json
4 | yarn.lock
5 |
--------------------------------------------------------------------------------
/static/favicon0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagmawibabi/TelegramCommunityGallery/HEAD/static/favicon0.png
--------------------------------------------------------------------------------
/static/Screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dagmawibabi/TelegramCommunityGallery/HEAD/static/Screenshot.jpg
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | .svelte-kit
3 | build
4 | node_modules
5 | .dockerignore
6 | .gitignore
7 | Dockerfile
8 | README.md
9 |
--------------------------------------------------------------------------------
/src/lib/components/ui/label/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./label.svelte";
2 |
3 | export {
4 | Root,
5 | //
6 | Root as Label,
7 | };
8 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { sveltekit } from '@sveltejs/kit/vite';
2 | import { defineConfig } from 'vite';
3 |
4 | export default defineConfig({
5 | plugins: [sveltekit()]
6 | });
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 | vite.config.js.timestamp-*
10 | vite.config.ts.timestamp-*
11 | .history
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /build
4 | /.svelte-kit
5 | /package
6 | .env
7 | .env.*
8 | !.env.example
9 |
10 | # Ignore files for PNPM, NPM and YARN
11 | pnpm-lock.yaml
12 | package-lock.json
13 | yarn.lock
14 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "useTabs": true,
3 | "singleQuote": true,
4 | "trailingComma": "none",
5 | "printWidth": 100,
6 | "plugins": ["prettier-plugin-svelte"],
7 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
8 | }
9 |
--------------------------------------------------------------------------------
/src/routes/+layout.server.ts:
--------------------------------------------------------------------------------
1 | import type { LayoutServerLoad } from "./$types"
2 |
3 | // -> load serverside any data we need.
4 |
5 | export const load: LayoutServerLoad = async (event) =>{
6 | return {
7 | session: await event.locals.auth()
8 | }
9 | }
--------------------------------------------------------------------------------
/src/lib/components/ui/dialog/dialog-portal.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/routes/+page.server.ts:
--------------------------------------------------------------------------------
1 | /** @type {import('./$types').PageServerLoad} */
2 | export async function load({ fetch }) {
3 | const res = await fetch('/api/get-communities');
4 | const data = await res.json()
5 |
6 | return {
7 | allCommunities: data
8 | };
9 | }
--------------------------------------------------------------------------------
/src/routes/api/get-communities/+server.ts:
--------------------------------------------------------------------------------
1 | import { json } from '@sveltejs/kit';
2 | import { Community } from '../../../models/community.model';
3 |
4 | export async function GET() {
5 | const fetchedCommunities = await Community.find().sort({_id: -1})
6 | return json(fetchedCommunities);
7 | }
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | LOGLIB_API_KEY= // LogLib.io key
2 | AUTH_SECRET= // mysecret
3 | GITHUB_CLIENT_ID= // your github client id
4 | GITHUB_CLIENT_SECRET= // your github client secret
5 | SECRET_MONGO_URI= // your mongo uri mongodb+srv://USERNAME:PASSWORD@DATABASE/COLLECTION?retryWrites=true&w=majority
6 |
7 |
--------------------------------------------------------------------------------
/src/app.d.ts:
--------------------------------------------------------------------------------
1 | // See https://kit.svelte.dev/docs/types#app
2 | // for information about these interfaces
3 | declare global {
4 | namespace App {
5 | // interface Error {}
6 | // interface Locals {}
7 | // interface PageData {}
8 | // interface PageState {}
9 | // interface Platform {}
10 | }
11 | }
12 |
13 | export {};
14 |
--------------------------------------------------------------------------------
/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://shadcn-svelte.com/schema.json",
3 | "style": "default",
4 | "tailwind": {
5 | "config": "tailwind.config.js",
6 | "css": "src\\app.css",
7 | "baseColor": "zinc"
8 | },
9 | "aliases": {
10 | "components": "$lib/components",
11 | "utils": "$lib/utils"
12 | },
13 | "typescript": true
14 | }
--------------------------------------------------------------------------------
/src/routes/api/get-community/+server.ts:
--------------------------------------------------------------------------------
1 | import { json } from '@sveltejs/kit';
2 | import { Community } from '../../../models/community.model';
3 |
4 |
5 | export async function GET({ request, url }) {
6 | const link = url.searchParams.get('link')
7 | const fetchedCommunity = await Community.find({ link });
8 | // console.log(fetchedCommunity)
9 | return json(fetchedCommunity);
10 | }
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-separator.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
4 | // List of extensions which should be recommended for users of this workspace.
5 | "recommendations": [
6 | "dbaeumer.vscode-eslint",
7 | "esbenp.prettier-vscode",
8 | "svelte.svelte-vscode"
9 | ],
10 | }
--------------------------------------------------------------------------------
/src/lib/components/ui/dialog/dialog-header.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dialog/dialog-footer.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-label.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dialog/dialog-title.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dialog/dialog-description.svelte:
--------------------------------------------------------------------------------
1 |
10 |
11 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/store/store.ts:
--------------------------------------------------------------------------------
1 | import { writable } from 'svelte/store';
2 |
3 | type Community = {
4 | name: string,
5 | link: string,
6 | description: string,
7 | owner: string | null | undefined,
8 | tags: string[],
9 | type: string,
10 | };
11 |
12 | export const currentCommunityStore = writable({});
13 | export const allCommunitiesStore = writable([]);
14 | export const filteredTagsStore = writable([]);
15 | export const visitorCountStore = writable(0);
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/routes/[username]/+page.server.ts:
--------------------------------------------------------------------------------
1 | /** @type {import('./$types').PageServerLoad} */
2 | export async function load({ fetch, params }) {
3 | const username = params.username
4 | const community = await fetch(`/api/get-community?link=${username}`)
5 | const res = await community.json()
6 |
7 | const allCommunities = await fetch('/api/get-communities');
8 | const res2 = await allCommunities.json()
9 |
10 | return ({
11 | community: res,
12 | allCommunities: res2
13 | });
14 | }
--------------------------------------------------------------------------------
/src/app.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
5 | body {
6 | color: aliceblue;
7 | background-color: #09090b;
8 | }
9 |
10 |
11 | @layer utilities {
12 | /* Hide scrollbar for Chrome, Safari and Opera */
13 | .no-scrollbar::-webkit-scrollbar {
14 | display: none;
15 | }
16 | /* Hide scrollbar for IE, Edge and Firefox */
17 | .no-scrollbar {
18 | -ms-overflow-style: none; /* IE and Edge */
19 | scrollbar-width: none; /* Firefox */
20 | }
21 | }
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/components/socials.svelte:
--------------------------------------------------------------------------------
1 |
4 |
5 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the official bun image as the base image
2 | FROM oven/bun:1 as base
3 |
4 | # Set the working directory
5 | WORKDIR /app
6 |
7 | # Copy the package.json, bun.lockb, and other necessary files
8 | COPY package.json bun.lockb ./
9 | COPY .env .env
10 |
11 | # Copy the rest of the application code
12 | COPY . .
13 |
14 | # Install dependencies using bun
15 | RUN bun install
16 |
17 | # Build the SvelteKit app
18 | RUN bun run build
19 |
20 | # Expose the port the app runs on
21 | EXPOSE 5173
22 |
23 | # Define the command to run the app
24 | CMD ["bun", "run", "dev"]
25 |
--------------------------------------------------------------------------------
/src/models/community.model.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose';
2 |
3 |
4 | const CommunityModel = new mongoose.Schema(
5 | {
6 | name: {type: String, required: true},
7 | link: {type: String, required: true, unique: true},
8 | description: {type: String},
9 | owner: { type: String, default: ''},
10 | tags: [
11 | {type: String}
12 | ],
13 | type: { type: String }
14 | },
15 | { timestamps: true}
16 | );
17 |
18 | export type Community = mongoose.InferSchemaType;
19 | export const Community = mongoose.model('Community', CommunityModel);
--------------------------------------------------------------------------------
/src/lib/components/ui/label/label.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/src/components/signInButton.svelte:
--------------------------------------------------------------------------------
1 |
5 |
6 | {#if $page.data.session}
7 |
8 | {#if $page.data.session.user?.image}
9 |
10 |
11 | {/if}
12 |
signOut()}>Sign Out
13 |
14 |
15 | {:else}
16 | signIn('github')}>Sign In
17 | {/if}
18 |
--------------------------------------------------------------------------------
/src/routes/api/create-community/+server.ts:
--------------------------------------------------------------------------------
1 | import { json } from '@sveltejs/kit';
2 | import { Community } from '../../../models/community.model';
3 |
4 | export async function POST({ request, }) {
5 | const body = await request.json()
6 | body.link = body.link.toString().toLowerCase()
7 | // console.log("The body: ",body)
8 | const newCommunity = new Community({...body})
9 |
10 | try {
11 | await newCommunity.save();
12 | return json({ status: 200, body: "Successfully created community"});
13 | } catch (error) {
14 | console.error(error);
15 | return json({ status: 500, body: "Error creating document"});
16 | }
17 | }
--------------------------------------------------------------------------------
/src/lib/db/db.ts:
--------------------------------------------------------------------------------
1 | import mongoose, { Mongoose } from 'mongoose';
2 | import { SECRET_MONGO_URI } from '$env/static/private';
3 |
4 | interface Connection {
5 | isConnected?: number;
6 | }
7 |
8 | const connection: Connection = {};
9 |
10 | const dbConnect: () => Promise = async () => {
11 | if (connection.isConnected) {
12 | return;
13 | }
14 | if (!SECRET_MONGO_URI) {
15 | throw new Error('Please define the SECRET_MONGO_URI environment variable inside .env');
16 | }
17 |
18 | const db: Mongoose = await mongoose.connect(SECRET_MONGO_URI);
19 |
20 | connection.isConnected = db.connections[0].readyState;
21 | };
22 |
23 | export { dbConnect };
--------------------------------------------------------------------------------
/src/lib/components/ui/dialog/dialog-overlay.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | /** @type { import("eslint").Linter.Config } */
2 | module.exports = {
3 | root: true,
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:@typescript-eslint/recommended',
7 | 'plugin:svelte/recommended',
8 | 'prettier'
9 | ],
10 | parser: '@typescript-eslint/parser',
11 | plugins: ['@typescript-eslint'],
12 | parserOptions: {
13 | sourceType: 'module',
14 | ecmaVersion: 2020,
15 | extraFileExtensions: ['.svelte']
16 | },
17 | env: {
18 | browser: true,
19 | es2017: true,
20 | node: true
21 | },
22 | overrides: [
23 | {
24 | files: ['*.svelte'],
25 | parser: 'svelte-eslint-parser',
26 | parserOptions: {
27 | parser: '@typescript-eslint/parser'
28 | }
29 | }
30 | ]
31 | };
32 |
--------------------------------------------------------------------------------
/src/lib/components/ui/button/button.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | import adapter from '@sveltejs/adapter-auto';
2 | // import adapter from "svelte-adapter-bun";
3 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
4 |
5 | /** @type {import('@sveltejs/kit').Config} */
6 | const config = {
7 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors
8 | // for more information about preprocessors
9 | preprocess: vitePreprocess(),
10 |
11 | kit: {
12 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
13 | // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
14 | // See https://kit.svelte.dev/docs/adapters for more information about adapters.
15 | adapter: adapter()
16 | }
17 | };
18 |
19 | export default config;
20 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./.svelte-kit/tsconfig.json",
3 | "compilerOptions": {
4 | "allowJs": true,
5 | "checkJs": true,
6 | "esModuleInterop": true,
7 | "forceConsistentCasingInFileNames": true,
8 | "resolveJsonModule": true,
9 | "skipLibCheck": true,
10 | "sourceMap": true,
11 | "strict": true,
12 | "moduleResolution": "bundler",
13 | "allowImportingTsExtensions": true,
14 | "noImplicitAny": false
15 | }
16 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
17 | // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
18 | //
19 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
20 | // from the referenced tsconfig.json - TypeScript does not merge them in
21 | }
22 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/index.ts:
--------------------------------------------------------------------------------
1 | import { Select as SelectPrimitive } from "bits-ui";
2 |
3 | import Label from "./select-label.svelte";
4 | import Item from "./select-item.svelte";
5 | import Content from "./select-content.svelte";
6 | import Trigger from "./select-trigger.svelte";
7 | import Separator from "./select-separator.svelte";
8 |
9 | const Root = SelectPrimitive.Root;
10 | const Group = SelectPrimitive.Group;
11 | const Input = SelectPrimitive.Input;
12 | const Value = SelectPrimitive.Value;
13 |
14 | export {
15 | Root,
16 | Group,
17 | Input,
18 | Label,
19 | Item,
20 | Value,
21 | Content,
22 | Trigger,
23 | Separator,
24 | //
25 | Root as Select,
26 | Group as SelectGroup,
27 | Input as SelectInput,
28 | Label as SelectLabel,
29 | Item as SelectItem,
30 | Value as SelectValue,
31 | Content as SelectContent,
32 | Trigger as SelectTrigger,
33 | Separator as SelectSeparator,
34 | };
35 |
--------------------------------------------------------------------------------
/src/lib/components/ui/input/index.ts:
--------------------------------------------------------------------------------
1 | import Root from "./input.svelte";
2 |
3 | export type FormInputEvent = T & {
4 | currentTarget: EventTarget & HTMLInputElement;
5 | };
6 | export type InputEvents = {
7 | blur: FormInputEvent;
8 | change: FormInputEvent;
9 | click: FormInputEvent;
10 | focus: FormInputEvent;
11 | focusin: FormInputEvent;
12 | focusout: FormInputEvent;
13 | keydown: FormInputEvent;
14 | keypress: FormInputEvent;
15 | keyup: FormInputEvent;
16 | mouseover: FormInputEvent;
17 | mouseenter: FormInputEvent;
18 | mouseleave: FormInputEvent;
19 | paste: FormInputEvent;
20 | input: FormInputEvent;
21 | wheel: FormInputEvent;
22 | };
23 |
24 | export {
25 | Root,
26 | //
27 | Root as Input,
28 | };
29 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-trigger.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 | span]:line-clamp-1",
16 | className
17 | )}
18 | {...$$restProps}
19 | let:builder
20 | on:click
21 | on:keydown
22 | >
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/hooks.server.ts:
--------------------------------------------------------------------------------
1 | import { type Handle } from "@sveltejs/kit";
2 | import { dbConnect } from '$lib/db/db';
3 | import { SvelteKitAuth } from '@auth/sveltekit';
4 | import GitHub from "@auth/sveltekit/providers/github";
5 |
6 |
7 | import { GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET } from '$env/static/private';
8 |
9 | // Connect DB
10 | export const handle: Handle = async ({ event, resolve }) => {
11 |
12 | try {
13 | await dbConnect();
14 | console.log("DB connected");
15 | } catch (error) {
16 | console.error("DB connection error:", error);
17 | }
18 |
19 | const githubProvider = GitHub({
20 | clientId: GITHUB_CLIENT_ID,
21 | clientSecret: GITHUB_CLIENT_SECRET
22 | });
23 |
24 |
25 | const authConfig = {
26 | providers: [githubProvider],
27 | trustHost: true,
28 | secret: "true"
29 | };
30 |
31 | // Initialize authentication middleware
32 | const auth = SvelteKitAuth(authConfig);
33 |
34 | return auth.handle({ event, resolve });
35 | };
36 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dialog/index.ts:
--------------------------------------------------------------------------------
1 | import { Dialog as DialogPrimitive } from "bits-ui";
2 |
3 | import Title from "./dialog-title.svelte";
4 | import Portal from "./dialog-portal.svelte";
5 | import Footer from "./dialog-footer.svelte";
6 | import Header from "./dialog-header.svelte";
7 | import Overlay from "./dialog-overlay.svelte";
8 | import Content from "./dialog-content.svelte";
9 | import Description from "./dialog-description.svelte";
10 |
11 | const Root = DialogPrimitive.Root;
12 | const Trigger = DialogPrimitive.Trigger;
13 | const Close = DialogPrimitive.Close;
14 |
15 | export {
16 | Root,
17 | Title,
18 | Portal,
19 | Footer,
20 | Header,
21 | Trigger,
22 | Overlay,
23 | Content,
24 | Description,
25 | Close,
26 | //
27 | Root as Dialog,
28 | Title as DialogTitle,
29 | Portal as DialogPortal,
30 | Footer as DialogFooter,
31 | Header as DialogHeader,
32 | Trigger as DialogTrigger,
33 | Overlay as DialogOverlay,
34 | Content as DialogContent,
35 | Description as DialogDescription,
36 | Close as DialogClose,
37 | };
38 |
--------------------------------------------------------------------------------
/src/lib/constants.ts:
--------------------------------------------------------------------------------
1 | export const TAGS = [
2 | 'Spiritual',
3 | 'Tech',
4 | 'News',
5 | 'Coding',
6 | 'Books',
7 | 'Product',
8 | 'Startup',
9 | 'Company',
10 | 'School',
11 | 'Food',
12 | 'Pets',
13 | 'Music',
14 | 'Crafts',
15 | 'Travel',
16 | 'Science',
17 | 'Fitness',
18 | 'NSFW',
19 | 'Education',
20 | 'Photography',
21 | 'Humor',
22 | 'Memes',
23 | 'Hardware',
24 | 'Politics',
25 | 'Nature',
26 | 'Aesthetics',
27 | 'Wallpapers',
28 | 'Esoteric',
29 | 'Literature',
30 | 'Quotes',
31 | 'Poems',
32 | 'Business',
33 | 'Crypto',
34 | 'Dating',
35 | 'Charity',
36 | 'NGO',
37 | 'Club',
38 | 'FOSS',
39 | 'Dumps',
40 | 'Gaming',
41 | 'Podcast',
42 | 'Resources',
43 | 'Language',
44 | 'Governmental',
45 | 'e-Commerce',
46 | 'Cybersecurity',
47 | 'Hacking',
48 | 'Competitive Programming',
49 | 'Bible Study',
50 | 'Philosphy',
51 | 'Thoughts',
52 | 'Opportunities',
53 | 'Jobs',
54 | 'AI / ML',
55 | 'Film / TV',
56 | 'Fashion / Beauty',
57 | 'Art / Design',
58 | 'Games / Apps',
59 | 'Unsorted',
60 | 'untagged',
61 | 'other'
62 | ];
63 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Dagmawi Babi
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 |
--------------------------------------------------------------------------------
/src/components/header.svelte:
--------------------------------------------------------------------------------
1 |
20 |
21 |
22 |
25 | #{allCommunities.length} Communities Added!
26 |
27 |
28 |
31 | Discover the Best Telegram Communities
32 |
33 |
34 |
35 |
Here are some of the most incredible channels and groups submitted by the public.
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-content.svelte:
--------------------------------------------------------------------------------
1 |
22 |
23 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
18 |
19 |
20 |
22 |
23 |
24 |
26 |
27 |
28 |
29 | %sveltekit.head%
30 |
31 |
32 |
33 | %sveltekit.body%
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/lib/components/ui/input/input.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
42 |
--------------------------------------------------------------------------------
/src/lib/components/ui/select/select-item.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | {label || value}
39 |
40 |
41 |
--------------------------------------------------------------------------------
/src/lib/components/ui/dialog/dialog-content.svelte:
--------------------------------------------------------------------------------
1 |
16 |
17 |
18 |
19 |
28 |
29 |
32 |
33 | Close
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tggallery",
3 | "version": "0.0.1",
4 | "private": true,
5 | "scripts": {
6 | "dev": "vite dev",
7 | "build": "vite build",
8 | "preview": "vite preview",
9 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
11 | "lint": "prettier --check . && eslint .",
12 | "format": "prettier --write ."
13 | },
14 | "devDependencies": {
15 | "@sveltejs/adapter-auto": "^3.0.0",
16 | "@sveltejs/kit": "^2.0.0",
17 | "@sveltejs/vite-plugin-svelte": "^3.0.0",
18 | "@types/eslint": "^8.56.0",
19 | "@typescript-eslint/eslint-plugin": "^7.0.0",
20 | "@typescript-eslint/parser": "^7.0.0",
21 | "autoprefixer": "^10.4.19",
22 | "eslint": "^8.56.0",
23 | "eslint-config-prettier": "^9.1.0",
24 | "eslint-plugin-svelte": "^2.35.1",
25 | "postcss": "^8.4.38",
26 | "prettier": "^3.1.1",
27 | "prettier-plugin-svelte": "^3.1.2",
28 | "svelte": "^4.2.7",
29 | "svelte-adapter-bun": "^0.5.2",
30 | "svelte-check": "^3.6.0",
31 | "tailwindcss": "^3.4.3",
32 | "tslib": "^2.4.1",
33 | "typescript": "^5.0.0",
34 | "vite": "^5.0.3"
35 | },
36 | "type": "module",
37 | "trustedDependencies": [
38 | "svelte-preprocess"
39 | ],
40 | "dependencies": {
41 | "@auth/sveltekit": "^1.0.1",
42 | "@loglib/tracker": "^0.8.0",
43 | "axios": "^1.6.8",
44 | "bits-ui": "^0.21.7",
45 | "clsx": "^2.1.1",
46 | "lucide-svelte": "^0.378.0",
47 | "mongoose": "^8.3.4",
48 | "tailwind-merge": "^2.3.0",
49 | "tailwind-variants": "^0.2.1"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/lib/components/ui/button/index.ts:
--------------------------------------------------------------------------------
1 | import { type VariantProps, tv } from "tailwind-variants";
2 | import type { Button as ButtonPrimitive } from "bits-ui";
3 | import Root from "./button.svelte";
4 |
5 | const buttonVariants = tv({
6 | base: "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
7 | variants: {
8 | variant: {
9 | default: "bg-primary text-primary-foreground hover:bg-primary/90",
10 | destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
11 | outline:
12 | "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
13 | secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
14 | ghost: "hover:bg-accent hover:text-accent-foreground",
15 | link: "text-primary underline-offset-4 hover:underline",
16 | },
17 | size: {
18 | default: "h-10 px-4 py-2",
19 | sm: "h-9 rounded-md px-3",
20 | lg: "h-11 rounded-md px-8",
21 | icon: "h-10 w-10",
22 | },
23 | },
24 | defaultVariants: {
25 | variant: "default",
26 | size: "default",
27 | },
28 | });
29 |
30 | type Variant = VariantProps["variant"];
31 | type Size = VariantProps["size"];
32 |
33 | type Props = ButtonPrimitive.Props & {
34 | variant?: Variant;
35 | size?: Size;
36 | };
37 |
38 | type Events = ButtonPrimitive.Events;
39 |
40 | export {
41 | Root,
42 | type Props,
43 | type Events,
44 | //
45 | Root as Button,
46 | type Props as ButtonProps,
47 | type Events as ButtonEvents,
48 | buttonVariants,
49 | };
50 |
--------------------------------------------------------------------------------
/src/lib/utils.ts:
--------------------------------------------------------------------------------
1 | import { type ClassValue, clsx } from "clsx";
2 | import { twMerge } from "tailwind-merge";
3 | import { cubicOut } from "svelte/easing";
4 | import type { TransitionConfig } from "svelte/transition";
5 |
6 | export function cn(...inputs: ClassValue[]) {
7 | return twMerge(clsx(inputs));
8 | }
9 |
10 | type FlyAndScaleParams = {
11 | y?: number;
12 | x?: number;
13 | start?: number;
14 | duration?: number;
15 | };
16 |
17 | export const flyAndScale = (
18 | node: Element,
19 | params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
20 | ): TransitionConfig => {
21 | const style = getComputedStyle(node);
22 | const transform = style.transform === "none" ? "" : style.transform;
23 |
24 | const scaleConversion = (
25 | valueA: number,
26 | scaleA: [number, number],
27 | scaleB: [number, number]
28 | ) => {
29 | const [minA, maxA] = scaleA;
30 | const [minB, maxB] = scaleB;
31 |
32 | const percentage = (valueA - minA) / (maxA - minA);
33 | const valueB = percentage * (maxB - minB) + minB;
34 |
35 | return valueB;
36 | };
37 |
38 | const styleToString = (
39 | style: Record
40 | ): string => {
41 | return Object.keys(style).reduce((str, key) => {
42 | if (style[key] === undefined) return str;
43 | return str + `${key}:${style[key]};`;
44 | }, "");
45 | };
46 |
47 | return {
48 | duration: params.duration ?? 200,
49 | delay: 0,
50 | css: (t) => {
51 | const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
52 | const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
53 | const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
54 |
55 | return styleToString({
56 | transform: `${transform} translate3d(${x}px, ${y}px, 0) scale(${scale})`,
57 | opacity: t
58 | });
59 | },
60 | easing: cubicOut
61 | };
62 | };
--------------------------------------------------------------------------------
/src/components/footer.svelte:
--------------------------------------------------------------------------------
1 |
33 |
34 |
35 | This gallery has been visited {visitorCount} times and was made with love by Dagmawi Babi .
36 |
37 |
38 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | import { fontFamily } from "tailwindcss/defaultTheme";
2 |
3 | /** @type {import('tailwindcss').Config} */
4 | const config = {
5 | darkMode: ["class"],
6 | content: ["./src/**/*.{html,js,svelte,ts}"],
7 | safelist: ["dark"],
8 | theme: {
9 | container: {
10 | center: true,
11 | padding: "2rem",
12 | screens: {
13 | "2xl": "1400px"
14 | }
15 | },
16 | extend: {
17 | colors: {
18 | border: "hsl(var(--border) / )",
19 | input: "hsl(var(--input) / )",
20 | ring: "hsl(var(--ring) / )",
21 | background: "hsl(var(--background) / )",
22 | foreground: "hsl(var(--foreground) / )",
23 | primary: {
24 | DEFAULT: "hsl(var(--primary) / )",
25 | foreground: "hsl(var(--primary-foreground) / )"
26 | },
27 | secondary: {
28 | DEFAULT: "hsl(var(--secondary) / )",
29 | foreground: "hsl(var(--secondary-foreground) / )"
30 | },
31 | destructive: {
32 | DEFAULT: "hsl(var(--destructive) / )",
33 | foreground: "hsl(var(--destructive-foreground) / )"
34 | },
35 | muted: {
36 | DEFAULT: "hsl(var(--muted) / )",
37 | foreground: "hsl(var(--muted-foreground) / )"
38 | },
39 | accent: {
40 | DEFAULT: "hsl(var(--accent) / )",
41 | foreground: "hsl(var(--accent-foreground) / )"
42 | },
43 | popover: {
44 | DEFAULT: "hsl(var(--popover) / )",
45 | foreground: "hsl(var(--popover-foreground) / )"
46 | },
47 | card: {
48 | DEFAULT: "hsl(var(--card) / )",
49 | foreground: "hsl(var(--card-foreground) / )"
50 | }
51 | },
52 | borderRadius: {
53 | lg: "var(--radius)",
54 | md: "calc(var(--radius) - 2px)",
55 | sm: "calc(var(--radius) - 4px)"
56 | },
57 | fontFamily: {
58 | sans: [...fontFamily.sans]
59 | }
60 | }
61 | },
62 | };
63 |
64 | export default config;
65 |
--------------------------------------------------------------------------------
/src/components/eachCommunity.svelte:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
13 |
14 |
15 |
16 | {#if community.type == "channel"}
17 |
{community.name}
18 | {:else}
19 |
{community.name}
20 | {/if}
21 |
22 |
23 | {#if community.type == "channel"}
24 |
25 |
26 |
27 | {:else}
28 |
29 |
30 |
31 |
32 | {/if}
33 |
34 |
35 |
36 |
{community.description}
37 |
38 |
39 |
52 |
53 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ✨ Telegram Community Gallery ✨
2 | 
3 |
4 | **[Telegram Community Gallery](https://telegram.dagmawi.dev)** is a platform where users can discover and submit their favorite Telegram channels and groups, creating a vibrant space for community exploration. Whether you're a seasoned Telegram user or just diving into the world of Telegram communities, this platform is designed with you in mind. 😊
5 |
6 | ### Features 🎉
7 | - **Discover Communities**: Explore a wide range of Telegram channels and groups, curated by fellow users.
8 | - **Submit Your Community**: Share your favorite Telegram communities with the world by submitting them to the gallery.
9 | - **Tagging and Filtering**: Easily find communities that match your interests with powerful tagging and filtering options.
10 | - **Crowdsourced and Open Source**: The platform thrives on community contributions and is completely open source, ensuring transparency and inclusivity.
11 |
12 | ### Tech Stack 💻
13 | Telegram Community Gallery is built using the following technologies:
14 | - **Frontend**: [SvelteKit](https://kit.svelte.dev/) and [Tailwind](https://tailwindcss.com/)
15 | - **Icons**: [Lucide Icons](https://lucide.dev/)
16 | - **Component Library**: [Shadcn-Svelte](https://www.shadcn-svelte.com/)
17 | - **Backend**: [HonoJS](https://hono.dev/)
18 | - **Database**: [MongoDB](https://www.mongodb.com/)
19 |
20 | ### Getting Started 🚀
21 | To get started with Telegram Community Gallery, simply visit our [Website](https://telegram.dagmawi.dev) and start exploring! If you'd like to contribute to the project or report any issues, check out our [GitHub repository.](https://github.com/dagmawibabi/TelegramCommunityGallery)
22 |
23 | ### How to Contribute 🤝
24 | We welcome contributions from the community! Follow these steps to contribute:
25 | 1. **Fork the Repository**: Fork the Telegram Community Gallery repository to your GitHub account.
26 | 2. **Make Changes**: Create a new branch, make your changes, and commit them to your branch.
27 | 3. **Create a Pull Request**: Once your changes are ready, create a detailed pull request (PR) explaining the changes you've made.
28 | 4. **Review and Iterate**: Collaborate with the maintainers to review and iterate on your changes until they are ready to be merged.
29 | 5. **That's it!**: Can't wait to see the wonders you'll be doing.
30 |
31 | For more detailed guidelines on contributing, please refer to our contribution guidelines.
32 |
33 | ### Feedback and Support 💌
34 | Have any questions, suggestions, or need support? Feel free to reach out to us in our discussions tab or [open an issue](https://github.com/dagmawibabi/TelegramCommunityGallery/issues) on GitHub. Your feedback helps us make Telegram Community Gallery even better!
35 |
36 | ### License 📝
37 | Telegram Community Gallery is licensed under the [MIT License](https://github.com/dagmawibabi/TelegramCommunityGallery?tab=MIT-1-ov-file).
38 |
39 | ### Thank You and Enjoy! 🥰
--------------------------------------------------------------------------------
/src/components/radioComponent.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
23 |
{legend}
25 |
26 | {#each options as { value, label }}
27 |
33 |
{label}
34 | {/each}
35 |
36 |
37 |
151 |
--------------------------------------------------------------------------------
/src/routes/[username]/+page.svelte:
--------------------------------------------------------------------------------
1 |
35 |
36 |
37 | {currentCommunity.name}
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 |
90 |
91 |
92 | Telegram Community Gallery
93 |
94 |
95 |
96 |
99 |
102 |
103 |
239 |
240 |
--------------------------------------------------------------------------------
/src/components/addCommunity.svelte:
--------------------------------------------------------------------------------
1 |
121 |
122 |
123 |
124 |
125 |
126 |
129 |
130 |
135 | Submit Your Channel / Group
136 |
137 |
138 |
139 |
140 |
143 |
144 |
145 | Add Channel / Group
146 |
147 | Add your community and click save when you're done!
148 |
149 |
150 |
151 |
152 |
153 |
Community Name
154 |
162 |
Community Link
163 |
164 |
172 |
173 |
174 | {#each errors as error}
175 | {error}
176 | {/each}
177 |
178 |
179 |
180 | Community Description
181 |
182 |
191 |
192 | Community Owner [Optional]
193 |
194 |
201 |
Community Type
202 |
205 |
206 |
207 |
Community Tags
208 |
209 | {#each TAGS as tag}
210 |
211 |
212 |
213 | {#if type == 'channel'}
214 | {#if !selectedTags.includes(tag)}
215 | addRemoveTag(tag)}
217 | class="rounded-full border border-zinc-700 w-fit pb-1 px-3 line-clamp-1 whitespace-nowrap hover:bg-emerald-400 hover:text-black overflow-scroll no-scrollbar"
218 | >
219 | {tag}
220 |
221 | {:else}
222 | addRemoveTag(tag)}
224 | class="rounded-full border border-zinc-700 w-fit pb-1 px-3 line-clamp-1 whitespace-nowrap bg-emerald-400 text-black overflow-scroll no-scrollbar"
225 | >
226 | {tag}
227 |
228 | {/if}
229 | {:else if !selectedTags.includes(tag)}
230 | addRemoveTag(tag)}
232 | class="rounded-full border border-zinc-700 w-fit pb-1 px-3 line-clamp-1 whitespace-nowrap hover:bg-cyan-400 hover:text-black overflow-scroll no-scrollbar"
233 | >
234 | {tag}
235 |
236 | {:else}
237 | addRemoveTag(tag)}
239 | class="rounded-full border border-zinc-700 w-fit pb-1 px-3 line-clamp-1 whitespace-nowrap bg-cyan-400 text-black overflow-scroll no-scrollbar"
240 | >
241 | {tag}
242 |
243 | {/if}
244 |
245 | {/each}
246 |
247 |
248 |
253 | Save Changes
254 |
255 |
256 |
257 |
258 |
259 |
--------------------------------------------------------------------------------