Skip to content

Instantly share code, notes, and snippets.

@100lvlmaster
Created February 12, 2022 09:13
Show Gist options
  • Save 100lvlmaster/e5fd65684aad80a2ae78d0718e8b90bb to your computer and use it in GitHub Desktop.
Save 100lvlmaster/e5fd65684aad80a2ae78d0718e8b90bb to your computer and use it in GitHub Desktop.
A helper class to parse css styles from css text to appropriate flutter textstyles and buttonstyles. Also supports gradients
import 'package:flutter/material.dart';
class CssParser {
const CssParser();
///
static Color getColorFromHashCode(String colorCode) {
String color = colorCode.replaceAll("#", "0xff").toLowerCase();
return Color(int.parse(color));
}
/// Take [CSS] string and return TextStyle
static TextStyle cssToTextStyle(String css) {
final List<List<String>> cssArray = _cssLexer(css);
TextStyle textStyle = const TextStyle();
for (var e in cssArray) {
if (e[0] == 'color') {
textStyle = textStyle.copyWith(color: getColorFromHashCode(e[1]));
}
if (e[0] == 'font-weight') {
textStyle =
textStyle.copyWith(fontWeight: _parseFontWeight(e[1].trim()));
}
if (e[0] == 'font-size') {
textStyle = textStyle.copyWith(
fontSize: double.tryParse(e[1]) ?? 16,
);
}
}
return textStyle;
}
/// Take [CSS] string & return BoxDecoration
static BoxDecoration cssToBoxDecoration(String css) {
BoxDecoration boxDecoration = const BoxDecoration();
final List<List<String>> cssArray = _cssLexer(css);
for (List<String> style in cssArray) {
/// Parse background attribute of cards
///
if (style[0] == 'background') {
/// Css property is a [linear-gradient]
if (style[1].trim().startsWith("linear-gradient")) {
boxDecoration = boxDecoration.copyWith(
gradient: _parseLinearGradient(style[1]),
);
}
/// Css property is a [radial-gradient]
if (style[1].trim().startsWith("radial-gradient")) {
boxDecoration = boxDecoration.copyWith(
gradient: _parseRadialGradient(style[1]),
);
}
}
}
return boxDecoration;
}
static RadialGradient? _parseRadialGradient(String gradientstring) {
final List<String> valueArray = gradientstring
.replaceAll("radial-gradient(", '')
.replaceAll("[", "")
.replaceAll("]", "")
.replaceAll(")", "")
.replaceAll(" ", ",")
.split(",");
List<Color> colors = [];
List<double> percents = [];
for (String e in valueArray) {
if (e.trim().startsWith("#")) {
colors.add(getColorFromHashCode(e));
}
if (e.trim().endsWith("%")) {
final double? parsedVal = double.tryParse(e.trim().replaceAll("%", ""));
if (parsedVal != null) {
percents.add(parsedVal);
}
}
}
return RadialGradient(
center: Alignment(percents.removeAt(0) / 100, percents.removeAt(0) / 100),
colors: colors,
focalRadius: percents.removeLast(),
);
}
/// Parse [linear-gradient] from gradient css attribute
static LinearGradient? _parseLinearGradient(String gradientString) {
final List<String> valueArray = gradientString
.replaceAll("linear-gradient(", '')
.replaceAll("[", "")
.replaceAll("]", "")
.replaceAll(")", "")
.replaceAll(" ", ",")
.split(",");
List<Color> colors = [];
List<double> stops = [];
double degrees = 0.0;
for (var e in valueArray) {
if (e.trim().startsWith("#")) {
colors.add(getColorFromHashCode(e));
}
if (e.trim().endsWith("%")) {
final double stop = double.parse(e.replaceAll("%", "")) / 100;
stops.add(stop);
}
if (e.trim().endsWith("deg")) {
final double? parsedDegrees =
double.tryParse(e.trim().replaceAll("deg", ""));
if (parsedDegrees != null) {
degrees = parsedDegrees;
}
}
}
/// Linear gradient requires the stops to be
/// equal to the length of colors
if (colors.length >= 2) {
return LinearGradient(
colors: colors,
stops: stops.length == colors.length ? stops : null,
transform: GradientRotation(degrees),
);
}
}
/// Take [CSS] string & return ButtonStyle
static ButtonStyle cssToButtonStyle(String css) {
ButtonStyle buttonStyle = ButtonStyle(
foregroundColor: MaterialStateProperty.all(Colors.black),
backgroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
);
final List<List<String>> styles = _cssLexer(css);
for (var e in styles) {
if (e[0] == 'background-color') {
buttonStyle = buttonStyle.copyWith(
backgroundColor: MaterialStateProperty.all(
e[1].trim().length == 7 ? getColorFromHashCode(e[1]) : Colors.white,
),
);
}
if (e[0] == 'background') {
buttonStyle = buttonStyle.copyWith(
backgroundColor: MaterialStateProperty.all(
e[1].trim().length == 7 ? getColorFromHashCode(e[1]) : Colors.white,
),
);
}
if (e[0] == "color") {
buttonStyle = buttonStyle.copyWith(
foregroundColor:
MaterialStateProperty.all(getColorFromHashCode(e[1])),
);
}
}
return buttonStyle;
}
/// Split a css attribute to key value array
static List<List<String>> _cssLexer(String css) {
List<List<String>> values = css
.replaceAll("}", "")
.replaceAll("{", "")
.split(';')
.map((String e) => e.trim().split(":"))
.toList();
return values;
}
/// Parse [FontWeight]
static FontWeight _parseFontWeight(String fontWeight) {
switch (fontWeight.substring(fontWeight.length - 3, fontWeight.length)) {
case '100':
return FontWeight.w100;
case '200':
return FontWeight.w200;
case '300':
return FontWeight.w300;
case '400':
return FontWeight.w400;
case '500':
return FontWeight.w500;
case '600':
return FontWeight.w600;
case '700':
return FontWeight.w700;
case '800':
return FontWeight.w800;
case '900':
return FontWeight.w900;
default:
return FontWeight.normal;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment