website-xp-phone 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.astro/content-assets.mjs +1 -0
- package/.astro/content-modules.mjs +1 -0
- package/.astro/content.d.ts +199 -0
- package/.astro/data-store.json +1 -0
- package/.astro/settings.json +8 -0
- package/.astro/types.d.ts +1 -0
- package/.devcontainer/devcontainer.json +23 -0
- package/.env.firebase.example +8 -0
- package/.firebaserc +5 -0
- package/.gitattributes +2 -0
- package/.github/copilot-instructions.md +131 -0
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/ci.yml +45 -0
- package/.github/workflows/deploy-admin.yml +48 -0
- package/.github/workflows/static.yml +43 -0
- package/.gitmodules +5 -0
- package/FIREBASE_SETUP.md +69 -0
- package/README.md +63 -0
- package/SECURITY.md +11 -0
- package/admin/Admin.csproj +7 -0
- package/admin/Dockerfile +14 -0
- package/admin/Program.cs +8 -0
- package/deploy-admin-cloud-run.md +229 -0
- package/eslint.config.js +28 -0
- package/firebase.json +5 -0
- package/firestore.rules +29 -0
- package/index.html +52 -0
- package/package.json +48 -0
- package/pagerts_output.json +1 -0
- package/public/5.html +967 -0
- package/public/BAHNSCHRIFT.TTF +0 -0
- package/public/Beep.ogg +0 -0
- package/public/Clippy.png +0 -0
- package/public/Layered Network Security Model for Home Networks (slides).pdf +0 -0
- package/public/Layered Network Security Model for Home Networks.pdf +0 -0
- package/public/TODO.pdf +0 -0
- package/public/WoW_Config.zip +3 -0
- package/public/addons/energy-swing.txt +1 -0
- package/public/addons/lego-yoda-death-readme.txt +11 -0
- package/public/addons/lego-yoda-death.mp3 +0 -0
- package/public/addons/mana-blast.txt +1 -0
- package/public/addons/rage-volley.txt +1 -0
- package/public/addons/rueg-cell.txt +1 -0
- package/public/addons/rueg-elvui-profile.txt +1 -0
- package/public/addons/rueg-grid2.txt +214 -0
- package/public/addons/rueg-plater-smol.txt +1 -0
- package/public/addons/rueg-plater.txt +1 -0
- package/public/addons/rueg-wa-druid.txt +1 -0
- package/public/addons/rueg-wa-priest.txt +1 -0
- package/public/addons/rueg-wa-rogue.txt +1 -0
- package/public/addons/rueg-wa-shaman.txt +1 -0
- package/public/addons/rueg-wa-warrior.txt +1 -0
- package/public/addons/spirit-smash.txt +1 -0
- package/public/avatar.jpg +0 -0
- package/public/avatar.png +0 -0
- package/public/crunchy_kick.ogg +0 -0
- package/public/documents/resume.html +312 -0
- package/public/favicon.ico +0 -0
- package/public/images/Ateric1.png +0 -0
- package/public/images/Ateric2.png +0 -0
- package/public/images/equal1.png +0 -0
- package/public/images/hyperawareofwhatacatis.png +0 -0
- package/public/images/kogg1.png +0 -0
- package/public/images/kogg2.png +0 -0
- package/public/images/rueg1.png +0 -0
- package/public/images/rueg2.png +0 -0
- package/public/incorrect_responses.txt +126 -0
- package/public/loading.css +51 -0
- package/public/resume.pdf +0 -0
- package/public/robots.txt +9 -0
- package/public/soundcloud.json +57 -0
- package/public/spinner.svg +12 -0
- package/public/tada.wav +0 -0
- package/public/yooh.mp3 +0 -0
- package/render.yaml +5 -0
- package/scripts/ensure-blog-worktree.mjs +24 -0
- package/scripts/generate-soundcloud-json.mjs +198 -0
- package/scripts/git-worktree-helper.mjs +122 -0
- package/scripts/hoist-dev-blog-local.mjs +149 -0
- package/scripts/music-schema.mjs +56 -0
- package/scripts/publish-soundcloud-json.mjs +32 -0
- package/scripts/sync-music-links-from-worktree.mjs +32 -0
- package/src/App.tsx +1500 -0
- package/src/addons.json +76 -0
- package/src/components/Addon.tsx +223 -0
- package/src/components/BlogContent.tsx +103 -0
- package/src/components/CopyToClipboardButton.tsx +21 -0
- package/src/components/MenuBar.tsx +151 -0
- package/src/components/MenuBarWithContext.tsx +6 -0
- package/src/components/Modal.tsx +17 -0
- package/src/components/MusicContent.tsx +309 -0
- package/src/components/NavBarController.tsx +55 -0
- package/src/components/NavBarControllerWrapper.tsx +13 -0
- package/src/components/Page.tsx +56 -0
- package/src/components/SitemapContent.tsx +125 -0
- package/src/contacts.json +32 -0
- package/src/env.d.ts +13 -0
- package/src/lib/assistantStateMachine.ts +80 -0
- package/src/lib/audioOverlap.ts +99 -0
- package/src/lib/keyboardInputUtils.ts +182 -0
- package/src/lib/musicSchema.ts +85 -0
- package/src/lib/naggingAssistantClient.ts +241 -0
- package/src/lib/resumeAnalytics.ts +163 -0
- package/src/main.tsx +35 -0
- package/src/pages.json +50 -0
- package/src/sections.json +243 -0
- package/src/src+addons.zip +3 -0
- package/src/styles/main.css +465 -0
- package/src/utils/blogSecurity.ts +87 -0
- package/src/utils/menuItems.ts +33 -0
- package/src/windowing/MinimizedSections.tsx +86 -0
- package/src/windowing/Section.tsx +586 -0
- package/src/windowing/context.tsx +13 -0
- package/src/windowing/hooks.ts +10 -0
- package/src/windowing/index.ts +7 -0
- package/src/windowing/provider.tsx +74 -0
- package/src/windowing/server.ts +3 -0
- package/src/windowing/types.ts +33 -0
- package/src/windowing/utils.ts +135 -0
- package/tests/generate-soundcloud-json.test.mjs +63 -0
- package/tests/music-schema.test.mjs +53 -0
- package/tsconfig.json +26 -0
- package/vite.config.ts +304 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# kine's website
|
|
2
|
+
|
|
3
|
+
This is the source code for my personal website. I built it as a landing page for myself, and as a point-of-interest for those that stumble upon it.
|
|
4
|
+
|
|
5
|
+
This code shows who I am, what I am building, and the things I care about in software.
|
|
6
|
+
|
|
7
|
+
The design is very human. The code is built with modern tooling so I can keep iterating quickly.
|
|
8
|
+
|
|
9
|
+
## Why this exists
|
|
10
|
+
|
|
11
|
+
This repo is where I experiment with:
|
|
12
|
+
|
|
13
|
+
- Personal storytelling through UI
|
|
14
|
+
- JSON-driven content that is easy to edit
|
|
15
|
+
- Small interactive features (windows, modals, media embeds)
|
|
16
|
+
- A workflow that is simple enough to maintain long-term
|
|
17
|
+
|
|
18
|
+
## Tech stack
|
|
19
|
+
|
|
20
|
+
- React + TypeScript
|
|
21
|
+
- ~~Astro~~
|
|
22
|
+
- Vite for development and builds
|
|
23
|
+
- xp.css for the nostalgia
|
|
24
|
+
|
|
25
|
+
## Local development
|
|
26
|
+
|
|
27
|
+
Start the dev server:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
npm run dev
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Build for production:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
npm run build
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Run linting:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
npm run lint
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Dependency audit:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
npm run check:audit
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Notes
|
|
52
|
+
|
|
53
|
+
Most content is managed through JSON, rendered into components in the browser.
|
|
54
|
+
|
|
55
|
+
This keeps content updates straightforward while still allowing rich UI behavior.
|
|
56
|
+
|
|
57
|
+
Some pages rely on raw github user content to serve the json so that a full website-rebuild is not necessary for updating content on those pages, such as blog.
|
|
58
|
+
|
|
59
|
+
## Contact
|
|
60
|
+
|
|
61
|
+
If you are here to learn more about me professionally, the website includes my resume and contact details.
|
|
62
|
+
|
|
63
|
+
Thanks for visiting.
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
This website is live updated from this repository through continuous deployment.
|
|
6
|
+
|
|
7
|
+
Please consult the version history, or any markdown files in the root of the project for support!
|
|
8
|
+
|
|
9
|
+
## Reporting a Vulnerability
|
|
10
|
+
|
|
11
|
+
Please report vulnerabilities directly through Github issues.
|
package/admin/Dockerfile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
|
2
|
+
WORKDIR /app
|
|
3
|
+
EXPOSE 8080
|
|
4
|
+
ENV ASPNETCORE_URLS=http://+:8080
|
|
5
|
+
|
|
6
|
+
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
|
7
|
+
WORKDIR /src
|
|
8
|
+
COPY . .
|
|
9
|
+
RUN dotnet publish -c Release -o /app/publish
|
|
10
|
+
|
|
11
|
+
FROM base AS final
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
COPY --from=build /app/publish .
|
|
14
|
+
ENTRYPOINT ["dotnet", "Admin.dll"]
|
package/admin/Program.cs
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
2
|
+
|
|
3
|
+
var app = builder.Build();
|
|
4
|
+
|
|
5
|
+
app.MapGet("/", () => Results.Text("nothing to see here", "text/plain"));
|
|
6
|
+
app.MapGet("/status", () => TypedResults.Ok(new { ok = true, service = "admin", timestamp = DateTimeOffset.UtcNow }));
|
|
7
|
+
|
|
8
|
+
app.Run();
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# ASP.NET Minimal API → Cloud Run via GitHub Actions
|
|
2
|
+
|
|
3
|
+
Deploy a single-file ASP.NET endpoint to Google Cloud Run, accessible at `admin.akinevz.com`. Everything triggered on `git push main`.
|
|
4
|
+
|
|
5
|
+
**Flow:** push → Actions → docker build → Artifact Registry → Cloud Run → Cloudflare DNS → `admin.akinevz.com`
|
|
6
|
+
|
|
7
|
+
Cloud Run free tier: 2 million requests/month, 360,000 GB-seconds. Sufficient for a personal site.
|
|
8
|
+
Nearest region to Hove, UK: **europe-west1** (Belgium).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Step 1 — GCP Setup
|
|
13
|
+
|
|
14
|
+
Firebase already lives in a GCP project. Enable two additional APIs in GCP Console:
|
|
15
|
+
|
|
16
|
+
- Artifact Registry API
|
|
17
|
+
- Cloud Run Admin API
|
|
18
|
+
|
|
19
|
+
Create a Service Account for GitHub Actions:
|
|
20
|
+
|
|
21
|
+
- Name: `github-actions-deploy`
|
|
22
|
+
- Roles: `roles/run.admin`, `roles/artifactregistry.writer`, `roles/iam.serviceAccountUser`
|
|
23
|
+
- Download JSON key → add to GitHub repo secrets as `GCP_SA_KEY`
|
|
24
|
+
- Also add secret `GCP_PROJECT_ID` = your GCP project ID
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Step 2 — Create Artifact Registry Repository
|
|
29
|
+
|
|
30
|
+
GCP Console → Artifact Registry → Create Repository:
|
|
31
|
+
|
|
32
|
+
- Name: `admin`
|
|
33
|
+
- Format: Docker
|
|
34
|
+
- Region: `europe-west1`
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Step 3 — ASP.NET Minimal API
|
|
39
|
+
|
|
40
|
+
Create folder `admin/` in the repo root.
|
|
41
|
+
|
|
42
|
+
**admin/Admin.csproj**
|
|
43
|
+
```xml
|
|
44
|
+
<Project Sdk="Microsoft.NET.Sdk.Web">
|
|
45
|
+
<PropertyGroup>
|
|
46
|
+
<TargetFramework>net9.0</TargetFramework>
|
|
47
|
+
</PropertyGroup>
|
|
48
|
+
</Project>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**admin/Program.cs**
|
|
52
|
+
```csharp
|
|
53
|
+
var app = WebApplication.Create(args);
|
|
54
|
+
|
|
55
|
+
app.MapGet("/", () => "nothing to see here");
|
|
56
|
+
app.MapGet("/status", () => Results.Ok(new { ok = true }));
|
|
57
|
+
|
|
58
|
+
app.Run();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**admin/Dockerfile**
|
|
62
|
+
```dockerfile
|
|
63
|
+
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
|
64
|
+
WORKDIR /app
|
|
65
|
+
EXPOSE 8080
|
|
66
|
+
ENV ASPNETCORE_URLS=http://+:8080
|
|
67
|
+
|
|
68
|
+
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
|
69
|
+
WORKDIR /src
|
|
70
|
+
COPY . .
|
|
71
|
+
RUN dotnet publish -c Release -o /app/publish
|
|
72
|
+
|
|
73
|
+
FROM base AS final
|
|
74
|
+
WORKDIR /app
|
|
75
|
+
COPY --from=build /app/publish .
|
|
76
|
+
ENTRYPOINT ["dotnet", "Admin.dll"]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Step 4 — GitHub Actions Workflow
|
|
82
|
+
|
|
83
|
+
Create `.github/workflows/deploy-admin.yml`:
|
|
84
|
+
|
|
85
|
+
```yaml
|
|
86
|
+
name: Deploy Admin to Cloud Run
|
|
87
|
+
|
|
88
|
+
on:
|
|
89
|
+
push:
|
|
90
|
+
branches: [main]
|
|
91
|
+
paths: ['admin/**', '.github/workflows/deploy-admin.yml']
|
|
92
|
+
|
|
93
|
+
env:
|
|
94
|
+
REGION: europe-west1
|
|
95
|
+
SERVICE: admin
|
|
96
|
+
IMAGE: europe-west1-docker.pkg.dev/${{ secrets.GCP_PROJECT_ID }}/admin/app
|
|
97
|
+
|
|
98
|
+
jobs:
|
|
99
|
+
deploy:
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
steps:
|
|
102
|
+
- uses: actions/checkout@v4
|
|
103
|
+
|
|
104
|
+
- uses: google-github-actions/auth@v2
|
|
105
|
+
with:
|
|
106
|
+
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
|
107
|
+
|
|
108
|
+
- uses: google-github-actions/setup-gcloud@v2
|
|
109
|
+
|
|
110
|
+
- run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev
|
|
111
|
+
|
|
112
|
+
- run: |
|
|
113
|
+
docker build -t ${{ env.IMAGE }}:${{ github.sha }} ./admin
|
|
114
|
+
docker push ${{ env.IMAGE }}:${{ github.sha }}
|
|
115
|
+
|
|
116
|
+
- run: |
|
|
117
|
+
gcloud run deploy ${{ env.SERVICE }} \
|
|
118
|
+
--image ${{ env.IMAGE }}:${{ github.sha }} \
|
|
119
|
+
--region ${{ env.REGION }} \
|
|
120
|
+
--platform managed \
|
|
121
|
+
--allow-unauthenticated \
|
|
122
|
+
--port 8080
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Step 5 — Custom Domain: admin.akinevz.com
|
|
128
|
+
|
|
129
|
+
Cloud Run supports custom domains directly — no Firebase rewrite needed for a subdomain.
|
|
130
|
+
|
|
131
|
+
### 5a — Map domain in Cloud Run
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
gcloud beta run domain-mappings create \
|
|
135
|
+
--service admin \
|
|
136
|
+
--domain admin.akinevz.com \
|
|
137
|
+
--region europe-west1
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This outputs DNS records to add. They will look something like:
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
Type Name Value
|
|
144
|
+
CNAME admin ghs.googlehosted.com
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 5b — Add DNS record in Cloudflare
|
|
148
|
+
|
|
149
|
+
1. Cloudflare Dashboard → akinevz.com → DNS
|
|
150
|
+
2. Add record:
|
|
151
|
+
- Type: `CNAME`
|
|
152
|
+
- Name: `admin`
|
|
153
|
+
- Target: `ghs.googlehosted.com`
|
|
154
|
+
- **Proxy status: DNS only (grey cloud)** ← required, Cloud Run handles TLS itself
|
|
155
|
+
3. Save
|
|
156
|
+
|
|
157
|
+
> ⚠️ **Reminder:** Cloudflare proxy (orange cloud) must be OFF for Cloud Run custom domains. Cloud Run provisions its own TLS certificate via Google-managed SSL. Orange cloud will break certificate verification.
|
|
158
|
+
|
|
159
|
+
SSL certificate provisioning takes ~15 minutes after DNS propagates.
|
|
160
|
+
|
|
161
|
+
### 5c — Verify
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
gcloud beta run domain-mappings describe \
|
|
165
|
+
--domain admin.akinevz.com \
|
|
166
|
+
--region europe-west1
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Status should show `CertificateProvisioned`.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Step 6 — Firebase Hosting (main site, unchanged)
|
|
174
|
+
|
|
175
|
+
`firebase.json` stays as-is for the React SPA. The `/admin` path on the main domain is now unused — subdomain handles it instead.
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"hosting": {
|
|
180
|
+
"public": "dist",
|
|
181
|
+
"rewrites": [
|
|
182
|
+
{
|
|
183
|
+
"source": "**",
|
|
184
|
+
"destination": "/index.html"
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Step 7 — First Deploy
|
|
194
|
+
|
|
195
|
+
Push `admin/` and the workflow file. Actions will:
|
|
196
|
+
|
|
197
|
+
- Build the Docker image
|
|
198
|
+
- Push to Artifact Registry
|
|
199
|
+
- Deploy to Cloud Run as service `admin`
|
|
200
|
+
|
|
201
|
+
Then run domain mapping command from Step 5a, add Cloudflare DNS, wait for cert.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Repo Structure
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
frontend/
|
|
209
|
+
├── admin/
|
|
210
|
+
│ ├── Admin.csproj
|
|
211
|
+
│ ├── Program.cs
|
|
212
|
+
│ └── Dockerfile
|
|
213
|
+
├── .github/
|
|
214
|
+
│ └── workflows/
|
|
215
|
+
│ ├── deploy-firebase.yml ← existing
|
|
216
|
+
│ └── deploy-admin.yml ← new
|
|
217
|
+
├── firebase.json
|
|
218
|
+
└── src/ ← React frontend
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Notes
|
|
224
|
+
|
|
225
|
+
- Cloud Run scales to zero when idle — no cost when unused.
|
|
226
|
+
- `ASPNETCORE_URLS` must be `http://+:8080` — Cloud Run routes to port 8080 by default.
|
|
227
|
+
- `--allow-unauthenticated` exposes the endpoint publicly. Add auth middleware in `Program.cs` if needed.
|
|
228
|
+
- Artifact Registry storage billed after 500 MB free. Prune old image tags periodically.
|
|
229
|
+
- Cloudflare proxy must stay grey (DNS only) on the `admin` CNAME — never orange.
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
+
import tseslint from 'typescript-eslint'
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
{ ignores: ['dist', '.astro'] },
|
|
9
|
+
{
|
|
10
|
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
languageOptions: {
|
|
13
|
+
ecmaVersion: 2020,
|
|
14
|
+
globals: globals.browser,
|
|
15
|
+
},
|
|
16
|
+
plugins: {
|
|
17
|
+
'react-hooks': reactHooks,
|
|
18
|
+
'react-refresh': reactRefresh,
|
|
19
|
+
},
|
|
20
|
+
rules: {
|
|
21
|
+
...reactHooks.configs.recommended.rules,
|
|
22
|
+
'react-refresh/only-export-components': [
|
|
23
|
+
'warn',
|
|
24
|
+
{ allowConstantExport: true },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
)
|
package/firebase.json
ADDED
package/firestore.rules
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
rules_version = '2';
|
|
2
|
+
service cloud.firestore {
|
|
3
|
+
match /databases/{database}/documents {
|
|
4
|
+
match /resume_interest/{docId} {
|
|
5
|
+
allow create: if
|
|
6
|
+
request.resource.data.keys().hasOnly([
|
|
7
|
+
'email',
|
|
8
|
+
'source',
|
|
9
|
+
'userAgent',
|
|
10
|
+
'createdAt'
|
|
11
|
+
])
|
|
12
|
+
&& request.resource.data.email is string
|
|
13
|
+
&& request.resource.data.email.size() > 5
|
|
14
|
+
&& request.resource.data.email.size() <= 254
|
|
15
|
+
&& request.resource.data.email.matches('^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$')
|
|
16
|
+
&& request.resource.data.source == 'resume_page'
|
|
17
|
+
&& request.resource.data.userAgent is string
|
|
18
|
+
&& request.resource.data.userAgent.size() > 0
|
|
19
|
+
&& request.resource.data.userAgent.size() <= 1024
|
|
20
|
+
&& request.resource.data.createdAt == request.time;
|
|
21
|
+
|
|
22
|
+
allow read, update, delete: if false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
match /{document=**} {
|
|
26
|
+
allow read, write: if false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
package/index.html
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta
|
|
6
|
+
name="viewport"
|
|
7
|
+
content="width=device-width, initial-scale=1.0, maximum-scale=10.0, user-scalable=yes"
|
|
8
|
+
/>
|
|
9
|
+
<meta
|
|
10
|
+
name="description"
|
|
11
|
+
content="my cozy little personal website"
|
|
12
|
+
data-route-meta="description"
|
|
13
|
+
/>
|
|
14
|
+
<link
|
|
15
|
+
rel="canonical"
|
|
16
|
+
href="https://akinevz.com/"
|
|
17
|
+
data-route-meta="canonical"
|
|
18
|
+
/>
|
|
19
|
+
<meta property="og:type" content="website" />
|
|
20
|
+
<meta property="og:title" content="home of kine" data-route-meta="og:title" />
|
|
21
|
+
<meta
|
|
22
|
+
property="og:description"
|
|
23
|
+
content="my cozy little personal website"
|
|
24
|
+
data-route-meta="og:description"
|
|
25
|
+
/>
|
|
26
|
+
<meta property="og:url" content="https://akinevz.com/" data-route-meta="og:url" />
|
|
27
|
+
<meta property="og:image" content="https://akinevz.com/avatar.png" data-route-meta="og:image" />
|
|
28
|
+
<meta name="twitter:card" content="summary" data-route-meta="twitter:card" />
|
|
29
|
+
<meta
|
|
30
|
+
name="twitter:image"
|
|
31
|
+
content="https://akinevz.com/avatar.png"
|
|
32
|
+
data-route-meta="twitter:image"
|
|
33
|
+
/>
|
|
34
|
+
<meta name="twitter:title" content="home of kine" data-route-meta="twitter:title" />
|
|
35
|
+
<meta
|
|
36
|
+
name="twitter:description"
|
|
37
|
+
content="my cozy little personal website"
|
|
38
|
+
data-route-meta="twitter:description"
|
|
39
|
+
/>
|
|
40
|
+
<title data-route-meta="title">home of kine</title>
|
|
41
|
+
<link
|
|
42
|
+
rel="stylesheet"
|
|
43
|
+
href="https://unpkg.com/xp.css@0.2.3/dist/98.css"
|
|
44
|
+
id="theme-css"
|
|
45
|
+
/>
|
|
46
|
+
<noscript><link rel="stylesheet" href="/loading.css" /></noscript>
|
|
47
|
+
</head>
|
|
48
|
+
<body>
|
|
49
|
+
<div id="root"></div>
|
|
50
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
51
|
+
</body>
|
|
52
|
+
</html>
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "website-xp-phone",
|
|
3
|
+
"version": "1.5.0",
|
|
4
|
+
"author": "Kirill <kine> Nevzorov <akinevz@outlook.com>",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "npx -y node@20 ./scripts/hoist-dev-blog-local.mjs",
|
|
8
|
+
"build": "npm run generate:music && vite build",
|
|
9
|
+
"build:local": "npm run generate:music && npm run publish:music && vite build",
|
|
10
|
+
"preview": "vite preview --host 127.0.0.1 --port 8086",
|
|
11
|
+
"lint": "eslint ./src --ext .ts,.tsx",
|
|
12
|
+
"test": "node --test",
|
|
13
|
+
"test:watch": "node --test --watch",
|
|
14
|
+
"check:audit": "npm audit --audit-level=low",
|
|
15
|
+
"security:check": "npm run lint && npm run test && npm run check:audit",
|
|
16
|
+
"pagerts": "NPM_CONFIG_LOGLEVEL=error npx --yes pagerts@latest",
|
|
17
|
+
"generate:music": "node ./scripts/generate-soundcloud-json.mjs",
|
|
18
|
+
"publish:music": "node ./scripts/publish-soundcloud-json.mjs"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"firebase": "^12.14.0",
|
|
22
|
+
"react": "^19.2.4",
|
|
23
|
+
"react-dom": "^19.2.4",
|
|
24
|
+
"react-markdown": "^10.1.0",
|
|
25
|
+
"react-toastify": "^11.0.5",
|
|
26
|
+
"rehype-raw": "^7.0.0",
|
|
27
|
+
"rehype-sanitize": "^6.0.0",
|
|
28
|
+
"xp.css": "^0.2.6"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@eslint/js": "^9.39.4",
|
|
32
|
+
"@types/node": "^24.9.1",
|
|
33
|
+
"@types/react": "^19.2.14",
|
|
34
|
+
"@types/react-dom": "^19.2.3",
|
|
35
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
36
|
+
"eslint": "^9.39.4",
|
|
37
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
38
|
+
"eslint-plugin-react-refresh": "^0.5.2",
|
|
39
|
+
"globals": "^17.4.0",
|
|
40
|
+
"pagerts": "^1.5.4",
|
|
41
|
+
"typescript": "^5.9.3",
|
|
42
|
+
"typescript-eslint": "^8.58.0",
|
|
43
|
+
"vite": "^8.0.10"
|
|
44
|
+
},
|
|
45
|
+
"overrides": {
|
|
46
|
+
"lodash": "^4.17.21"
|
|
47
|
+
}
|
|
48
|
+
}
|