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:
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal 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
36
README.md
Normal 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
13
index.html
Normal 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
2022
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
package.json
Normal file
24
package.json
Normal 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
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 KiB |
BIN
public/ritsu.png
Normal file
BIN
public/ritsu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
27
src/App.vue
Normal file
27
src/App.vue
Normal 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>
|
||||||
23
src/components/HeroSection.vue
Normal file
23
src/components/HeroSection.vue
Normal 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>
|
||||||
37
src/components/RitsuSection.vue
Normal file
37
src/components/RitsuSection.vue
Normal 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>
|
||||||
44
src/components/SiteHeader.vue
Normal file
44
src/components/SiteHeader.vue
Normal 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>
|
||||||
27
src/components/SupportSection.vue
Normal file
27
src/components/SupportSection.vue
Normal 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
5
src/main.ts
Normal 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
7
src/style.css
Normal 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
16
tsconfig.app.json
Normal 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
7
tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./tsconfig.app.json" },
|
||||||
|
{ "path": "./tsconfig.node.json" }
|
||||||
|
]
|
||||||
|
}
|
||||||
26
tsconfig.node.json
Normal file
26
tsconfig.node.json
Normal 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
8
vite.config.ts
Normal 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()],
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user