Files
+1 913b1178c8 fix(path): change path package to pathe (#4038)
* fix(path): change path package to pathe

* fix: handle special chat in filename, fixed
#3342

- Integrated @sindresorhus/slugify to format file names based on titles.
- Updated pnpm-lock.yaml to include new dependencies.
- Minor adjustments in package.json files to ensure consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: add eslint rule for use pathe first

* refactor: useWhoami from user store (#4061)

* refactor: useWhoami from user store

* update

* update

* update

* update

* return all

* fix: invalidate entries query after unsubscribe

* feat: implement imperative modal (#4041)

* feat: implement ImperativeModalProvider with modal context and controls

* fix: make onClose prop optional for bottom modal

* chore: add ImperativeModalProvider to context providers

* feat: wrap BottomModal content in KeyboardAvoidingView for better keyboard handling

* chore: add polyfill for Promise.withResolvers

* fix: wrap ImperativeModal in a View and update onClose to accept modal ID

* feat: implement ImperativeModal with context and modal control hooks

* refactor: redesign imperative modal with root-siblings

* fix: wrap BottomModal in a View to resolve rendering issues on Android

* refactor: replace Alert.prompt with modalPrompt for category creation and renaming

* fix(desktop): show login modal when auth fail

* feat: invalidate entry readability cache

* refactor: long press to open text select sheet for ai summary

* feat: new domain folo.is

* fix: enhance auth client with mobile-specific headers (#4064)

* feat(desktop): add missing i18n key (#4066)

* feat: update twitter handle

* docs: use google play badge

* feat: add hideAvatar prop to ProfileSettingForm for conditional avatar display

Signed-off-by: Innei <tukon479@gmail.com>

* docs: update images

* feat(ssr): add Google Analytics tracking to index.html

- Integrated Google Tag Manager for enhanced tracking and analytics capabilities.
- Added asynchronous loading of gtag.js and configuration for tracking ID G-DZMBZBW3EC.

Signed-off-by: Innei <tukon479@gmail.com>

* chore: Update Japanese Languages (#4078)

* chore: update ja.json

* chore: update 6 ja.json files

chore: update and bump 6 ja.json files.

* chore: update error/ja.json

fix locale/error/ja.json

* chore: auto-fix linting and formatting issues

* chore: update app/ja.json

* chore: update ja.json

* chore: update ja.json

* chore: update ja.json and tested local.

* chore: update ja.json

update settings/ja.json

* feat(i18n): update Japanese locale files with new error messages and dialog options

* chore(vscode): set default formatter for JSON and JSONC files

* Remove JSON and JSONC formatter settings

so sorry, @hyoban 😢

Perhaps my local settings are in. I have restored it to the original. Thanks for your kindness. 
You have always been a great help.

* chore: auto-fix linting and formatting issues

* chore: update ja.json

sync and update settings/ja.json

* chore: update Japanese translations for clarity and consistency

* chore: update some ja.json

* chore(locales): update Japanese translations with new entry actions and settings

* fix: update Japanese translations for user actions and login prompts

* feat(locales): add Japanese translations for login and registration features

* feat(locales): update Japanese translations for RSSHub and related settings

* chore: auto-fix linting and formatting issues

* feat(i18n): update Japanese locale with new toolbar customization and profile link social fields

* feat(locales): update Japanese translations for search results and two-factor authentication

* feat: 日本語ローカライズの更新

---------

Co-authored-by: dai <dai@users.noreply.github.com>
Co-authored-by: Innei <i@innei.in>
Co-authored-by: Innei <Innei@users.noreply.github.com>

* feat(desktop): real user deletion

* feat(mobile): real user deletion

* feat(settings): add accent color customization and update UI components

- Introduced accent color setting to allow users to customize the app's interface.
- Updated various components to utilize the new accent color, including buttons, sliders, and text elements.
- Added translations for accent color settings in English, Japanese, and Chinese.
- Refactored related styles in Tailwind CSS configuration to support the new accent color feature.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: update text styling for feed parameters message

* feat: use insertedBefore for mark above read

* feat(mobile): use insertedBefore for mark above read

* fix: improved lightbox component for iOS (#4089)

* feat: replace Image component with ProxyImage for improved performance and styling

* fix: update Image component style prop

* fix: improved layout in ImageItem component

* feat: integrate animated ref for media preview in EntryPictureItem

* fix: option can not be press when out of screen in the FlatList

* fix: lint

* fix: types

* fix: update lock

* fix: lint

* chore: auto-fix linting and formatting issues

---------

Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: Innei <tukon479@gmail.com>
Co-authored-by: Stephen Zhou <38493346+hyoban@users.noreply.github.com>
Co-authored-by: Whitewater <me@waterwater.moe>
Co-authored-by: lawvs <18554747+lawvs@users.noreply.github.com>
Co-authored-by: DIYgod <i@diygod.me>
Co-authored-by: Konv Suu <2583695112@qq.com>
Co-authored-by: dai <dosada@gmail.com>
Co-authored-by: dai <dai@users.noreply.github.com>
Co-authored-by: Innei <i@innei.in>
Co-authored-by: Innei <Innei@users.noreply.github.com>
2025-07-07 16:55:37 +08:00

119 lines
3.1 KiB
TypeScript

import fs from "node:fs"
import path from "pathe"
import { parse } from "svg-parser"
const DIST_DIR = "apps/mobile/src/icons"
const DEFAULT_COLOR = "#10161F"
interface SvgNode {
type: string
tagName: string
properties: Record<string, any>
children?: SvgNode[]
}
const generateElement = (node: SvgNode): string => {
const props = Object.entries(node.properties)
.map(([key, value]) => {
const camelKey = key.replaceAll(/-([a-z])/g, (_match, p1: string) => p1.toUpperCase())
if (
["stroke", "fill"].includes(key) &&
(!value || value === "currentColor" || value === DEFAULT_COLOR)
) {
return `${camelKey}={color}`
}
if (typeof value === "number") {
return `${camelKey}={${value}}`
}
return `${camelKey}="${value}"`
})
.join(" ")
const tagName = `${node.tagName.charAt(0).toUpperCase()}${node.tagName.slice(1)}`
return ` <${tagName} ${props} />`
}
const isPureBackgroundPath = (node: any) => {
return (
node.tagName === "path" &&
node.properties.fill === "#fff" &&
node.properties["fill-opacity"] === 0.01 &&
node.properties.d === "M24 0v24H0V0z"
)
}
const supportedTags = new Set(["path", "circle"])
const convertSvgToRN = (svgContent: string, componentName: string) => {
const ast = parse(svgContent)
const svgNode = ast.children[0] as SvgNode
const { width, height } = svgNode.properties
const pathElements =
svgNode.children
?.filter((child) => supportedTags.has(child.tagName))
.filter((child) => !isPureBackgroundPath(child))
.map((node) => generateElement(node))
.join("\n") ?? ""
return `import * as React from "react"
import Svg, { Circle, Path } from "react-native-svg"
interface ${componentName}Props {
width?: number
height?: number
color?: string
}
export const ${componentName} = ({
width = ${width},
height = ${height},
${pathElements.includes(`{color}`) ? `color = "${DEFAULT_COLOR}",` : ""}
}: ${componentName}Props) => {
return (
<Svg width={width} height={height} fill="none" viewBox="0 0 ${width} ${height}">
${pathElements}
</Svg>
)
}
`
}
const processFile = (filePath: string) => {
const svgContent = fs.readFileSync(filePath, "utf-8")
const fileName = path.basename(filePath, ".svg")
const componentName = `${fileName
.split("_")
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join("")}Icon`
const rnComponent = convertSvgToRN(svgContent, componentName)
const outputDir = path.join(process.cwd(), DIST_DIR)
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true })
}
const outputPath = path.join(outputDir, `${fileName}.tsx`)
fs.writeFileSync(outputPath, rnComponent)
// eslint-disable-next-line no-console
console.log(`Converted ${filePath} to ${outputPath}`)
}
// 处理整个目录
const processDirectory = (dirPath: string) => {
const files = fs.readdirSync(dirPath)
files.forEach((file) => {
if (file.endsWith(".svg")) {
processFile(path.join(dirPath, file))
}
})
}
processDirectory(path.join(process.cwd(), "icons/mgc"))