feat: initialize Vue 3 project with Tailwind CSS and Vite

- Add package.json with project metadata and dependencies
- Create favicon.ico and ritsu.png assets
- Implement main App.vue component with site structure
- Add HeroSection, RitsuSection, SiteHeader, and SupportSection components
- Set up theme toggle functionality in SiteHeader
- Create main entry point in main.ts
- Add Tailwind CSS styles in style.css
- Configure TypeScript with tsconfig files
- Set up Vite configuration for Vue and Tailwind CSS
This commit is contained in:
Alexander
2026-02-28 14:51:48 +03:00
commit ed400c8b1f
18 changed files with 2350 additions and 0 deletions

28
.gitignore vendored Normal file
View File

@@ -0,0 +1,28 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# Ignore all files in the .vscode folder except extensions.json
.vscode/*
!.vscode/extensions.json

36
README.md Normal file
View File

@@ -0,0 +1,36 @@
# nevedomhren
Simple Vue 3 + Tailwind CSS site for the Telegram channel *[@nevedomhren](https://t.me/nevedomhren)*.
## Description
A small landing page reminding that sometimes just a subscription or a few words can make someone feel less alone. It uses Vite, Vue 3 and Tailwind CSS.
## Development
1. Clone the repository.
2. Run `npm install` to install dependencies.
3. Run `npm run dev` to start the development server.
## Building and Serving
Build the static files with:
```bash
npm run build
```
To serve the built site on the internet you can use the `serve` package:
```bash
npm install -g serve
serve -s dist
```
This will start a local web server serving the contents of the `dist` folder. Forward ports or deploy the folder to any static host to make it available on the internet.
## License
The project is licensed under the MIT License — see the license file:
[LICENSE](https://git.kernils.ru/POTI/nevedom/src/branch/master/LICENSE)

13
index.html Normal file
View File

@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" type="image/x-icon">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Nevedom Hren</title>
</head>
<body class="dark:bg-gray-950 dark:text-white">
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

2022
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
package.json Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "nevedom",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vue-tsc -b && vite build",
"preview": "vite preview"
},
"dependencies": {
"@tailwindcss/vite": "^4.2.1",
"tailwindcss": "^4.2.1",
"vue": "^3.5.25"
},
"devDependencies": {
"@types/node": "^24.10.1",
"@vitejs/plugin-vue": "^6.0.2",
"@vue/tsconfig": "^0.8.1",
"typescript": "~5.9.3",
"vite": "^7.3.1",
"vue-tsc": "^3.1.5"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

BIN
public/ritsu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

27
src/App.vue Normal file
View File

@@ -0,0 +1,27 @@
<template>
<div :class="[
'min-h-screen transition-colors duration-300',
'bg-gray-100 text-black',
'dark:bg-gray-900 dark:text-gray-200'
]">
<SiteHeader />
<HeroSection />
<RitsuSection />
<SupportSection />
</div>
</template>
<script setup lang="ts">
import { onMounted } from 'vue'
import SiteHeader from './components/SiteHeader.vue'
import HeroSection from './components/HeroSection.vue'
import RitsuSection from './components/RitsuSection.vue'
import SupportSection from './components/SupportSection.vue'
onMounted(() => {
if (window.matchMedia("(prefers-color-scheme: dark)").matches)
document.documentElement.classList.add('dark');
});
</script>

View File

@@ -0,0 +1,23 @@
<template>
<section class="container mx-auto px-6 py-20 text-center">
<h2 class="text-3xl md:text-4xl font-bold mb-6">
Иногда человеку нужно совсем немного
</h2>
<p class="text-lg max-w-2xl mx-auto mb-8 opacity-80">
Просто знать, что он не один.
Даже одна подписка может быть теплее слов.
</p>
<a
href="https://t.me/nevedomhren"
target="_blank"
class="inline-block bg-green-500 hover:bg-green-600 text-white px-8 py-3 rounded-xl shadow-md hover:scale-105 transition duration-300"
>
Поддержать в Telegram
</a>
</section>
</template>
<script setup lang="ts">
</script>

View File

@@ -0,0 +1,37 @@
<template>
<section class="container max-w-fit mx-auto px-6 py-16">
<div class="flex flex-col md:flex-row items-center gap-10">
<img
src="/ritsu.png"
alt="Ritsu Tainaka"
class="w-64 md:w-80 rounded-2xl shadow-lg hover:scale-105 transition duration-300"
/>
<div class="max-w-xl">
<h3 class="text-2xl font-semibold mb-4">
Немного о Рицу и том самом тортике
</h3>
<p class="mb-4 opacity-80 leading-relaxed">
Рицу Тайнака энергичная и шумная барабанщица из аниме «K-On!».<br>
Она всегда кажется лёгкой, живой и беззаботной.
</p>
<p class="mb-4 opacity-80 leading-relaxed">
Но даже у таких людей бывают моменты, которые выглядят мелочью
как история когда <b>nevedom</b> пил чай (без тортика) с Вайбославом в Фогеле...
Снаружи это шутка. Внутри ощущение, что Фогель больше не с нами.
</p>
<p class="opacity-80 leading-relaxed">
Иногда достаточно малого, чтобы стало легче.
Даже простого присутствия.
</p>
</div>
</div>
</section>
</template>
<script setup lang="ts">
</script>

View File

@@ -0,0 +1,44 @@
<template>
<header class="w-full flex pt-6">
<div
:class="[
'flex items-center justify-between',
'container rounded-full',
'px-6 py-4 mx-auto',
'shadow-md transition-all duration-300',
'bg-green-500 dark:bg-green-600'
]"
>
<h1 class="text-white font-semibold text-lg tracking-wide">
nevedomhren
</h1>
<button
@click="toggleTheme"
class="bg-white/20 hover:bg-white/30 text-white px-4 py-1 rounded-full text-sm transition duration-300"
>
{{ isDark ? 'Светлая тема' : 'Тёмная тема' }}
</button>
</div>
</header>
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref } from 'vue';
const isDark = ref(false);
function toggleTheme() {
isDark.value
? document.documentElement.classList.remove('dark')
: document.documentElement.classList.add('dark');
isDark.value = !isDark.value;
}
onMounted(() => {
nextTick(() => {
isDark.value = document.documentElement.classList.contains('dark');
});
});
</script>

View File

@@ -0,0 +1,27 @@
<template>
<section class="container mx-auto px-6 py-20 text-center">
<h3 class="text-2xl md:text-3xl font-semibold mb-6">
За каналом стоит живой человек
</h3>
<p class="max-w-2xl mx-auto mb-8 opacity-80">
Этот Telegram-канал не про цифры и не про охваты.<br>
Иногда подписка это просто знак того, что кто-то рядом.
</p>
<a
href="https://t.me/nevedomhren"
target="_blank"
class="inline-block bg-green-500 hover:bg-green-600 text-white px-10 py-4 rounded-xl shadow-lg hover:scale-105 transition duration-300 text-lg"
>
Перейти и поддержать
</a>
<p class="mt-4 text-sm opacity-60">
Это бесплатно. Но может значить больше, чем кажется.
</p>
</section>
</template>
<script setup lang="ts">
</script>

5
src/main.ts Normal file
View File

@@ -0,0 +1,5 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
createApp(App).mount('#app')

7
src/style.css Normal file
View File

@@ -0,0 +1,7 @@
@import "tailwindcss";
@media (prefers-color-scheme: dark) {
body { background: black; color: white; }
}
@custom-variant dark (&:where(.dark, .dark *));

16
tsconfig.app.json Normal file
View File

@@ -0,0 +1,16 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"types": ["vite/client"],
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}

7
tsconfig.json Normal file
View File

@@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

26
tsconfig.node.json Normal file
View File

@@ -0,0 +1,26 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"types": ["node"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

8
vite.config.ts Normal file
View File

@@ -0,0 +1,8 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'
// https://vite.dev/config/
export default defineConfig({
plugins: [vue(), tailwindcss()],
})