Skip to content

Commit

Permalink
feat: flutter
Browse files Browse the repository at this point in the history
  • Loading branch information
junghyeonsu committed Mar 22, 2024
1 parent ba28fa2 commit 7d5cc94
Show file tree
Hide file tree
Showing 14 changed files with 1,568 additions and 5 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
"license": "MIT",
"author": "junghyeonsu <[email protected]>",
"workspaces": [
"packages/types",
"packages/utils",
"packages/generator",
"figma-plugin"
"packages/*",
"figma-plugin",
"test"
],
"scripts": {
"build": "ultra -r build",
Expand Down
2 changes: 2 additions & 0 deletions packages/generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@
"@svgr/core": "^8.0.0",
"@types/cli-progress": "^3.11.5",
"cli-progress": "^3.12.0",
"opentype.js": "^1.3.4",
"pdfkit": "^0.13.0",
"svg-to-pdfkit": "^0.1.8",
"svg2vectordrawable": "^2.9.1",
"svgo": "^3.0.2"
},
"devDependencies": {
"@types/opentype.js": "^1.3.8",
"nanobundle": "^1.6.0",
"prettier": "^2.8.8",
"typescript": "^5.1.3"
Expand Down
102 changes: 102 additions & 0 deletions packages/generator/src/core/flutter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import type { GenerateDartConfig } from "@icona/types";
import {
deleteAllFilesInDir,
getProjectRootPath,
makeFolderIfNotExistFromRoot,
} from "@icona/utils";
import { readFileSync, writeFileSync } from "fs";
import type { GlyphSet } from "opentype.js";
import opentype from "opentype.js";
import { resolve } from "path";

interface GenerateDartFunction {
config: GenerateDartConfig;
}

const dartTemplate = ({
glyphs,
fileName,
fontFamily,
}: {
glyphs: GlyphSet;
fileName: GenerateDartConfig["fileName"];
fontFamily: GenerateDartConfig["fontFamily"];
}) => `/// To use this font, place it in your fonts/ directory and include the
/// following in your pubspec.yaml
///
/// flutter:
/// fonts:
/// - family: ${fontFamily}
/// fonts:
/// - asset: fonts/seed-icon.ttf
///
///
///
import 'package:flutter/widgets.dart';
class ${fileName} {
${fileName}._();
static const _fontFam = '${fontFamily}';
static const String? _fontPkg = null;
${new Array(glyphs.length)
.fill(0)
.map((_, i) => {
const glyph = glyphs.get(i);
if (i === 0) return null; // NOTE: There is no glyph at index 0
if (!glyph) return null;
const code = glyph?.unicode?.toString(16);
const name = glyph?.name;
return ` static const IconData ${name} =
IconData(0x${code}, fontFamily: _fontFam, fontPackage: _fontPkg);`;
})
.join("\n")}
}
`;

/**
* @description SVG 폴더를 기준으로 폰트 파일들을 생성합니다.
*/
export const generateDart = async ({ config }: GenerateDartFunction) => {
const {
genMode,
path = "flutter",
ttfPath,
fileName = "SeedIcons",
fontFamily = "SeedIcon",
} = config;

const projectPath = getProjectRootPath();

const resolvedTtfPath = resolve(projectPath, ttfPath);
const resolvedDistPath = resolve(projectPath, path);

if (!resolvedTtfPath) {
console.error(
`\n[@Icona/generator] Dart File need ttf file. Please check ttf file path or You can generate font file with font option`,
);
return;
}

if (genMode === "recreate") {
deleteAllFilesInDir(resolve(projectPath, path));
}

console.log(`\n[@Icona/generator] Dart Generate in \`${path}\` folder...`);

const { buffer } = readFileSync(ttfPath);
const ttf = opentype.parse(buffer);

const template = dartTemplate({
glyphs: ttf.glyphs,
fileName,
fontFamily,
});

// make dart file
makeFolderIfNotExistFromRoot(path);
writeFileSync(resolve(resolvedDistPath, `${fileName}.dart`), template);

console.log(`\n[@Icona/generator] Dart Generate Success!!`);
};
45 changes: 45 additions & 0 deletions packages/generator/src/core/font.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { GenerateFontConfig } from "@icona/types";
import { deleteAllFilesInDir, getProjectRootPath } from "@icona/utils";
import { resolve } from "path";
import svgtofont from "svgtofont";

interface GenerateFontFunction {
/**
* @description Icona icons data
* @default .icona/icons.json
*/
config: GenerateFontConfig;
}

/**
* @description SVG 폴더를 기준으로 폰트 파일들을 생성합니다.
*/
export const generateFont = async ({ config }: GenerateFontFunction) => {
const { genMode, svgToFontOptions } = config;

const projectPath = getProjectRootPath();

const src = resolve(projectPath, svgToFontOptions?.src || "svg");
const dist = resolve(projectPath, svgToFontOptions?.dist || "font");
// NOTE: css 옵션을 넣어주지 않으면 error가 throw됨
const css = svgToFontOptions?.css || false;
const name = svgToFontOptions?.fontName || "icona";

if (genMode === "recreate") {
deleteAllFilesInDir(resolve(projectPath, dist));
}

console.log(`\n[@Icona/generator] Font Generate in \`${dist}\` folder...`);

const options = {
...svgToFontOptions,
name,
src,
dist,
css,
};

await svgtofont(options);

console.log(`\n[@Icona/generator] Font Generate Success!!`);
};
6 changes: 5 additions & 1 deletion packages/generator/src/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import type { IconaConfig, IconaIconData } from "@icona/types";
import { getIconaIconsFile } from "@icona/utils";

import { generateDrawable } from "./core/drawable.js";
import { generateDart } from "./core/flutter.js";
import { generateFont } from "./core/font.js";
import { generatePDF } from "./core/pdf.js";
import { generatePNG } from "./core/png.js";
import { generateReact } from "./core/react.js";
Expand All @@ -11,7 +13,7 @@ export const generator = (
icons: Record<string, IconaIconData>,
config: IconaConfig,
) => {
const { pdf, drawable, react, svg, png } = config;
const { pdf, drawable, react, svg, png, font, flutter } = config;

const generate = async () => {
console.log("[@Icona/generator] Start generating...");
Expand All @@ -21,6 +23,8 @@ export const generator = (
if (pdf?.active) generatePDF({ icons, config: pdf });
if (drawable?.active) await generateDrawable({ icons, config: drawable });
if (png?.active) await generatePNG({ icons, config: png });
if (font?.active) await generateFont({ config: font });
if (flutter?.active) await generateDart({ config: flutter });

console.log("\n[@Icona/generator] Finish generating!!!");
};
Expand Down
3 changes: 3 additions & 0 deletions packages/generator/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { generateDrawable } from "./core/drawable.js";
import { generateDart } from "./core/flutter.js";
import { generateFont } from "./core/font.js";
import { generatePDF } from "./core/pdf.js";
import { generatePNG } from "./core/png.js";
import { generateReact } from "./core/react.js";
Expand All @@ -7,6 +9,7 @@ import { generate, generator } from "./generator.js";

export {
generate,
generateDart,
generateDrawable,
generatePDF,
generatePNG,
Expand Down
55 changes: 55 additions & 0 deletions packages/types/src/lib.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,65 @@ export interface GeneratePNGConfig {
path?: string;
}

export interface GenerateFontConfig {
/**
* @default overwrite
*/
genMode?: GenerateMode;

/**
* generate drawable PNG files
* @default false
*/
active: boolean;

/**
* @see https://wangchujiang.com/svgtofont/#options
*/
svgToFontOptions?: SvgToFontOptions;
}

export interface GenerateDartConfig {
/**
* @default overwrite
*/
genMode?: GenerateMode;

/**
* generate dart file
*/
active: boolean;

/**
* ttf file path
*/
ttfPath: string;

/**
* dart files path that will be generated
* @default flutter
*/
path?: string;

/**
* flutter className and file name
* @default SeedIcons
*/
fileName?: string;

/**
* flutter font family
* @default SeedIcon
*/
fontFamily?: string;
}

export interface IconaConfig {
svg: GenerateSVGConfig;
react: GenerateReactConfig;
pdf: GeneratePDFConfig;
drawable: GenerateDrawableConfig;
png: GeneratePNGConfig;
font: GenerateFontConfig;
flutter: GenerateDartConfig;
}
Loading

0 comments on commit 7d5cc94

Please sign in to comment.