Skip to content

Commit cb24768

Browse files
committed
refactor: remove QR code from share modal
1 parent 182fffa commit cb24768

File tree

2 files changed

+0
-623
lines changed

2 files changed

+0
-623
lines changed

src/routes/[username]/[slug]/+page.svelte

Lines changed: 0 additions & 311 deletions
Original file line numberDiff line numberDiff line change
@@ -48,245 +48,7 @@
4848
window.open(tweetUrl, '_blank', 'width=550,height=420');
4949
}
5050
51-
function generateQrMatrix(input: string): boolean[][] {
52-
const EC_CODEWORDS: Record<number, number> = { 1: 7, 2: 10, 3: 15, 4: 20, 5: 26, 6: 36, 7: 40, 8: 48, 9: 60, 10: 72 };
53-
const TOTAL_CODEWORDS: Record<number, number> = { 1: 26, 2: 44, 3: 70, 4: 100, 5: 134, 6: 172, 7: 196, 8: 242, 9: 292, 10: 346 };
54-
const DATA_CAPACITY: Record<number, number> = {};
55-
for (let v = 1; v <= 10; v++) DATA_CAPACITY[v] = TOTAL_CODEWORDS[v] - EC_CODEWORDS[v];
56-
57-
const bytes: number[] = [];
58-
for (let i = 0; i < input.length; i++) {
59-
const c = input.charCodeAt(i);
60-
if (c < 128) bytes.push(c);
61-
else if (c < 2048) { bytes.push(192 | (c >> 6)); bytes.push(128 | (c & 63)); }
62-
else { bytes.push(224 | (c >> 12)); bytes.push(128 | ((c >> 6) & 63)); bytes.push(128 | (c & 63)); }
63-
}
64-
65-
let version = 1;
66-
for (let v = 1; v <= 10; v++) {
67-
const dataCap = DATA_CAPACITY[v];
68-
const bitCap = dataCap * 8;
69-
const needed = 4 + 8 + bytes.length * 8;
70-
if (needed <= bitCap) { version = v; break; }
71-
if (v === 10) version = 10;
72-
}
73-
74-
const size = 17 + version * 4;
75-
const modules: boolean[][] = Array.from({ length: size }, () => Array(size).fill(false));
76-
const reserved: boolean[][] = Array.from({ length: size }, () => Array(size).fill(false));
77-
78-
function setModule(r: number, c: number, val: boolean, reserve = true) {
79-
if (r >= 0 && r < size && c >= 0 && c < size) {
80-
modules[r][c] = val;
81-
if (reserve) reserved[r][c] = true;
82-
}
83-
}
84-
85-
function addFinderPattern(row: number, col: number) {
86-
for (let r = -1; r <= 7; r++) {
87-
for (let c = -1; c <= 7; c++) {
88-
const rr = row + r, cc = col + c;
89-
if (rr < 0 || rr >= size || cc < 0 || cc >= size) continue;
90-
const inOuter = r === 0 || r === 6 || c === 0 || c === 6;
91-
const inInner = r >= 2 && r <= 4 && c >= 2 && c <= 4;
92-
const inSep = r === -1 || r === 7 || c === -1 || c === 7;
93-
setModule(rr, cc, (inOuter || inInner) && !inSep);
94-
}
95-
}
96-
}
97-
98-
addFinderPattern(0, 0);
99-
addFinderPattern(0, size - 7);
100-
addFinderPattern(size - 7, 0);
101-
102-
for (let i = 8; i < size - 8; i++) {
103-
setModule(6, i, i % 2 === 0);
104-
setModule(i, 6, i % 2 === 0);
105-
}
10651
107-
setModule(size - 8, 8, true);
108-
109-
if (version >= 2) {
110-
const alignPos = [6, size - 7];
111-
for (const ar of alignPos) {
112-
for (const ac of alignPos) {
113-
if (reserved[ar][ac]) continue;
114-
for (let r = -2; r <= 2; r++) {
115-
for (let c = -2; c <= 2; c++) {
116-
const val = Math.abs(r) === 2 || Math.abs(c) === 2 || (r === 0 && c === 0);
117-
setModule(ar + r, ac + c, val);
118-
}
119-
}
120-
}
121-
}
122-
}
123-
124-
for (let i = 0; i < 15; i++) {
125-
const r1 = i < 6 ? i : i < 8 ? i + 1 : size - 15 + i;
126-
const c1 = 8;
127-
reserved[r1][c1] = true;
128-
const r2 = 8;
129-
const c2 = i < 8 ? size - 1 - i : i < 9 ? 15 - i : 14 - i;
130-
reserved[r2][c2] = true;
131-
}
132-
133-
const dataCap = DATA_CAPACITY[version];
134-
const bits: number[] = [];
135-
function pushBits(val: number, len: number) {
136-
for (let i = len - 1; i >= 0; i--) bits.push((val >> i) & 1);
137-
}
138-
139-
pushBits(0b0100, 4);
140-
pushBits(bytes.length, 8);
141-
for (const b of bytes) pushBits(b, 8);
142-
pushBits(0, Math.min(4, dataCap * 8 - bits.length));
143-
while (bits.length % 8 !== 0) bits.push(0);
144-
const pads = [0xEC, 0x11];
145-
let padIdx = 0;
146-
while (bits.length < dataCap * 8) {
147-
pushBits(pads[padIdx % 2], 8);
148-
padIdx++;
149-
}
150-
151-
const dataCodewords: number[] = [];
152-
for (let i = 0; i < bits.length; i += 8) {
153-
let val = 0;
154-
for (let j = 0; j < 8; j++) val = (val << 1) | (bits[i + j] || 0);
155-
dataCodewords.push(val);
156-
}
157-
158-
const numEc = EC_CODEWORDS[version];
159-
const gfExp: number[] = new Array(256);
160-
const gfLog: number[] = new Array(256);
161-
let x = 1;
162-
for (let i = 0; i < 255; i++) {
163-
gfExp[i] = x;
164-
gfLog[x] = i;
165-
x <<= 1;
166-
if (x >= 256) x ^= 0x11D;
167-
}
168-
gfExp[255] = gfExp[0];
169-
170-
function gfMul(a: number, b: number): number {
171-
if (a === 0 || b === 0) return 0;
172-
return gfExp[(gfLog[a] + gfLog[b]) % 255];
173-
}
174-
175-
const gen: number[] = [1];
176-
for (let i = 0; i < numEc; i++) {
177-
const newGen = new Array(gen.length + 1).fill(0);
178-
for (let j = 0; j < gen.length; j++) {
179-
newGen[j] ^= gfMul(gen[j], gfExp[i]);
180-
newGen[j + 1] ^= gen[j];
181-
}
182-
gen.length = 0;
183-
gen.push(...newGen);
184-
}
185-
186-
const msgPoly = new Array(dataCodewords.length + numEc).fill(0);
187-
for (let i = 0; i < dataCodewords.length; i++) msgPoly[i] = dataCodewords[i];
188-
for (let i = 0; i < dataCodewords.length; i++) {
189-
const coef = msgPoly[i];
190-
if (coef !== 0) {
191-
for (let j = 0; j < gen.length; j++) {
192-
msgPoly[i + j] ^= gfMul(gen[j], coef);
193-
}
194-
}
195-
}
196-
const ecCodewords = msgPoly.slice(dataCodewords.length);
197-
198-
const allCodewords = [...dataCodewords, ...ecCodewords];
199-
const allBits: number[] = [];
200-
for (const cw of allCodewords) {
201-
for (let i = 7; i >= 0; i--) allBits.push((cw >> i) & 1);
202-
}
203-
204-
let bitIndex = 0;
205-
let upward = true;
206-
for (let col = size - 1; col >= 0; col -= 2) {
207-
if (col === 6) col = 5;
208-
const rows = upward ? Array.from({ length: size }, (_, i) => size - 1 - i) : Array.from({ length: size }, (_, i) => i);
209-
for (const row of rows) {
210-
for (const dc of [0, -1]) {
211-
const cc = col + dc;
212-
if (cc < 0 || cc >= size) continue;
213-
if (reserved[row][cc]) continue;
214-
modules[row][cc] = bitIndex < allBits.length ? allBits[bitIndex] === 1 : false;
215-
bitIndex++;
216-
}
217-
}
218-
upward = !upward;
219-
}
220-
221-
for (let r = 0; r < size; r++) {
222-
for (let c = 0; c < size; c++) {
223-
if (reserved[r][c]) continue;
224-
if ((r + c) % 2 === 0) modules[r][c] = !modules[r][c];
225-
}
226-
}
227-
228-
const formatBits = (1 << 10) | (0 << 3);
229-
let rem = formatBits;
230-
for (let i = 0; i < 5; i++) {
231-
if (rem & (1 << (14 - i))) rem ^= 0x537 << (4 - i);
232-
}
233-
let formatInfo = (formatBits | rem) ^ 0x5412;
234-
235-
for (let i = 0; i < 15; i++) {
236-
const bit = ((formatInfo >> (14 - i)) & 1) === 1;
237-
const r1 = i < 6 ? i : i < 8 ? i + 1 : size - 15 + i;
238-
modules[r1][8] = bit;
239-
const c2 = i < 8 ? size - 1 - i : i < 9 ? 15 - i : 14 - i;
240-
modules[8][c2] = bit;
241-
}
242-
243-
return modules;
244-
}
245-
246-
function qrToSvg(url: string, cellSize = 8, margin = 16): string {
247-
const matrix = generateQrMatrix(url);
248-
const qrSize = matrix.length;
249-
const svgSize = qrSize * cellSize + margin * 2;
250-
251-
let rects = '';
252-
for (let r = 0; r < qrSize; r++) {
253-
for (let c = 0; c < qrSize; c++) {
254-
if (matrix[r][c]) {
255-
rects += `<rect x="${margin + c * cellSize}" y="${margin + r * cellSize}" width="${cellSize}" height="${cellSize}" rx="1.5"/>`;
256-
}
257-
}
258-
}
259-
260-
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${svgSize} ${svgSize}" width="${svgSize}" height="${svgSize}">
261-
<rect width="${svgSize}" height="${svgSize}" fill="#ffffff" rx="12"/>
262-
${rects}
263-
</svg>`;
264-
}
265-
266-
function downloadQrPng() {
267-
const svg = qrToSvg(getShareUrl(), 10, 20);
268-
const blob = new Blob([svg], { type: 'image/svg+xml' });
269-
const url = URL.createObjectURL(blob);
270-
const img = new Image();
271-
img.onload = () => {
272-
const canvas = document.createElement('canvas');
273-
canvas.width = img.width * 2;
274-
canvas.height = img.height * 2;
275-
const ctx = canvas.getContext('2d')!;
276-
ctx.scale(2, 2);
277-
ctx.drawImage(img, 0, 0);
278-
URL.revokeObjectURL(url);
279-
canvas.toBlob((pngBlob) => {
280-
if (!pngBlob) return;
281-
const a = document.createElement('a');
282-
a.href = URL.createObjectURL(pngBlob);
283-
a.download = `${data.config.name.replace(/\s+/g, '-').toLowerCase()}-qr.png`;
284-
a.click();
285-
URL.revokeObjectURL(a.href);
286-
}, 'image/png');
287-
};
288-
img.src = url;
289-
}
29052
29153
async function forkConfig() {
29254
forking = true;
@@ -708,22 +470,7 @@ ${rects}
708470
<span class="share-option-label">Share on X</span>
709471
</button>
710472

711-
<div class="share-qr-section">
712-
<div class="share-qr-header">
713-
<span class="share-option-icon">
714-
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="3" height="3"/><line x1="21" y1="14" x2="21" y2="17"/><line x1="14" y1="21" x2="17" y2="21"/></svg>
715-
</span>
716-
<span class="share-qr-title">QR Code</span>
717-
</div>
718-
<div class="share-qr-code">
719-
{@html qrToSvg(getShareUrl())}
720-
</div>
721-
<button class="share-qr-download" onclick={downloadQrPng}>
722-
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
723-
Download PNG
724-
</button>
725473
</div>
726-
</div>
727474
</div>
728475
</div>
729476
</div>
@@ -1498,64 +1245,6 @@ ${rects}
14981245
font-weight: 500;
14991246
}
15001247
1501-
.share-qr-section {
1502-
display: flex;
1503-
flex-direction: column;
1504-
align-items: center;
1505-
gap: 12px;
1506-
padding: 16px;
1507-
background: var(--bg-tertiary);
1508-
border: 1px solid var(--border);
1509-
border-radius: 10px;
1510-
}
1511-
1512-
.share-qr-header {
1513-
display: flex;
1514-
align-items: center;
1515-
gap: 12px;
1516-
align-self: flex-start;
1517-
}
1518-
1519-
.share-qr-title {
1520-
font-size: 0.9rem;
1521-
font-weight: 500;
1522-
color: var(--text-primary);
1523-
}
1524-
1525-
.share-qr-code {
1526-
background: #ffffff;
1527-
border-radius: 12px;
1528-
padding: 8px;
1529-
display: flex;
1530-
align-items: center;
1531-
justify-content: center;
1532-
}
1533-
1534-
.share-qr-code :global(svg) {
1535-
width: 180px;
1536-
height: 180px;
1537-
}
1538-
1539-
.share-qr-download {
1540-
display: flex;
1541-
align-items: center;
1542-
gap: 6px;
1543-
padding: 8px 16px;
1544-
background: var(--bg-secondary);
1545-
border: 1px solid var(--border);
1546-
border-radius: 6px;
1547-
color: var(--text-secondary);
1548-
font-size: 0.8rem;
1549-
font-family: inherit;
1550-
cursor: pointer;
1551-
transition: all 0.2s;
1552-
}
1553-
1554-
.share-qr-download:hover {
1555-
border-color: var(--accent);
1556-
color: var(--accent);
1557-
}
1558-
15591248
@media (max-width: 600px) {
15601249
.config-name {
15611250
font-size: 1.5rem;

0 commit comments

Comments
 (0)