1
0
mirror of https://git.boykissers.com/pawkey/pawkey-sk.git synced 2025-12-20 04:04:16 +00:00

feat: [frontend / backend] update git urls, update userid watermark, authenticate image proxy and url previews

This commit is contained in:
Leafus
2025-11-18 05:08:44 +01:00
parent 3fddd69ad8
commit ab15656458
25 changed files with 193 additions and 114 deletions

View File

@@ -1,7 +1,7 @@
<!-- 💖 Thanks for taking the time to fill out this bug report! <!-- 💖 Thanks for taking the time to fill out this bug report!
💁 Having trouble with deployment? [Ask the support chat.]() 💁 Having trouble with deployment? [Ask the support chat.]()
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://git.leafus.net/pawkey/pawkey/-/blob/stable/SECURITY.md) 🔒 Found a security vulnerability? [Please disclose it responsibly.](https://git.pawlickers.org/pawkey/pawkey/src/branch/stable/SECURITY.md)
🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://git.leafus.net/pawkey/pawkey/-/blob/stable/CONTRIBUTING.md) --> 🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://git.pawlickers.org/pawkey/pawkey/src/branch/stable/CONTRIBUTING.md) -->
# **What happened?** # **What happened?**
<!-- Please give us a brief description of what happened. --> <!-- Please give us a brief description of what happened. -->
@@ -30,6 +30,6 @@
<!-- Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks. --> <!-- Please copy and paste any relevant log output. You can find your log by inspecting the page, and going to the "console" tab. This will be automatically formatted into code, so no need for backticks. -->
# **Contribution Guidelines** # **Contribution Guidelines**
By submitting this issue, you agree to follow our [Contribution Guidelines](https://git.leafus.net/pawkey/pawkey/-/blob/stable/CONTRIBUTING.md) By submitting this issue, you agree to follow our [Contribution Guidelines](https://git.pawlickers.org/pawkey/pawkey/src/branch/stable/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines - [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar issues, and this is not a duplicate. - [ ] I have searched the issue tracker for similar issues, and this is not a duplicate.

View File

@@ -1,7 +1,7 @@
<!-- 💖 Thanks for taking the time to fill out this bug report! <!-- 💖 Thanks for taking the time to fill out this bug report!
💁 Having trouble with deployment? [Ask the support chat.]() 💁 Having trouble with deployment? [Ask the support chat.]()
🔒 Found a security vulnerability? [Please disclose it responsibly.](https://git.leafus.net/pawkey/pawkey/-/blob/stable/SECURITY.md) 🔒 Found a security vulnerability? [Please disclose it responsibly.](https://git.pawlickers.org/pawkey/pawkey/src/branch/stable/SECURITY.md)
🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://git.leafus.net/pawkey/pawkey/-/blob/stable/CONTRIBUTING.md) --> 🤝 By submitting this feature request, you agree to follow our [Contribution Guidelines.](https://git.pawlickers.org/pawkey/pawkey/src/branch/stable/CONTRIBUTING.md) -->
# **What feature would you like implemented?** # **What feature would you like implemented?**
<!-- Please give us a brief description of what you'd like. --> <!-- Please give us a brief description of what you'd like. -->
@@ -16,6 +16,6 @@
<!-- What instance of Pawkey are you using? --> <!-- What instance of Pawkey are you using? -->
# **Contribution Guidelines** # **Contribution Guidelines**
By submitting this issue, you agree to follow our [Contribution Guidelines](https://activitypub.software/TransFem-org/Pawkey/-/blob/develop/CONTRIBUTING.md) By submitting this issue, you agree to follow our [Contribution Guidelines](https://git.pawlickers.org/pawkey/pawkey/src/branch/stable/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines - [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have searched the issue tracker for similar requests, and this is not a duplicate. - [ ] I have searched the issue tracker for similar requests, and this is not a duplicate.

View File

@@ -6,7 +6,7 @@
%{all_commits} %{all_commits}
# **Contribution Guidelines** # **Contribution Guidelines**
By submitting this merge request, you agree to follow our [Contribution Guidelines](https://git.leafus.net/pawkey/pawkey/-/blob/stable/CONTRIBUTING.md) By submitting this merge request, you agree to follow our [Contribution Guidelines](https://git.pawlickers.org/pawkey/pawkey/src/branch/stable/CONTRIBUTING.md)
- [ ] I agree to follow this project's Contribution Guidelines - [ ] I agree to follow this project's Contribution Guidelines
- [ ] I have made sure to test this merge request - [ ] I have made sure to test this merge request

View File

@@ -133,7 +133,7 @@ An actual domain will be assigned so you can test the federation.
- `x.y.z` is the new version you are trying to release. - `x.y.z` is the new version you are trying to release.
3. Deploy and perform a simple QA check. Also verify that the tests passed. 3. Deploy and perform a simple QA check. Also verify that the tests passed.
4. Merge it. (Do not squash commit) 4. Merge it. (Do not squash commit)
5. Create a [release](https://git.leafus.net/pawkey/pawkey/-/releases) 5. Create a [release](https://git.pawlickers.org/pawkey/pawkey/releases)
- The target branch must be `stable` - The target branch must be `stable`
- The tag name must be the version - The tag name must be the version

View File

@@ -1,6 +1,6 @@
<div align="center"> <div align="center">
<a href="https://pawkey.dev"> <a href="https://pawkey.dev">
<img src="https://git.leafus.net/pawkey/pawkey/-/raw/stable/packages/frontend/assets/pawkey.png" alt="Pawkey logo" width="300"/> <img src="https://git.pawlickers.org/pawkey/pawkey/raw/branch/stable/packages/frontend/assets/pawkey.png" alt="Pawkey logo" width="300"/>
</a> </a>
**🌎 **[Pawkey](https://pawkey.dev)** is an open source, decentralized social media platform that's free forever! 🚀** **🌎 **[Pawkey](https://pawkey.dev)** is an open source, decentralized social media platform that's free forever! 🚀**

2
locales/index.d.ts vendored
View File

@@ -4888,7 +4888,7 @@ export interface Locale extends ILocale {
*/ */
"repositoryUrl": string; "repositoryUrl": string;
/** /**
* If there is a repository where the source code is publicly available, enter its URL. If you are using Pawkey as-is (without any changes to the source code), enter https://git.leafus.net/pawkey/pawkey. * If there is a repository where the source code is publicly available, enter its URL. If you are using Pawkey as-is (without any changes to the source code), enter https://git.pawlickers.org/pawkey/pawkey.
*/ */
"repositoryUrlDescription": string; "repositoryUrlDescription": string;
/** /**

View File

@@ -4,7 +4,7 @@
"codename": "pawjob", "codename": "pawjob",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://git.leafus.net/pawkey/pawkey.git" "url": "https://git.pawlickers.org/pawkey/pawkey.git"
}, },
"packageManager": "pnpm@9.6.0", "packageManager": "pnpm@9.6.0",
"workspaces": [ "workspaces": [

View File

@@ -6,8 +6,8 @@
export class AddSomeUrls1557761316509 { export class AddSomeUrls1557761316509 {
async up(queryRunner) { async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ADD "ToSUrl" character varying(512)`); await queryRunner.query(`ALTER TABLE "meta" ADD "ToSUrl" character varying(512)`);
await queryRunner.query(`ALTER TABLE "meta" ADD "repositoryUrl" character varying(512) NOT NULL DEFAULT 'https://git.leafus.net/pawkey/pawkey'`); await queryRunner.query(`ALTER TABLE "meta" ADD "repositoryUrl" character varying(512) NOT NULL DEFAULT 'https://git.pawlickers.org/pawkey/pawkey'`);
await queryRunner.query(`ALTER TABLE "meta" ADD "feedbackUrl" character varying(512) DEFAULT 'https://git.leafus.net/pawkey/pawkey/issues/new/choose'`); await queryRunner.query(`ALTER TABLE "meta" ADD "feedbackUrl" character varying(512) DEFAULT 'https://git.pawlickers.org/pawkey/pawkey/issues/new'`);
} }
async down(queryRunner) { async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "feedbackUrl"`); await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "feedbackUrl"`);

View File

@@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: pawinput and Pawkey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class ChangeGITUrls1763436210524 {
name = 'ChangeGITUrls1763436210524'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET DEFAULT 'https://git.pawlickers.org/pawkey/pawkey'`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "feedbackUrl" SET DEFAULT 'https://git.pawlickers.org/pawkey/pawkey/issues/new'`);
await queryRunner.query(`UPDATE "meta" SET "repositoryUrl"=DEFAULT WHERE "repositoryUrl" IN ('https://git.leafus.net/pawkey/pawkey')`);
await queryRunner.query(`UPDATE "meta" SET "feedbackUrl"=DEFAULT WHERE "feedbackUrl" IN ('https://git.leafus.net/pawkey/pawkey/-/issues/new')`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "repositoryUrl" SET DEFAULT 'https://git.leafus.net/pawkey/pawkey'`);
await queryRunner.query(`ALTER TABLE "meta" ALTER COLUMN "feedbackUrl" SET DEFAULT 'https://git.leafus.net/pawkey/pawkey/-/issues/new'`);
await queryRunner.query(`UPDATE "meta" SET "repositoryUrl"=DEFAULT WHERE "repositoryUrl" IN ('https://git.pawlickers.org/pawkey/pawkey')`);
await queryRunner.query(`UPDATE "meta" SET "feedbackUrl"=DEFAULT WHERE "feedbackUrl" IN ('https://git.pawlickers.org/pawkey/pawkey/issues/new')`);
}
}

View File

@@ -483,7 +483,7 @@ export function loadConfig(): Config {
videoThumbnailGenerator: config.videoThumbnailGenerator ? videoThumbnailGenerator: config.videoThumbnailGenerator ?
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
: null, : null,
userAgent: `Misskey/${version} (${config.url})`, userAgent: `Pawkey/${version} (${config.url})`,
frontendEntry: frontendManifest['src/_boot_.ts'], frontendEntry: frontendManifest['src/_boot_.ts'],
frontendManifestExists: frontendManifestExists, frontendManifestExists: frontendManifestExists,
frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'], frontendEmbedEntry: frontendEmbedManifest['src/boot.ts'],

View File

@@ -458,14 +458,14 @@ export class MiMeta {
@Column('varchar', { @Column('varchar', {
length: 1024, length: 1024,
default: 'https://git.leafus.net/pawkey/pawkey/', default: 'https://git.pawlickers.org/pawkey/pawkey/',
nullable: false, nullable: false,
}) })
public repositoryUrl: string | null; public repositoryUrl: string | null;
@Column('varchar', { @Column('varchar', {
length: 1024, length: 1024,
default: 'https://git.leafus.net/pawkey/pawkey/-/issues/new', default: 'https://git.pawlickers.org/pawkey/pawkey/issues/new',
nullable: true, nullable: true,
}) })
public feedbackUrl: string | null; public feedbackUrl: string | null;

View File

@@ -108,6 +108,43 @@ export class FileServerService {
return; return;
} }
const body = request.method === 'GET'
? request.query
: request.body;
let cookieToken: string | undefined;
if (request.headers.cookie) {
const cookies = request.headers.cookie.split(';').reduce((acc, cookie) => {
const [key, value] = cookie.trim().split('=');
acc[key] = value;
return acc;
}, {} as Record<string, string>);
cookieToken = cookies.token;
}
const token = request.headers.authorization?.startsWith('Bearer ')
? request.headers.authorization.slice(7)
: (body as any)?.['i'] ?? cookieToken;
if (token != null && typeof token !== 'string') {
reply.code(400);
return;
}
const [user] = await this.authenticateService.authenticate(token);
if (!user) {
reply.code(401);
reply.send({
error: {
message: 'Credential required.',
code: 'CREDENTIAL_REQUIRED',
id: '1384574d-a912-4b81-8601-c7b1c4085df1',
},
});
return;
}
const keyUrl = new URL(url); const keyUrl = new URL(url);
keyUrl.searchParams.forEach(k => keyUrl.searchParams.delete(k)); keyUrl.searchParams.forEach(k => keyUrl.searchParams.delete(k));
keyUrl.hash = ''; keyUrl.hash = '';
@@ -632,7 +669,7 @@ export class FileServerService {
// https://datatracker.ietf.org/doc/html/rfc6750.html#section-2.1 (case sensitive) // https://datatracker.ietf.org/doc/html/rfc6750.html#section-2.1 (case sensitive)
const token = request.headers.authorization?.startsWith('Bearer ') const token = request.headers.authorization?.startsWith('Bearer ')
? request.headers.authorization.slice(7) ? request.headers.authorization.slice(7)
: body?.['i']; : (body as any)?.['i'];
if (token != null && typeof token !== 'string') { if (token != null && typeof token !== 'string') {
reply.code(400); reply.code(400);
return false; return false;

View File

@@ -95,12 +95,27 @@ export class StreamingApiServerService {
? request.headers.authorization.slice(7) ? request.headers.authorization.slice(7)
: q.get('i'); : q.get('i');
// Require authentication for WebSocket connections
if (!token) {
socket.write([
'HTTP/1.1 401 Unauthorized',
'WWW-Authenticate: Bearer realm="Misskey"',
].join('\r\n') + '\r\n\r\n');
socket.destroy();
return;
}
try { try {
[user, app] = await this.authenticateService.authenticate(token); [user, app] = await this.authenticateService.authenticate(token);
if (app !== null && !app.permission.some(p => p === 'read:account')) { if (app !== null && !app.permission.some(p => p === 'read:account')) {
throw new AuthenticationError('Your app does not have necessary permissions to use websocket API.'); throw new AuthenticationError('Your app does not have necessary permissions to use websocket API.');
} }
// Ensure we have a valid user
if (!user) {
throw new AuthenticationError('Invalid token or user not found.');
}
} catch (e) { } catch (e) {
if (e instanceof AuthenticationError) { if (e instanceof AuthenticationError) {
socket.write([ socket.write([

View File

@@ -19,7 +19,7 @@ export function genOpenapiSpec(config: Config, includeSelfRef = false) {
externalDocs: { externalDocs: {
description: 'Repository', description: 'Repository',
url: 'https://git.leafus.net/pawkey/pawkey', url: 'https://git.pawlickers.org/pawkey/pawkey',
}, },
servers: [{ servers: [{
@@ -97,7 +97,7 @@ export function genOpenapiSpec(config: Config, includeSelfRef = false) {
description: desc, description: desc,
externalDocs: { externalDocs: {
description: 'Source code', description: 'Source code',
url: `https://git.leafus.net/pawkey/pawkey/-/tree/stable/packages/backend/src/server/api/endpoints/${endpoint.name}.ts`, url: `https://git.pawlickers.org/pawkey/pawkey/src/branch/stable/packages/backend/src/server/api/endpoints/${endpoint.name}.ts`,
}, },
...(endpoint.meta.tags ? { ...(endpoint.meta.tags ? {
tags: [endpoint.meta.tags[0]], tags: [endpoint.meta.tags[0]],

View File

@@ -169,8 +169,22 @@ export class UrlPreviewService {
return; return;
} }
// Check rate limit // Check authentication
const auth = await this.authenticate(request); const auth = await this.authenticate(request);
const [user] = auth;
if (!user) {
reply.code(401);
return reply.send({
error: {
message: 'Credential required.',
code: 'CREDENTIAL_REQUIRED',
id: '1384574d-a912-4b81-8601-c7b1c4085df1',
},
});
}
// Check rate limit
if (!await this.checkRateLimit(auth, reply)) { if (!await this.checkRateLimit(auth, reply)) {
return; return;
} }
@@ -450,10 +464,21 @@ export class UrlPreviewService {
private async authenticate(request: FastifyRequest<{ Querystring?: { i?: string | string[] }, Body?: { i?: string | string[] } }>): Promise<AuthArray> { private async authenticate(request: FastifyRequest<{ Querystring?: { i?: string | string[] }, Body?: { i?: string | string[] } }>): Promise<AuthArray> {
const body = request.method === 'GET' ? request.query : request.body; const body = request.method === 'GET' ? request.query : request.body;
// Parse token from cookie header if present
let cookieToken: string | undefined;
if (request.headers.cookie) {
const cookies = request.headers.cookie.split(';').reduce((acc, cookie) => {
const [key, value] = cookie.trim().split('=');
acc[key] = value;
return acc;
}, {} as Record<string, string>);
cookieToken = cookies.token;
}
// https://datatracker.ietf.org/doc/html/rfc6750.html#section-2.1 (case sensitive) // https://datatracker.ietf.org/doc/html/rfc6750.html#section-2.1 (case sensitive)
const token = request.headers.authorization?.startsWith('Bearer ') const token = request.headers.authorization?.startsWith('Bearer ')
? request.headers.authorization.slice(7) ? request.headers.authorization.slice(7)
: body?.['i']; : body?.['i'] ?? cookieToken;
if (token != null && typeof token !== 'string') { if (token != null && typeof token !== 'string') {
return [undefined, undefined, getIpHash(request.ip)]; return [undefined, undefined, getIpHash(request.ip)];
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 KiB

After

Width:  |  Height:  |  Size: 774 KiB

View File

@@ -16,6 +16,7 @@ import { prefer } from '@/preferences.js';
import { store } from '@/store.js'; import { store } from '@/store.js';
import { $i } from '@/i.js'; import { $i } from '@/i.js';
import { signout } from '@/signout.js'; import { signout } from '@/signout.js';
import Cookies from 'js-cookie';
type AccountWithToken = Misskey.entities.MeDetailed & { token: string }; type AccountWithToken = Misskey.entities.MeDetailed & { token: string };
@@ -186,6 +187,8 @@ export async function login(token: AccountWithToken['token'], redirect?: string)
token, token,
})); }));
Cookies.set('token', token, { expires: 365 * 100 });
await addAccount(host, me, token); await addAccount(host, me, token);
if (redirect) { if (redirect) {

View File

@@ -335,7 +335,7 @@ export async function mainBoot() {
} }
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read'); const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://git.leafus.net/pawkey/pawkey') { if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://git.pawlickers.org/pawkey/pawkey') {
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, { const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {
closed: () => dispose(), closed: () => dispose(),
}); });

View File

@@ -47,7 +47,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #label>{{ i18n.ts.basicNotesBeforeCreateAccount }}</template> <template #label>{{ i18n.ts.basicNotesBeforeCreateAccount }}</template>
<template #suffix><i v-if="agreeNote" class="ti ti-check" style="color: var(--MI_THEME-success)"></i></template> <template #suffix><i v-if="agreeNote" class="ti ti-check" style="color: var(--MI_THEME-success)"></i></template>
<a href="https://git.leafus.net/pawkey/pawkey/-/blob/stable/IMPORTANT_NOTES.md" class="_link" target="_blank">{{ i18n.ts.basicNotesBeforeCreateAccount }} <i class="ti ti-external-link"></i></a> <a href="https://git.pawlickers.org/pawkey/pawkey/src/branch/stable/IMPORTANT_NOTES.md" class="_link" target="_blank">{{ i18n.ts.basicNotesBeforeCreateAccount }} <i class="ti ti-external-link"></i></a>
<MkSwitch :modelValue="agreeNote" style="margin-top: 16px;" data-cy-signup-rules-notes-agree @update:modelValue="updateAgreeNote">{{ i18n.ts.agree }}</MkSwitch> <MkSwitch :modelValue="agreeNote" style="margin-top: 16px;" data-cy-signup-rules-notes-agree @update:modelValue="updateAgreeNote">{{ i18n.ts.agree }}</MkSwitch>
</MkFolder> </MkFolder>

View File

@@ -27,7 +27,7 @@ const modal = useTemplateRef('modal');
const whatIsNew = () => { const whatIsNew = () => {
modal.value?.close(); modal.value?.close();
window.open(`https://git.leafus.net/pawkey/pawkey/-/releases/${version}`, '_blank'); window.open(`https://git.pawlickers.org/pawkey/pawkey/releases${version}`, '_blank');
}; };
onMounted(() => { onMounted(() => {

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { $i } from "@/i.js"; import { $i } from "@/i.js";
import { computed, onMounted, ref } from "vue"; import { computed, onMounted, onUnmounted, ref } from "vue";
const generateRandomClass = () => { const generateRandomClass = () => {
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -14,10 +14,27 @@ const generateRandomClass = () => {
const gridClass = ref(generateRandomClass()); const gridClass = ref(generateRandomClass());
const itemClasses = ref<string[]>([]); const itemClasses = ref<string[]>([]);
const recreationKey = ref(0); const recreationKey = ref(0);
const gridItemCount = ref(600);
let regenerationInterval: ReturnType<typeof setInterval> | null = null; let regenerationInterval: ReturnType<typeof setInterval> | null = null;
let styleElement: HTMLStyleElement | null = null; let styleElement: HTMLStyleElement | null = null;
let allCreatedClasses: string[] = []; let allCreatedClasses: string[] = [];
// Calculate grid items based on screen resolution
const calculateGridItemCount = () => {
const width = window.innerWidth;
const height = window.innerHeight;
// Grid cell size: 80px width + 10px gap, 16px height + 10px gap (more concise)
const itemWidth = 80 + 10;
const itemHeight = 16 + 10;
const columns = Math.ceil(width / itemWidth);
const rows = Math.ceil(height / itemHeight);
// Add some buffer (20%) to ensure coverage during animations/scrolling
return Math.ceil(columns * rows * 1.2);
};
const encodeTextToPath = (text: string) => { const encodeTextToPath = (text: string) => {
const charPaths: { [key: string]: string } = { const charPaths: { [key: string]: string } = {
a: "M2,8 L4,2 L6,2 L8,8 M3,6 L7,6", a: "M2,8 L4,2 L6,2 L8,8 M3,6 L7,6",
@@ -77,7 +94,7 @@ const encodeTextToPath = (text: string) => {
); );
path += translatedPath + " "; path += translatedPath + " ";
} }
xOffset += 10; xOffset += 7; // Reduced from 10 to 7 for tighter spacing
}); });
return path.trim(); return path.trim();
@@ -95,7 +112,9 @@ const regenerateWatermark = () => {
cleanupOldElements(); cleanupOldElements();
gridClass.value = generateRandomClass(); gridClass.value = generateRandomClass();
itemClasses.value = generateItemClasses(600); const count = calculateGridItemCount();
gridItemCount.value = count;
itemClasses.value = generateItemClasses(count);
recreationKey.value++; recreationKey.value++;
allCreatedClasses.push(gridClass.value, ...itemClasses.value); allCreatedClasses.push(gridClass.value, ...itemClasses.value);
@@ -140,13 +159,13 @@ const createStyleElement = () => {
.${className} svg { .${className} svg {
opacity: 0.02 !important; opacity: 0.02 !important;
width: auto !important; width: auto !important;
height: 12px !important; height: 10px !important;
} }
.${className} svg path { .${className} svg path {
stroke: var(--MI_THEME-fg) !important; stroke: var(--MI_THEME-fg) !important;
fill: none !important; fill: none !important;
stroke-width: 1 !important; stroke-width: 0.8 !important;
} }
`, `,
) )
@@ -160,10 +179,10 @@ const createStyleElement = () => {
width: 100vw !important; width: 100vw !important;
height: 100vh !important; height: 100vh !important;
display: grid !important; display: grid !important;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)) !important; grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)) !important;
grid-template-rows: repeat(auto-fill, minmax(20px, 1fr)) !important; grid-template-rows: repeat(auto-fill, minmax(16px, 1fr)) !important;
gap: 20px !important; gap: 10px !important;
padding: 20px !important; padding: 10px !important;
pointer-events: none !important; pointer-events: none !important;
z-index: 999999999 !important; z-index: 999999999 !important;
overflow: hidden !important; overflow: hidden !important;
@@ -177,24 +196,51 @@ const createStyleElement = () => {
const watermarkText = computed(() => $i?.id || "not signed in"); const watermarkText = computed(() => $i?.id || "not signed in");
const pathData = computed(() => encodeTextToPath(watermarkText.value)); const pathData = computed(() => encodeTextToPath(watermarkText.value));
const textWidth = computed(() => watermarkText.value.length * 10 + 10); const textWidth = computed(() => watermarkText.value.length * 7 + 10); // Adjusted for tighter spacing
let resizeTimeout: ReturnType<typeof setTimeout> | null = null;
const handleResize = () => {
if (resizeTimeout) clearTimeout(resizeTimeout);
// Debounce resize to avoid excessive recalculations
resizeTimeout = setTimeout(() => {
regenerateWatermark();
}, 250);
};
onMounted(() => { onMounted(() => {
itemClasses.value = generateItemClasses(600); const count = calculateGridItemCount();
gridItemCount.value = count;
itemClasses.value = generateItemClasses(count);
allCreatedClasses.push(gridClass.value, ...itemClasses.value); allCreatedClasses.push(gridClass.value, ...itemClasses.value);
createStyleElement(); createStyleElement();
regenerationInterval = setInterval(() => { regenerationInterval = setInterval(() => {
itemClasses.value = generateItemClasses(600); const count = calculateGridItemCount();
gridItemCount.value = count;
itemClasses.value = generateItemClasses(count);
allCreatedClasses.push(gridClass.value, ...itemClasses.value); allCreatedClasses.push(gridClass.value, ...itemClasses.value);
regenerateWatermark(); regenerateWatermark();
}, 5000); }, 5000);
window.addEventListener("resize", handleResize);
});
onUnmounted(() => {
if (regenerationInterval) clearInterval(regenerationInterval);
if (resizeTimeout) clearTimeout(resizeTimeout);
window.removeEventListener("resize", handleResize);
cleanupOldElements();
if (styleElement && styleElement.parentNode) {
styleElement.parentNode.removeChild(styleElement);
}
}); });
</script> </script>
<template> <template>
<div :key="`watermark-${recreationKey}`" :class="gridClass"> <div :key="`watermark-${recreationKey}`" :class="gridClass">
<div v-for="n in 600" :key="n" :class="itemClasses[n]"> <div v-for="n in gridItemCount" :key="n" :class="itemClasses[n]">
<svg :viewBox="`0 0 ${textWidth} 10`" xmlns="http://www.w3.org/2000/svg"> <svg :viewBox="`0 0 ${textWidth} 10`" xmlns="http://www.w3.org/2000/svg">
<path :d="pathData" /> <path :d="pathData" />
</svg> </svg>

View File

@@ -22,12 +22,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<button v-if="thereIsTreasure" class="_button treasure" @click="getTreasure"><img src="/fluent-emoji/1f3c6.png" class="treasureImg"></button> <button v-if="thereIsTreasure" class="_button treasure" @click="getTreasure"><img src="/fluent-emoji/1f3c6.png" class="treasureImg"></button>
</div> </div>
<div style="text-align: center;"> <div style="text-align: center;">
{{ i18n.ts._aboutMisskey.about }}<br><a href="https://leafus.net/pawkey" target="_blank" class="_link">{{ i18n.ts.learnMore }}</a> {{ i18n.ts._aboutMisskey.about }}<br><a href="https://pawkey.dev" target="_blank" class="_link">{{ i18n.ts.learnMore }}</a>
</div> </div>
<div v-if="$i != null" style="text-align: center;"> <div v-if="$i != null" style="text-align: center;">
<MkButton primary rounded inline @click="iLoveMisskey">I <Mfm text="$[jelly ❤]"/> #Pawkey</MkButton> <MkButton primary rounded inline @click="iLoveMisskey">I <Mfm text="$[jelly ❤]"/> #Pawkey</MkButton>
</div> </div>
<FormSection v-if="instance.repositoryUrl !== 'https://git.leafus.net/pawkey/pawkey'"> <FormSection v-if="instance.repositoryUrl !== 'https://git.pawlickers.org/pawkey/pawkey'">
<div class="_gaps_s"> <div class="_gaps_s">
<FormLink v-if="instance.repositoryUrl" :to="instance.repositoryUrl" external> <FormLink v-if="instance.repositoryUrl" :to="instance.repositoryUrl" external>
<template #icon><i class="ti ti-code"></i></template> <template #icon><i class="ti ti-code"></i></template>
@@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</FormSection> </FormSection>
<FormSection> <FormSection>
<div class="_gaps_s"> <div class="_gaps_s">
<FormLink to="https://git.leafus.net/pawkey/pawkey" external> <FormLink to="https://git.pawlickers.org/pawkey/pawkey" external>
<template #icon><i class="ph-code ph-bold ph-lg"></i></template> <template #icon><i class="ph-code ph-bold ph-lg"></i></template>
{{ i18n.ts._aboutMisskey.source }} ({{ i18n.ts._aboutMisskey.original_pawkey }}) {{ i18n.ts._aboutMisskey.source }} ({{ i18n.ts._aboutMisskey.original_pawkey }})
<template #suffix>GitLab</template> <template #suffix>GitLab</template>
@@ -128,81 +128,12 @@ const everyone = ref<Section[]>([
heading: 'Pawkey Creators', heading: 'Pawkey Creators',
people: fisher_yates([ people: fisher_yates([
{ {
handle: '@Leafus', handle: '@pawinput',
avatar: 'https://git.leafus.net/uploads/-/system/user/avatar/2/avatar.png?width=192', avatar: 'https://git.pawlickers.org/avatars/5e909e3e9e43b099242596d67debcd61264809b7765f160b01c8a376f23e47a5?size=512',
link: 'https://leafus.net', link: 'https://pawlickers.org',
}, },
]), ]),
}, },
{
heading: 'Sharkey Contributors',
link: {
label: i18n.ts._aboutMisskey.allContributors,
url: 'https://activitypub.software/TransFem-org/Sharkey/-/graphs/develop',
},
people: fisher_yates([
{
handle: '@CenTdemeern1',
avatar: 'https://secure.gravatar.com/avatar/e97dd57d32caf703cea556ace6304617b7420f17f5b1aac4a1eea8e4234735bb?s=128&d=identicon',
link: 'https://activitypub.software/CenTdemeern1',
},
{
handle: '@dakkar',
avatar: 'https://secure.gravatar.com/avatar/c71b315eed7c63ff94c42b1b3e8dbad1?s=128&d=identicon',
link: 'https://activitypub.software/dakkar',
},
{
handle: '@hazelnoot',
avatar: 'https://activitypub.software/uploads/-/system/user/avatar/5/avatar.png?width=128',
link: 'https://activitypub.software/fEmber',
},
{
handle: '@julia',
avatar: 'https://activitypub.software/uploads/-/system/user/avatar/41/avatar.png?width=128',
link: 'https://activitypub.software/julia',
},
{
handle: '@Luna',
avatar: 'https://secure.gravatar.com/avatar/4faf37df86a3d93a6c19ed6abf8588eade4efb837410dbbc53021b4fd12eaae7?s=128&d=identicon',
link: 'https://activitypub.software/luna',
},
{
handle: '@Marie',
avatar: 'https://activitypub.software/uploads/-/system/user/avatar/2/avatar.png?width=128',
link: 'https://activitypub.software/marie',
},
{
handle: '@supakaity',
avatar: 'https://activitypub.software/uploads/-/system/user/avatar/65/avatar.png?width=128',
link: 'https://activitypub.software/supakaity',
},
{
handle: '@tess',
avatar: 'https://activitypub.software/uploads/-/system/user/avatar/132/avatar.png?width=128',
link: 'https://activitypub.software/tess',
},
]),
},
{
heading: 'Sharkey Testers',
people: [
{
handle: '@lucent',
avatar: 'https://antani.cyou/proxy/avatar.webp?url=https%3A%2F%2Fantani.cyou%2Ffiles%2Fa2944119-024c-4abd-86e5-64bf0d30b26f&avatar=1',
link: 'https://antani.cyou/@lucent',
},
{
handle: '@privateger',
avatar: 'https://mediaproxy.plasmatrap.com/?url=https%3A%2F%2Fplasmatrap.com%2Ffiles%2F2cf35a8f-6520-4d4c-9611-bf22ee983293&avatar=1',
link: 'https://plasmatrap.com/@privateger',
},
{
handle: '@phoenix_fairy',
avatar: 'https://thetransagenda.gay/proxy/avatar.webp?url=https%3A%2F%2Fs3.us-east-005.backblazeb2.com%2Ftranssharkey%2Fnull%2Fd93ac6dc-2020-4b5a-bce7-84b41e97a0ac.png&avatar=1',
link: 'https://thetransagenda.gay/@phoenix_fairy',
},
],
},
{ {
heading: i18n.ts._aboutMisskey.misskeyContributors, heading: i18n.ts._aboutMisskey.misskeyContributors,
people: [ people: [

View File

@@ -147,7 +147,7 @@ clickToOpen: "Click to open notes"
showBots: "Show bots in timeline" showBots: "Show bots in timeline"
showRenotes: "Show boosts" showRenotes: "Show boosts"
sourceCodeIsNotYetProvided: "The source code is not yet available. Please contact your administrator to fix this problem." sourceCodeIsNotYetProvided: "The source code is not yet available. Please contact your administrator to fix this problem."
repositoryUrlDescription: "If there is a repository where the source code is publicly available, enter its URL. If you are using Pawkey as-is (without any changes to the source code), enter https://git.leafus.net/pawkey/pawkey." repositoryUrlDescription: "If there is a repository where the source code is publicly available, enter its URL. If you are using Pawkey as-is (without any changes to the source code), enter https://git.pawlickers.org/pawkey/pawkey."
donation: "Donate" donation: "Donate"
donationUrl: "Donation URL" donationUrl: "Donation URL"
showBelowAvatar: "Show Below Avatar" showBelowAvatar: "Show Below Avatar"

View File

@@ -131,7 +131,7 @@ clickToOpen: "クリックしてノートを開く"
showBots: "ボットをタイムラインに表示" showBots: "ボットをタイムラインに表示"
showRenotes: "ブーストを表示" showRenotes: "ブーストを表示"
sourceCodeIsNotYetProvided: "ソースコードはまだ提供されていません。この問題の修正について管理者に問い合わせてください。" sourceCodeIsNotYetProvided: "ソースコードはまだ提供されていません。この問題の修正について管理者に問い合わせてください。"
repositoryUrlDescription: "ソースコードが公開されているリポジトリがある場合、そのURLを記入します。Pawkeyを現状のままソースコードにいかなる変更も加えずに使用している場合は https://git.leafus.net/pawkey/pawkey と記入します。" repositoryUrlDescription: "ソースコードが公開されているリポジトリがある場合、そのURLを記入します。Pawkeyを現状のままソースコードにいかなる変更も加えずに使用している場合は https://git.pawlickers.org/pawkey/pawkey と記入します。"
donation: "寄付する" donation: "寄付する"
donationUrl: "寄付URL" donationUrl: "寄付URL"
showBelowAvatar: "アイコンの後ろに表示" showBelowAvatar: "アイコンの後ろに表示"