infra: add linting and formatting for js projects (#230)
* wip * wip * wip * format * wip(mobile): lint and format * cleanup * nits * nits * idiomatic react * nit * format all root files
This commit was merged in pull request #230.
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import { useEffect, useRef, type ReactNode } from "react";
|
||||
import { Platform, ScrollView, Text, View, type ViewStyle } from "react-native";
|
||||
import { Renderer, useMarkdown, type MarkedStyles } from "react-native-marked";
|
||||
import type { Particle } from "@/api/types";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { RelativeTimestamp } from "@/components/RelativeTimestamp";
|
||||
import { useStreamSafeArea } from "./stream-safe-area";
|
||||
import { useEffect, useRef, type ReactNode } from 'react';
|
||||
import { Platform, ScrollView, Text, View, type ViewStyle } from 'react-native';
|
||||
import { Renderer, useMarkdown, type MarkedStyles } from 'react-native-marked';
|
||||
import type { Particle } from '@/api/types';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { RelativeTimestamp } from '@/components/RelativeTimestamp';
|
||||
import { useStreamSafeArea } from './stream-safe-area';
|
||||
|
||||
type TextParticle = Extract<Particle, { type: "text" }>;
|
||||
type TextParticle = Extract<Particle, { type: 'text' }>;
|
||||
|
||||
interface TextParticleViewProps {
|
||||
particle: TextParticle;
|
||||
@@ -31,11 +31,9 @@ function computeReadDuration(text: string): number {
|
||||
}
|
||||
|
||||
function getImmersiveStyle(length: number) {
|
||||
if (length < 30)
|
||||
return { className: "text-5xl font-semibold leading-tight" };
|
||||
if (length < 70)
|
||||
return { className: "text-3xl font-semibold leading-snug" };
|
||||
return { className: "text-2xl font-normal leading-snug" };
|
||||
if (length < 30) return { className: 'text-5xl font-semibold leading-tight' };
|
||||
if (length < 70) return { className: 'text-3xl font-semibold leading-snug' };
|
||||
return { className: 'text-2xl font-normal leading-snug' };
|
||||
}
|
||||
|
||||
// Mirrors desktop's text-particle-view: short plain notes get the immersive
|
||||
@@ -59,7 +57,7 @@ function withTaskCheckboxes(markdown: string): string {
|
||||
return markdown.replace(
|
||||
TASK_ITEM_RE,
|
||||
(_match, indent: string, mark: string) =>
|
||||
`${indent}${mark === " " ? "☐" : "☑"} `,
|
||||
`${indent}${mark === ' ' ? '☐' : '☑'} `,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -72,11 +70,11 @@ function withTaskCheckboxes(markdown: string): string {
|
||||
// Known gap vs desktop: fenced code blocks aren't syntax-highlighted (Crepe
|
||||
// uses CodeMirror; react-native-marked only exposes the language tag). They
|
||||
// render as plain monospace on the dark surface, which is acceptable for v1.
|
||||
const TEXT_COLOR = "rgba(255,255,255,0.92)";
|
||||
const ACCENT = "#60a5fa";
|
||||
const SURFACE = "rgba(24,24,28,0.96)";
|
||||
const OUTLINE = "rgba(255,255,255,0.2)";
|
||||
const MONO = Platform.OS === "ios" ? "Menlo" : "monospace";
|
||||
const TEXT_COLOR = 'rgba(255,255,255,0.92)';
|
||||
const ACCENT = '#60a5fa';
|
||||
const SURFACE = 'rgba(24,24,28,0.96)';
|
||||
const OUTLINE = 'rgba(255,255,255,0.2)';
|
||||
const MONO = Platform.OS === 'ios' ? 'Menlo' : 'monospace';
|
||||
|
||||
const MARKDOWN_THEME = {
|
||||
colors: {
|
||||
@@ -90,26 +88,88 @@ const MARKDOWN_THEME = {
|
||||
const MARKDOWN_STYLES: MarkedStyles = {
|
||||
text: { color: TEXT_COLOR, fontSize: 18, lineHeight: 28 },
|
||||
li: { color: TEXT_COLOR, fontSize: 18, lineHeight: 28 },
|
||||
strong: { fontWeight: "700" },
|
||||
em: { fontStyle: "italic" },
|
||||
strong: { fontWeight: '700' },
|
||||
em: { fontStyle: 'italic' },
|
||||
strikethrough: {
|
||||
textDecorationLine: "line-through",
|
||||
color: "rgba(255,255,255,0.6)",
|
||||
textDecorationLine: 'line-through',
|
||||
color: 'rgba(255,255,255,0.6)',
|
||||
},
|
||||
// fontStyle "normal" cancels react-native-marked's italic-by-default for
|
||||
// links and inline code (desktop renders neither italic).
|
||||
link: { color: ACCENT, fontStyle: "normal" },
|
||||
link: { color: ACCENT, fontStyle: 'normal' },
|
||||
// borderBottomWidth 0 removes the library's default heading underline rule,
|
||||
// which desktop's headings don't have.
|
||||
h1: { color: "#ffffff", fontSize: 28, lineHeight: 34, fontWeight: "700", marginTop: 8, marginBottom: 8, borderBottomWidth: 0 },
|
||||
h2: { color: "#ffffff", fontSize: 24, lineHeight: 30, fontWeight: "700", marginTop: 8, marginBottom: 6, borderBottomWidth: 0 },
|
||||
h3: { color: "#ffffff", fontSize: 20, lineHeight: 26, fontWeight: "600", marginTop: 6, marginBottom: 4 },
|
||||
h4: { color: "#ffffff", fontSize: 18, lineHeight: 24, fontWeight: "600", marginTop: 6, marginBottom: 4 },
|
||||
h5: { color: "#ffffff", fontSize: 16, lineHeight: 22, fontWeight: "600", marginTop: 4, marginBottom: 2 },
|
||||
h6: { color: "rgba(255,255,255,0.7)", fontSize: 15, lineHeight: 20, fontWeight: "600", marginTop: 4, marginBottom: 2 },
|
||||
codespan: { color: "#fca5a5", fontFamily: MONO, fontStyle: "normal", backgroundColor: "rgba(255,255,255,0.1)" },
|
||||
code: { backgroundColor: SURFACE, borderColor: OUTLINE, borderWidth: 1, borderRadius: 8, padding: 12, marginVertical: 6 },
|
||||
blockquote: { borderLeftWidth: 3, borderLeftColor: OUTLINE, paddingLeft: 12, marginVertical: 6, opacity: 0.85 },
|
||||
h1: {
|
||||
color: '#ffffff',
|
||||
fontSize: 28,
|
||||
lineHeight: 34,
|
||||
fontWeight: '700',
|
||||
marginTop: 8,
|
||||
marginBottom: 8,
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
h2: {
|
||||
color: '#ffffff',
|
||||
fontSize: 24,
|
||||
lineHeight: 30,
|
||||
fontWeight: '700',
|
||||
marginTop: 8,
|
||||
marginBottom: 6,
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
h3: {
|
||||
color: '#ffffff',
|
||||
fontSize: 20,
|
||||
lineHeight: 26,
|
||||
fontWeight: '600',
|
||||
marginTop: 6,
|
||||
marginBottom: 4,
|
||||
},
|
||||
h4: {
|
||||
color: '#ffffff',
|
||||
fontSize: 18,
|
||||
lineHeight: 24,
|
||||
fontWeight: '600',
|
||||
marginTop: 6,
|
||||
marginBottom: 4,
|
||||
},
|
||||
h5: {
|
||||
color: '#ffffff',
|
||||
fontSize: 16,
|
||||
lineHeight: 22,
|
||||
fontWeight: '600',
|
||||
marginTop: 4,
|
||||
marginBottom: 2,
|
||||
},
|
||||
h6: {
|
||||
color: 'rgba(255,255,255,0.7)',
|
||||
fontSize: 15,
|
||||
lineHeight: 20,
|
||||
fontWeight: '600',
|
||||
marginTop: 4,
|
||||
marginBottom: 2,
|
||||
},
|
||||
codespan: {
|
||||
color: '#fca5a5',
|
||||
fontFamily: MONO,
|
||||
fontStyle: 'normal',
|
||||
backgroundColor: 'rgba(255,255,255,0.1)',
|
||||
},
|
||||
code: {
|
||||
backgroundColor: SURFACE,
|
||||
borderColor: OUTLINE,
|
||||
borderWidth: 1,
|
||||
borderRadius: 8,
|
||||
padding: 12,
|
||||
marginVertical: 6,
|
||||
},
|
||||
blockquote: {
|
||||
borderLeftWidth: 3,
|
||||
borderLeftColor: OUTLINE,
|
||||
paddingLeft: 12,
|
||||
marginVertical: 6,
|
||||
opacity: 0.85,
|
||||
},
|
||||
// hr is left to the library default, which already draws a 1px rule in the
|
||||
// themed border color (OUTLINE).
|
||||
table: { borderWidth: 1, borderColor: OUTLINE, marginVertical: 6 },
|
||||
@@ -187,7 +247,10 @@ export function TextParticleView({
|
||||
// Immersive (short, plain): centered, large type — feels like a lock-screen
|
||||
// note. Short messages that contain markdown fall through to the rendered
|
||||
// card so formatting isn't shown as raw syntax.
|
||||
if (content.length < IMMERSIVE_CHAR_LIMIT && !hasMarkdownFormatting(content)) {
|
||||
if (
|
||||
content.length < IMMERSIVE_CHAR_LIMIT &&
|
||||
!hasMarkdownFormatting(content)
|
||||
) {
|
||||
const style = getImmersiveStyle(content.length);
|
||||
return (
|
||||
<View
|
||||
@@ -198,7 +261,7 @@ export function TextParticleView({
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
className={cn("text-white text-center max-w-xl", style.className)}
|
||||
className={cn('text-white text-center max-w-xl', style.className)}
|
||||
>
|
||||
{content}
|
||||
</Text>
|
||||
|
||||
Reference in New Issue
Block a user