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