From 035d7e8bf304b993f327432194040853439035a9 Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Fri, 14 Jan 2022 23:50:00 -0500 Subject: [PATCH 01/10] Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..81bc276 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# AnalogCSS +A CSS framework for people who hate CSS From dd64502e953b1ba751baed8b813f2f68b5217bbf Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Fri, 14 Jan 2022 23:53:57 -0500 Subject: [PATCH 02/10] Add files via upload I'm awake at 11:52 PM so I decided to upload my code to Github... --- AnalogCSS/CSSClass.py | 44 +++++ AnalogCSS/FindFiles.py | 16 ++ AnalogCSS/ShorthandClass.py | 169 ++++++++++++++++++ AnalogCSS/__pycache__/CSSClass.cpython-39.pyc | Bin 0 -> 1715 bytes .../__pycache__/ExtractClasses.cpython-39.pyc | Bin 0 -> 628 bytes .../__pycache__/FindFiles.cpython-39.pyc | Bin 0 -> 660 bytes .../IncorperateOldCSS.cpython-39.pyc | Bin 0 -> 1357 bytes AnalogCSS/__pycache__/Parse.cpython-39.pyc | Bin 0 -> 798 bytes .../__pycache__/ShorthandClass.cpython-39.pyc | Bin 0 -> 5031 bytes .../__pycache__/generate_class.cpython-39.pyc | Bin 0 -> 734 bytes .../__pycache__/get_config.cpython-39.pyc | Bin 0 -> 1424 bytes .../__pycache__/get_user_css.cpython-39.pyc | Bin 0 -> 1784 bytes AnalogCSS/__pycache__/lang.cpython-39.pyc | Bin 0 -> 203 bytes AnalogCSS/__pycache__/syntax.cpython-39.pyc | Bin 0 -> 244 bytes AnalogCSS/__pycache__/tools.cpython-39.pyc | Bin 0 -> 1668 bytes AnalogCSS/get_config.py | 29 +++ AnalogCSS/get_user_css.py | 70 ++++++++ AnalogCSS/syntax.py | 4 + AnalogCSS/tools.py | 51 ++++++ analog_config.json | 80 +++++++++ analog_css.py | 36 ++++ 21 files changed, 499 insertions(+) create mode 100644 AnalogCSS/CSSClass.py create mode 100644 AnalogCSS/FindFiles.py create mode 100644 AnalogCSS/ShorthandClass.py create mode 100644 AnalogCSS/__pycache__/CSSClass.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/ExtractClasses.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/FindFiles.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/IncorperateOldCSS.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/Parse.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/ShorthandClass.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/generate_class.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/get_config.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/get_user_css.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/lang.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/syntax.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/tools.cpython-39.pyc create mode 100644 AnalogCSS/get_config.py create mode 100644 AnalogCSS/get_user_css.py create mode 100644 AnalogCSS/syntax.py create mode 100644 AnalogCSS/tools.py create mode 100644 analog_config.json create mode 100644 analog_css.py diff --git a/AnalogCSS/CSSClass.py b/AnalogCSS/CSSClass.py new file mode 100644 index 0000000..b84c5cd --- /dev/null +++ b/AnalogCSS/CSSClass.py @@ -0,0 +1,44 @@ +class CSSClass: + """ + This class is used to store CSS classes neatly. + You can access property values like this: + >>> css_class.get("property_name") + >>> + """ + def __init__(self, name, attr_str = None): + self.name = name + self.attr_str = attr_str + self.attributes = dict() + if attr_str: + self.parse_attr_str() + + def parse_attr_str(self): + attrs = self.attr_str.split(";") + for line in attrs: + if line != "": + property = line.split(":")[0].strip() + value = line.split(":")[1].strip() + self.attributes[property] = value + + def get(self, property_name): + return self.attributes[property_name] + + def set(self, property_name, value): + self.attributes[property_name] = value + + def create_media_query(self, mq_type, breakpoint): + return f"@media ({mq_type}: {breakpoint}) {{\n{self.compile()[1:]}}}\n" + + def compile(self): + output = f".{self.name} {{\n" + + for key in self.attributes.keys(): + value = self.attributes[key] + output += f"\t{key}: {value};\n" + return output + "}\n" + + + + + + \ No newline at end of file diff --git a/AnalogCSS/FindFiles.py b/AnalogCSS/FindFiles.py new file mode 100644 index 0000000..aa06341 --- /dev/null +++ b/AnalogCSS/FindFiles.py @@ -0,0 +1,16 @@ +import imp +from AnalogCSS.tools import read_json +from AnalogCSS.get_config import get_input_extensions, get_input_paths +import os + + +def find_files(): + input_paths = get_input_paths() + extensions = get_input_extensions() + for dir in input_paths: + for root, dirs, files in os.walk(dir): + for file in files: + file_ext = "." + file.split(".")[-1] + if file_ext in extensions: + file_path = os.path.join(root, file) + yield file_path \ No newline at end of file diff --git a/AnalogCSS/ShorthandClass.py b/AnalogCSS/ShorthandClass.py new file mode 100644 index 0000000..13268d3 --- /dev/null +++ b/AnalogCSS/ShorthandClass.py @@ -0,0 +1,169 @@ +from AnalogCSS.get_config import * +from AnalogCSS.syntax import * +from AnalogCSS.CSSClass import CSSClass +from AnalogCSS.tools import NUMBERS +from AnalogCSS.get_user_css import GetUserCSS + +class ShorthandClass: + """ + This class determines how to interpret a shorthand CSS class. + I.E If the inputed shorthand class is 'p-2em', then GenerateClass would generate a CSS class that gives a padding of 2em. + If the inputed shorthand class is 'md:py-4em', then GenerateClass would generate a CSS class that gives a padding of 4em to + the top and bottom of the element, only after the medium (md) breakpoint is reached. + + The syntax for a shorthand CSS class is [optional breakpoint:]- + So if you wanted a CSS class to give a margin of 1rem to an element, + the shorthand CSS class would be: 'm-1rem'. If you wanted that class to only have an effect + at the small (sm) breakpoint, you would prepend 'sm:' to the shorthand class, like this: 'sm:m-1rem'. + + + """ + def __init__(self, shorthand_class: str): + + # The shorthand CSS class/class name + self.shorthand_class = shorthand_class + self.parsed_name = self.parse_name() + + # Gets the defined breakpoint values from analog_config.json + self.breakpoint_values = get_breakpoint_values() + + # Gets the class mappings from analog_config.json + self.class_mappings = get_class_mappings() + + # Gets any custom values the user made in analog_config.json + self.custom_values = get_custom_values() + + # Gets the predefined CSS that the user wrote. + self.user_css_classes = GetUserCSS(get_user_css_file_paths()).get_classes() + + self.media_queries = dict() # {"breakpoint": list()} + + + def is_shorthand_class(self): + return PROPTERTY_SEPERATOR in self.shorthand_class + + def breakpoint_exists(self): + return BREAKPOINT_SEPERATOR in self.shorthand_class + + def parse_name(self): + parsed_name = "" + for char in self.shorthand_class: + if char in SPECIAL_CHARS: + parsed_name += f"\{char}" + else: + parsed_name += char + return parsed_name + + def get_breakpoint(self): + """ + Gets the breakpoint of the shorthand class, if any, and returns its value. + """ + if self.breakpoint_exists(): + breakpoint_index = self.shorthand_class.index(BREAKPOINT_SEPERATOR) + breakpoint_shorthand = self.shorthand_class[:breakpoint_index] # Evaluates to xs, sm, md, lg, xl or custom values. + if breakpoint_shorthand in self.breakpoint_values.keys(): + return self.breakpoint_values[breakpoint_shorthand] + else: + return breakpoint_shorthand + + return None + + def get_shorthand_property(self): + """ + Gets the CSS property from the shorthand CSS class and returns its mapped value. + """ + property_shorthand = self.shorthand_class.split(PROPTERTY_SEPERATOR)[0] + if BREAKPOINT_SEPERATOR in property_shorthand: + property_shorthand = property_shorthand[property_shorthand.index(BREAKPOINT_SEPERATOR) + 1:] + + return property_shorthand + + def get_real_property(self, prop_shorthand): + if prop_shorthand in self.class_mappings.keys(): + return self.class_mappings[prop_shorthand]["property"] + + def get_shorthand_value(self): + """ + Gets the value from the shorthand class and returns it. + """ + if self.is_shorthand_class(): + value = self.shorthand_class.split(PROPTERTY_SEPERATOR)[1] + + # If the value was assigned in the "custom_values", then use the assigned value. + if value in self.custom_values: + value = self.custom_values[value] + + return value + + def get_unit(self, value): + for i, char in enumerate(value): + if char not in NUMBERS: + return value[i + 2:] + + def get_value(self, value): + # Evaluate fractions + if "/" in value: + slash_index = value.index("/") + for i in range(slash_index + 1, len(value)): + if value[i] not in NUMBERS: + expression = value[:i] + evaluated_value = round(int(expression.split("/")[0]) / int(expression.split("/")[1]), 2) + unit = self.get_unit(value) + value = str(evaluated_value) + unit + break + + # Otherwise the value is good + return value + + def generate(self): + + output = "" + is_media_query = False + + if self.breakpoint_exists(): + is_media_query = True + mq_type = get_media_query_type() + breakpoint = self.get_breakpoint() + + # This means the breakpoint is a custom one + if breakpoint[0] == "@" and breakpoint not in self.breakpoint_values.keys(): + breakpoint = self.get_value(breakpoint[1:]) + + + # self.media_queries[breakpoint].append() + output += f"@media ({mq_type}: {breakpoint}) {{\n" + + if self.get_shorthand_property() in self.user_css_classes.keys(): + # This means the user is adding a breakpoint to one of their classes. + user_class_name = self.get_shorthand_property() + user_css_class = self.user_css_classes[user_class_name] + user_css_class.name = self.parsed_name(user_class_name) + return user_css_class.create_media_query(mq_type, breakpoint) + + + + if not self.is_shorthand_class(): + return "" + + shorthand_prop = self.get_shorthand_property() + attributes = self.get_real_property(shorthand_prop) + if not attributes: + attributes = shorthand_prop + value = self.get_value(self.get_shorthand_value()) + + css_class = CSSClass(self.parsed_name) + + if type(attributes) == list: + for attr in attributes: + css_class.set(attr, value) + else: + css_class.set(attributes, value) + + compiled_class = css_class.compile() + output += compiled_class + + + if is_media_query == True: + output += "}\n" + + return output diff --git a/AnalogCSS/__pycache__/CSSClass.cpython-39.pyc b/AnalogCSS/__pycache__/CSSClass.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f2b23a17636ce7b10865ded3fef35aa00809c45 GIT binary patch literal 1715 zcmZux&2HO95Z>jFL@~0W_)yzT3lKpL;UU&BfFlTLU8Fa`fP1NcV!?2?He*VpcUJ|Z zP^Y+0Q3S9~g&!m@v8Mt(<=mT2omq*B9cPK19nQ|~%zX2a$<9tlV6@)-lYI0D`4?Yq z4;Nlu!Bo2-ekPo7dIj^nGa}qMC9#`={m$5)_z}#4j3_4~htrYEA99y_S9IiYpEs_^ z$mdNSz}ny~9>Ut>4|p5afbZ}QtSuX%Yl7p`)8jl*YW{Z^!T9AoQ&EbB2$ZQ3Jkmv^ zbRk6quInwKqKQa!K0CB$el4a^noOc3O$D4QWl;*LXVD)?J_Xl2yAY9vdylO5U@(YM zrI-zJcqa6-C-n(7Nyg$yymjl>8_(@k1G_Oy5rul7?!Y{Tsh)zUXhj&Q9FSBy?+L7K z<;bWa*WQv)K>3v1&|&Nw52KkN(ONR4rSW){Y7^pn_GYSuGMzG!O0e1^c8#Y*{=3AW z5;{t5h-|^K>i5ozvFPb++&huQnM}sxY;x8+nd$Rl()(eOP~UO@FGLI~dH~r=wBOKmYR)>fojMy!w=Z%rE--Qr4k;Uf&fD7zVB;S3kO>z0 z4u%ENVc@dY?#G0UdodAT8x!fyp~-*2@1k-* zxEu06h#)4-_^larEMRPBX-i5LY=U2`mjHzj+#kkCJu}Rf5 z$CpgcN@2n`QY05;kxlfMS?{K>r3JGWv&*TFv+r*e@puc|eZM;tM*1QHY)!90ftmnE ztm=acBqnbuk`<`@6sQbu71RdQ1uEOBy~?$f`Y*_WUhadvv4_NM4h=n=yHM$hw&Y{D zc<#Im<#(V!nbXY8{WHK2|UczRx2tj>0{>7dUgnqk=!vYSyfi`m(9C0jBjWdi9 zC*1piGQ#~Oii1CJ7sYs(oe9?2YSqbQ)3pV5^j!sTx?Vt=k1#Ci!S9xAu*J7%LwdX= zJM<1+Bpa{ywjL)ttmi$Pj~)AH zA(=74&`MET3fk)Cs^WsvRV4*28fAsDpj4b{VLPpilhu>~M`dMfGWvZ!8GW8TKY2>; z;0u6z@+BZ)izG=dM)A%4($+F*nKnWX!6=FY?RGf$&NB;FkS~XLSy(cYGi&uQVQniE zkArOHvgQA?WxjzOX3=PqkB=V-DQd_)O!ATaiS!Ye|2<2~rWUEK>hxSUYt8DqQtR~m z+Lnz<-zp}X^<~d<%?i8NFDYrShlgTM?VW}3-FG^Mfr1E6$P`C-ibMPW>wCa` jioMMHYEH+O8<{c5!3aS$gs<8ivDk~u_+#^*Ri4zB?pr9VBij_D-pjA|7cfBNW)^?$lk`sIZ zU$A@RcR2cl#Hqi)1;(kMJJvkU8)=?BW9NH&BOv?s<7XZ-fM1^M8s*?6xp_t)Kwt@( z-&u(j%NY8Ym%IwHpbE3F=U7HrBmxnBg=`>j3Q2TB)o_-e8|oq#vz1YG!rXXK*qN-G zOFJvBY*8DjYUB3rvQ2K6=EB$hvmpfoa-TFy0t;WD1B-;%!W;PTwqurUc+0j(?BqS~ zco%eG8xnikMFQJs6A0X*V2|Mubc1%#;wR8YmaW1~)bcjkvMz4pcYv@yT0dDI2%sML znZwD=AF^bi13FoA0>_kb!RNgE=t9$!(z?K3+65~m>tvYSyKS#;#Eo{k)ers`FAU zUQeex(W$J(saKyg*KRZ?HuI{+57Kx|z=&3iWAa1t2dKxCP2!Bps&V`OMJHCN(rEuH u-1si*U+hBFbGhh;ayuTc-plmY-hqd{I(}X$aak6}NX*0pG2X`mjQL-G!K^<3 literal 0 HcmV?d00001 diff --git a/AnalogCSS/__pycache__/IncorperateOldCSS.cpython-39.pyc b/AnalogCSS/__pycache__/IncorperateOldCSS.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..639ebd4e715998cba36840fd0f2ef45559802058 GIT binary patch literal 1357 zcmZ9M&2AGh5XWt=ce6=b3KbFsaqyv+Ae0>8fGSX-h)bzx4`>C7RLFX+LgOwzb z=A@trrPyXUD}p5O?I7nxn1s;gGW+wk2cP1{=%H9_cRq1uvva8?IF?)6L0P9ZRM#kLyF7hPXHFn78KKiO46D-@}7JbHFHd|LuQ_X4Gx(WlpMWq)Uj8j zrbn@(5R;z`Is%@L${JzEN(?cCDAPiTk**3D%Z$jgQoR%tT^(mqNnEFufbn#`T&hu4 zW;Uxz0l&p3-g85)sc7hr-=rHf96dE1A7p?*8a^DSTF0<+UtNFbkE=rUZC3Pmb#BB@^;{oA!vWdDpjrdVo)YBg>5YAkUzDBd(ujRM1ui2GazP8D zBCHAw&^Z}r!|{R~jC*)Wz7!R5J;{s`dhTyK&5i2$5ITfSXxvsqdmdGn>Nbuo*lA3w zd6b!X;^5e)yavMtlObHMLVYh$bb+pYqQ9VFA=Psb5eSJ{dQR#q+ci_WRulpNM^Y}et@hGTleMX=&^-Eu7%g6xiM=t9TOSslCJB69I1UXZy@i~_RU zaNM;(mi%ZN+5w=A&c5CXGtF}W2Rl=nGBaf^0OJJ_X(<=jfMX$2lxLn9E2EU zs2TI71vDz5HJNf@$mll#%W*wHA7f=x% zbIu~hLB|h*H~>vE2E7>G4(&jn`?+PNpTO#!Zo6TX(Wr)Ib#a?|wyJXDK_qLpqc_w% lg&7ajkN0$EcV2*Ad-0p1lG9vmqD~F|cP>+SgLpZP{sH^oPI~|V literal 0 HcmV?d00001 diff --git a/AnalogCSS/__pycache__/Parse.cpython-39.pyc b/AnalogCSS/__pycache__/Parse.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e426e5b1c6f723a191c6a1f29d13c434074aeaf2 GIT binary patch literal 798 zcmZ8f&1xGl5FYK1v)$TFPo*uT_+9uGOG5EGngu0UL4cc8>l0##hlk*_< zF|V}HQ%`w?o;ssVz;s|nqxsX!Hxh$E3P|@4zr}d~@P{tP6yoIzvVD(2f@B&hmNN$5 zK?X9s0~zjuJdn{8viJdGAY<*|n-XhR&enR`td|8@j|t!DYQ957LCz##1tx<#$U_;* z2+v5ySh3gkCc;={3d(sR(y6ZtWcwP0gDsP67i@tu7wiDfPy*%$K!6caV_tR+6RBGhPYBVv;+=!|w z>-lJM;}%Ul`dSO!%rB1h78aoOZ(vpS%Sl&m+-%7VmWVVk2*bA28v?+VZHm@Eh{x5i(#e`8UD#dx5a$YrZjVs`7pYzpP=+0y4ubKe~ uDt{!X1w)7tdw>&`MBXya!aV$GKl;^s%Tb;$e((>;HMEle literal 0 HcmV?d00001 diff --git a/AnalogCSS/__pycache__/ShorthandClass.cpython-39.pyc b/AnalogCSS/__pycache__/ShorthandClass.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..148c78097e738e6f7018fd093973928436f1cd41 GIT binary patch literal 5031 zcmb_g%WvGq8J{7!yIg8_CCj!HJ5Ir*N#spsDGkyTH3GwrD6Y{~Q7!pUHUUfRP}15< zay^{2tu1v@nnO>$rvX;S0Qoz5>>t2Wfu4Np*{A-#;l5?GC{QjqkB{^CzTfwn*`Qu` z7@li?|3~oh4aWXSo$1F!=QiH-a}bjL7s%PBgP)MJ2DK+g7I>RlEvk z_n9b(^4Cn1PYur&m0i}fUt%rR#_g*JRQ?x7FkA8D^>)|e%&izn5N<)dS zEgC-kjG2l-4VlLU^9;c~Gqi;9S1wFpeQkNAVq>o?D#HGnc@<_ zM=XjZ)C=N*SVmnF7sVyib#Ym&pl*m&@doNeaRtm@%^SN%iBv~HEHvA}GT3okJbOp& z)NPR{t_W2qqjnso?osmGRf*eRVy%1QqcB=qr*W}+Ka4{es8BQGK2Lfb;T{fY*lWB4MhD70Y(E1}f!hs)Xvc?c za^PaE;qL!^=SbY_9^d%*|F}EWB6zg;B)3YsE}(Vy6Qz=f_#uwTvj@{q@ zSZaC{igqt@uScTk?#nQE(oF!g3y{!h9fhKhY^a{lO^;(0yl@W^`Fb_b%-<(n)lTA| zGqvK)uRiU{q#H_geCx)i&w@@byrmc2g=P=j<451?T&i+G~(1}zHYVLK*ieku!r zgLo{|SoYW0#ZaO9;Z1ifxi{-TGz(l(t@Lx-#n`@*QJ!@>RdY^T-(|!U~!QR0Z297v$^j5ln3onl4 z@%6NpG3CV6ruQD+^fMG0&zR3LHsEI{eM6b2R9mW~>$0lo+E!KNoU&6sSkU8Ys;=n` z!FJjAe7m_QD_AXex`9kXKMtZWU(jt)bS@u;%AeSZua%kR7tWKGX{6@dkAiL&?vmz> zx&8$`rkBE2M=RA^(_L92ZdPen58=#jrKx|=?u33fP)BLLFy13f^QG|!y$dLoXt$JC zCo>QHr@c_N!?bDSRvLB=w4C2Fxq=N|-Q7G&qHt5Sqs<+e9LgX<^f}zzIaWtWym<%K zoE#z)OtogC*hcp_w|&1Ix0UZ-#)@eJ1vAUsF>U=@GWx4?b4KG^oW>3xYL695$wfhp zkNGpGN80Fu{fj#fzu4K^dbsyHe|KwV>*1ZfFCG@sa7lY>k&0p!-F&&7`g6AQ0qCi= zC*FU1j;-^f|5pYt-F>)q=T|#lJlNiw<4|6G4S& zQjjECio0mQuh|)sx5yL*@a?lgDlT}&|72WYBpJS0gVGs;d^f3`fxgQ!V;2}eCZqqQ zjx3aF?}sYYk!b?vC{>INrAVyn6rY3mcwJ`|B zCyqal<_h65#@ZiExR2>61sY~8!D?5G{(G;%^ZdMX*=cOQF4m&#M96CEyhiN|_!7pj zPP|QHJGVzHKnRMS^2aDf0yXI4gxz^zbRNN(r8Ab}x0sxgZW-*NKOaO$_L<@5%wo(w z1(BiqeF(;f?pK(H7R!QxtmBJCA|cqoC-U*I9&4S#wS{@hA&+IRjsGZ=$Y`H@gF2B ze#$AO=5T{w5RFsc}+*MO8A| zp{(qzbjq{xDr|?dr{6rqim;y2_A9=r)vkSCu7ka1Rg#nEB^ktrVQzN9SR(~O(u+lI z;_zPB#U>3iQze^~35ec8irdvu5pv}QhImf+0w>lq#ev;h3`xPb3W?$<=2-;nJmOVC zQd`0y7Dz9lV1|thw}Kd4;~$_^<7Kn|#%oNeFd&LzqoyR5J5hChW{YS^cg= z=^o?CbohN-(KDGG6cp0R<4RV77nebSUe2HwznYZ?PG)A-8N3>F9Guf1D5VZ(RZ!Qm z3ih)zJN;W$K~0>nLH&$@T2&3KYoGEHM=fTk)zTB=FI-xg4QpCDS;(Bhg=`_Ko*B^p zzv7zi+eIJkWk_9v#nm+LhA{Q)k06_)DP%1R+ww<%@$)@xEU)-&Z8?4Wwm$m0*Zamz zw{JDwKRSKm#A#mCsXD(zx||%2k9~EFJKDQgNGEL_faNFDU8CY66~(EC?gid*3n5g6 z(<>D5sYwHWLIp+9+@fW3tAmprY%)}NrIkco9O9dGZJc>I=_y>-y#|h+Q|x$^=&5EY zcP3fiTP#lb^gn^Vk$8>SW53s!O-{KJC?(tb_&Xq#6id7+T_SY6%`N)oHHQ3%f;w;V z2r|Wg1kW%#y@i4q7Pnya7B6$#yvmoY6=PX@0ek@Al)gFmYVn5Q7!7^;tAS=C%-ZKK z0;Bb}n@eyT74{tfj(8(jbZ literal 0 HcmV?d00001 diff --git a/AnalogCSS/__pycache__/generate_class.cpython-39.pyc b/AnalogCSS/__pycache__/generate_class.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f005e2846602338b8cba6b5fe1369ab5fcad1c7f GIT binary patch literal 734 zcmaJ<7b-Sn?GF`v!s|qqi(T#w@jPNz@M!TJnX6)|xfkg7x1CN#O|HgxZ(TWW|wp~;!S!c>DSM=#%1J5=P zJ7_y-hFszIATH2#ksHU&vd$bYa&3mO3#Z%MilZWlcXckZr3)_8Vv!{sxiIy@>_ka> zcb->gQbj%`_cfDPo77}wR+;Za-N*Rm)%aYN+1TXe_*BWcO3M--K0aNVb6Jg#wjCZ% zCVRViR%Hsa>?)1wrR)70@(?1dk$_EoU}{R5JLxL5!H literal 0 HcmV?d00001 diff --git a/AnalogCSS/__pycache__/get_config.cpython-39.pyc b/AnalogCSS/__pycache__/get_config.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d3e3b9eda79499de363b42cce6954a78450338cb GIT binary patch literal 1424 zcmb7D&2H2%5Vn)-|7QQI3f^EZ-4{R=s8>`~+FLG>iQQ}(yg*-vV@^n% zcm+<(WK(KNwhrX-^QrGz_y zBV6u&rQGA4TQBe$)a5-uod)&!08qCm)wIJ#gqMVM>)p=x+}Pzy(Y_24je! zUnr+92*h?SgZVoM`=O9YZo*G2Erq^w6rQL?hv?yTl8QT`y0BN9U+0^h%*4hd+2%^g zSg|Zi@_2K#H#?bc-qg}Awp(iz3v;iv*jFbA|Do-mLL??s^})8g#w1Fa)?vnq0<>u5 zL4*g%hgA>uszt5kFK1-CXCAa>_M=i8nKj8fPCT!PZQqf_iCPN%|=Yc;dv|(tyR;PQyx;rYNDZY!%0| zutX8o5!Af01o&+QRHGzE{{LKlioBNRsl_>M%NfiLk;IJ=xlUyMOxEjXf9(F!VxPhK za_v{sKRtV9q)c_){|Xzj@^})Nx*rv`hQc~kSS||Rt8%qb3KOUBCJF;S*>(L_ndD_E T&MA241(>npITQEc>$|@J>e(Op literal 0 HcmV?d00001 diff --git a/AnalogCSS/__pycache__/get_user_css.cpython-39.pyc b/AnalogCSS/__pycache__/get_user_css.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d91528d0a7a4e46593b202d938b3006c4dd16ca3 GIT binary patch literal 1784 zcmZ`(OOM+&5GE^Bb< z$I$gN7z7bCCk2fu#W~Aa;l&;$FNyF3e@6trW-%B3IT`mpfIJyfJ5Vwe$vn#?EP|8s z^OHQ)dWNU_jltp=x;}zIl9&n-GeHG=M`Ewlj+#Xe*1qVA0KPpj0860_U&{JBEfpxA zp`KmCIrbCidIW=^h9sn>*95*y5V%dx#-6>uhTF+ZYv-r7Tx7G_KJ0d9=(5yfX1SL6 zT=}5uccK6<^6_}Os0ul)vts&6RTnBPimbetzIt0Ps&e{unda36IJP&tkae<_TVl9(PB-UKFsHq6j($oEm>8BefFrk}#syJRY& zWcAE2<2@%0TLp$e=zMb#M%xCqbW|^7pG&@+Ulf)8MEwa8|R4ky@mP)TtVRfytMre&nI`cBha%SmTOVQh-R zVCkeqjydGi13WbNF6tQ z(-%Ha@|W5-zJZF-1SSA0Jp->>^nV7>UqEeX^`kAI?xEqP57gzWv(@1W?7Zm#frHHt z9a<0|@G;LLcxx>yrEVGAr3PzIl$N3c95PTuDbhI4bRAW5ynKRhy;FPYvS4ZW+S29& z0(Ca-yZ5gUTI=g&p4AF@qp-p#4~ISs<79PG+U9PA!_e6UQFmTkV`C$qIuvfPmz z++9jlXHv(byC?WY+T1?^{dRzg-NX1N7Y;h&OZ^3iy4p?rkOrJH4)5f?7kZqAl));1 zUr0x=-k!0|<2|yQq; FzX8aBvEl## literal 0 HcmV?d00001 diff --git a/AnalogCSS/__pycache__/lang.cpython-39.pyc b/AnalogCSS/__pycache__/lang.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e6bc3c8a7f6c7b4ff1147beb63bb6010953aae5 GIT binary patch literal 203 zcmYe~<>g`kf~ivX6HS2hV-N=!FakLaKwQiNBvKfn7*ZIc7*m*n88n%HF<>g`kf{3~Yi4j2hF^Gc<7=auIATAaF5-AK(3@MCJj44b}OexI444N#z7_ELW z+ExiDIw-5C#;Iv(XlmQ)Tj}ZeX);HNI0d;ndI$J>`h~;?y9T%hIfnQLMF|H4`3Ho! z28Bc-1aI*M2e>+WI{L&rdpHIKuVg4<0on#8ep%^f<|XFjr#lA+Be9Ar^GXsc^a?6(aoFVMr
  • S#&=lAT`KmXo`Y&IhT0G`_2dA z1Ki{({LCH*OV;#+tVl@?nWBm*Pw`&?UrE*;_-RQGx!F~IpWqDc4SGxVQL$`4U)cG= z#!vhGcr?w@PE{)w7H0{o_$1Bdf~(ZnWh8T%730p(n8dF_smF7vO)6TC^>{H$b9;cM z77eM?09Kt(L~aw>Mst9fFcCPHt~feRi4MX2*Te3ln5A7iopld%G1hW6o95&0!I7O5 zdH1oq8X#Vn*`mlyXMR+Lc~X{1fd~q(~t#}Q;l&RQuLk;qz>0!fM< zv)^tZO-SRngh60Ae8)gxpWGwn!#zUX_Z>(DzJ&EEs*$8(p5_(TsZ^(6&83}GbmX43 z5s0g*R6lksmrMUh*|p?1bvL z1brL5H&=e?m)=iQ@0Z>h<|mYr*ZZ&I(nBVC%bkgxWt~k03xAkN=mvpHVvR{$@oZ|W z2uD*0mdr8{PNW$~YjqWDLYM><$0`s_l!J511UJz0MC48!xI=1bmSSJ2f`RkCP0kIh zd$*FB!AKV~ml_`c3WFsEO~8+6z#24yItytF-U;5Mp^+?o8-(zFH1{2D(cZS0jycM$ z{8`j`-+cY#%NKpuKsGPL{MVRmE&%Sh3!q%=T&;(XW`$a0>F1b~<~ dict: + return read_json(config_file)["breakpoint_values"] + +def get_class_mappings() -> dict: + return read_json(config_file)["class_mappings"] + +def get_custom_values() -> dict: + return read_json(config_file)["custom_values"] + +def get_media_query_type() -> dict: + return read_json(config_file)["media_query_type"] + +def get_user_css_file_paths() -> dict: + return read_json(config_file)["user_css_file_paths"] + +def get_output_css_path() -> str: + return read_json(config_file)["output_css_file_path"] + +def get_input_paths(): + return read_json(config_file)["input_paths"] + +def get_input_extensions(): + return read_json(config_file)["input_extensions"] + + diff --git a/AnalogCSS/get_user_css.py b/AnalogCSS/get_user_css.py new file mode 100644 index 0000000..e29e192 --- /dev/null +++ b/AnalogCSS/get_user_css.py @@ -0,0 +1,70 @@ +from AnalogCSS.tools import read_file +from AnalogCSS.CSSClass import CSSClass + + +class GetUserCSS: + def __init__(self, user_css_files): + self.user_css_files = user_css_files + self.user_css_classes = dict() + + def get_class_name_from_line(self, line): + """ + Gets the class name from this line, provided there is a class definition on this line + """ + class_name = "" + for char in line: + if char == " " or char == "{": + break + + class_name += char + return class_name + + def is_class_def_line(self, line): + """ + Returns True if the provided line is one on which a class is defined, otherwise returns False. + """ + return line != "" and line[0] == "." + + + def get_classes(self): + """ + Gets all CSS classes from provided file and returns them as a list of CSSClass + """ + + for css_file in self.user_css_files: + user_css = read_file(css_file) + + """ If parse_class is True, that means the program found a CSS class name, + so it should grab all the properties under it (in that class) """ + parse_class = False + + current_class_properties = "" + current_class_name = "" + + for line in user_css.split("\n"): + + # This means the program found a CSS class + if self.is_class_def_line(line): + """ Since the program found a CSS class, set parse_class to True so next + itteration start adding the class properties to the current_class_properties list """ + parse_class = True + current_class_name = self.get_class_name_from_line(line) + continue + + if parse_class: + for char in line: + if char == "}": + css_class = CSSClass(current_class_name, current_class_properties) + self.user_css_classes[current_class_name[1:]] = css_class + + # Reset the current class attributes to nothing + current_class_properties = "" + current_class_name = "" + + parse_class = False + break + + current_class_properties += char + + return self.user_css_classes + diff --git a/AnalogCSS/syntax.py b/AnalogCSS/syntax.py new file mode 100644 index 0000000..fec2a75 --- /dev/null +++ b/AnalogCSS/syntax.py @@ -0,0 +1,4 @@ +BREAKPOINT_SEPERATOR = ":" +PROPTERTY_SEPERATOR = "=" + +SPECIAL_CHARS = "!@#$%^&*()+=/:.," \ No newline at end of file diff --git a/AnalogCSS/tools.py b/AnalogCSS/tools.py new file mode 100644 index 0000000..c3da868 --- /dev/null +++ b/AnalogCSS/tools.py @@ -0,0 +1,51 @@ +import argparse +import json + +from bs4 import BeautifulSoup +from AnalogCSS.syntax import * + +NUMBERS = "0123456789" + +def get_args(): + parser = argparse.ArgumentParser() + parser.add_argument("-o", help="Output CSS file.", dest="outfile") + args = parser.parse_args() + + if not args.outfile: + return "analog.css" + return args.outfile + +def read_file(path): + with open(path, "r") as f: + return f.read() + +def write_file(path, content): + with open(path, "w") as f: + return f.write(content) + +def append_to_file(path, content): + with open(path, "a") as f: + return f.write(content) + +def read_json(path): + """ + Reads a JSON file and returns the contents as a dictionary + """ + with open(path, "r") as f: + return json.loads(f.read()) + +def get_classes_from_file(file): + file_contents = read_file(file) + """ + Finds all classes in the provided file contents and returns them as a list. + ['class-1', 'class-2', class-3', etc...] + """ + soup = BeautifulSoup(file_contents, "html.parser") + class_list = list() + + for element in soup.find_all(): + if element.has_attr("class"): + for _class in element["class"]: + if _class not in class_list: + class_list.append(_class) + return class_list \ No newline at end of file diff --git a/analog_config.json b/analog_config.json new file mode 100644 index 0000000..257a872 --- /dev/null +++ b/analog_config.json @@ -0,0 +1,80 @@ +{ + "user_css_file_paths": ["app.css"], + "output_css_file_path": "analog.css", + + "input_paths": ["./"], + "input_extensions": [".html", ".php"], + + "custom_values": { + "dark_red": "rgb(255, 50, 50)", + "col": "column" + }, + + "media_query_type": "min-width", + + "class_mappings": { + "p": { + "property": "padding" + }, + + "px": { + "property": ["padding-left", "padding-right"] + }, + + "m": { + "property": "margin" + }, + + "mt": { + "property": "margin-top" + }, + + "mb": { + "property": "margin-bottom" + }, + + "mx":{ + "property": ["margin-left", "margin-right"] + }, + + "max-w": { + "property": "max-width" + }, + + "min-w": { + "property": "min-width" + }, + + "w": { + "property": "width" + }, + + "h": { + "property": "height" + }, + + "bg": { + "property": "background-color" + }, + + "flex-dir": { + "property": "flex-direction" + }, + + "justify": { + "property": "justify-content" + }, + + "align": { + "property": "align-content" + } + }, + + "breakpoint_values": { + "xs": "300px", + "sm": "500px", + "md": "900px", + "lg": "1300px", + "xl": "1600px" + } +} \ No newline at end of file diff --git a/analog_css.py b/analog_css.py new file mode 100644 index 0000000..0285a7c --- /dev/null +++ b/analog_css.py @@ -0,0 +1,36 @@ +from webbrowser import get +from AnalogCSS.tools import get_classes_from_file, append_to_file, write_file +from AnalogCSS.FindFiles import find_files +from AnalogCSS.get_config import get_output_css_path + +import time + +from AnalogCSS.ShorthandClass import ShorthandClass +print("[+] Watching files") + +while True: + output_path = get_output_css_path() + try: + files = find_files() + + generated_classes = list() + + for file in files: + classes = get_classes_from_file(file) + + for _class in classes: + shorthand_class = ShorthandClass(_class) + generated_classes.append(shorthand_class.generate()) + + + write_file(output_path, "") + for _class in generated_classes: + append_to_file(output_path, _class) + time.sleep(1) + + except KeyboardInterrupt: + print("\n[+] Stopped watching files") + exit() + + + From 40d62caf9dae6625f050ad514ef0399d9259ff8e Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Sat, 15 Jan 2022 00:21:35 -0500 Subject: [PATCH 03/10] Commented code --- AnalogCSS/CSSClass.py | 49 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/AnalogCSS/CSSClass.py b/AnalogCSS/CSSClass.py index b84c5cd..6a74849 100644 --- a/AnalogCSS/CSSClass.py +++ b/AnalogCSS/CSSClass.py @@ -2,9 +2,18 @@ class CSSClass: """ This class is used to store CSS classes neatly. You can access property values like this: - >>> css_class.get("property_name") - >>> + >>> css_class.get("property_name") # Returns property value + + And you can set property values like this: + >>> css_class.set("property_name", "property_value") # Sets specified property name to specified value + + You can generate a full CSS class that contains all of the properties you set in this class using: + >>> css_class.compile() # Returns a valid CSS class as a string. + + You can generate a breakpoint media query using: + >>> css_class.create_media_query("mq_type", "breakpoint") # Returns a CSS class string inside of a media query """ + def __init__(self, name, attr_str = None): self.name = name self.attr_str = attr_str @@ -13,29 +22,51 @@ def __init__(self, name, attr_str = None): self.parse_attr_str() def parse_attr_str(self): + """ + Loops through the attribute string and identifies properties and their value. + Once properties and values are found, add them to self.attributes + """ + + # This splits the attribute string into individiual attributes since a CSS attribute is defined as : ; attrs = self.attr_str.split(";") + + # Loop over each of the attributes and get the attribute name and value. for line in attrs: if line != "": - property = line.split(":")[0].strip() + property = line.split(":")[0].strip() # value = line.split(":")[1].strip() - self.attributes[property] = value + self.set(property, value) # Set the new property name to the new value. def get(self, property_name): + """ + Returns the value of the property within self.attributes + """ return self.attributes[property_name] def set(self, property_name, value): + """ + Sets the value of property_name to value within self.attributes. + """ self.attributes[property_name] = value def create_media_query(self, mq_type, breakpoint): - return f"@media ({mq_type}: {breakpoint}) {{\n{self.compile()[1:]}}}\n" + """ + Generates a media query breakpoint with the current class attributes within self.attributes. + """ + compiled_class = self.compile() + return f"@media ({mq_type}: {breakpoint}) {{\n{compiled_class[1:]}}}\n" # use [1:] because otherwise the CSS class would start with 2 dots instead of one def compile(self): - output = f".{self.name} {{\n" + """ + Generates a valid CSS class using the information provided in self.attributes and return it as a string. + """ + output_string = f".{self.name} {{\n" for key in self.attributes.keys(): - value = self.attributes[key] - output += f"\t{key}: {value};\n" - return output + "}\n" + # Loop over all of the set attributes and add them to the output_string. + value = self.get(key) + output_string += f"\t{key}: {value};\n" + return output_string + "}\n" From 640cc21de2c183c34ec1c5ce2779f41e0970e51c Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Sat, 15 Jan 2022 00:31:47 -0500 Subject: [PATCH 04/10] Commented code --- AnalogCSS/FindFiles.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/AnalogCSS/FindFiles.py b/AnalogCSS/FindFiles.py index aa06341..034199d 100644 --- a/AnalogCSS/FindFiles.py +++ b/AnalogCSS/FindFiles.py @@ -5,12 +5,19 @@ def find_files(): - input_paths = get_input_paths() - extensions = get_input_extensions() + """ + Function code inspired by: Stackoverflow user 'muon' https://stackoverflow.com/users/3130926/muon in answer: https://stackoverflow.com/a/41419432 + + Finds all of the files in the paths that you want AnalogCSS to monitor. + """ + input_paths = get_input_paths() # Get the file paths we want to monitor. + extensions = get_input_extensions() # Get the extensions of the files we want to grab. for dir in input_paths: + # Walk each path in input_paths and find any file that has an extension set it analog_config.json for root, dirs, files in os.walk(dir): for file in files: + # Check to see if the file extension is a valid one to check. file_ext = "." + file.split(".")[-1] if file_ext in extensions: - file_path = os.path.join(root, file) - yield file_path \ No newline at end of file + file_path = os.path.join(root, file) # Get the full path to the file + yield file_path # Yield the results as a generator. \ No newline at end of file From 7cfed2152189f50e7d060620a1f40366b7066e72 Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Fri, 21 Jan 2022 10:25:00 -0500 Subject: [PATCH 05/10] Commented and cleaned up code --- AnalogCSS/ShorthandClass.py | 94 ++++++++++-------- AnalogCSS/__pycache__/CSSClass.cpython-39.pyc | Bin 1715 -> 2822 bytes .../__pycache__/FindFiles.cpython-39.pyc | Bin 660 -> 903 bytes .../__pycache__/ShorthandClass.cpython-39.pyc | Bin 5031 -> 5284 bytes .../__pycache__/get_config.cpython-39.pyc | Bin 1424 -> 1896 bytes .../__pycache__/get_user_css.cpython-39.pyc | Bin 1784 -> 1789 bytes AnalogCSS/__pycache__/syntax.cpython-39.pyc | Bin 244 -> 249 bytes AnalogCSS/__pycache__/tools.cpython-39.pyc | Bin 1668 -> 1399 bytes AnalogCSS/get_config.py | 24 +++++ AnalogCSS/tools.py | 31 +++--- analog_css.py | 21 ++-- app.css | 11 ++ index.html | 67 +++++++++++++ 13 files changed, 187 insertions(+), 61 deletions(-) create mode 100644 app.css create mode 100644 index.html diff --git a/AnalogCSS/ShorthandClass.py b/AnalogCSS/ShorthandClass.py index 13268d3..2c69a54 100644 --- a/AnalogCSS/ShorthandClass.py +++ b/AnalogCSS/ShorthandClass.py @@ -15,14 +15,13 @@ class ShorthandClass: So if you wanted a CSS class to give a margin of 1rem to an element, the shorthand CSS class would be: 'm-1rem'. If you wanted that class to only have an effect at the small (sm) breakpoint, you would prepend 'sm:' to the shorthand class, like this: 'sm:m-1rem'. - - """ + def __init__(self, shorthand_class: str): # The shorthand CSS class/class name self.shorthand_class = shorthand_class - self.parsed_name = self.parse_name() + self.parsed_name = self.parse_name(shorthand_class) # Gets the defined breakpoint values from analog_config.json self.breakpoint_values = get_breakpoint_values() @@ -45,9 +44,12 @@ def is_shorthand_class(self): def breakpoint_exists(self): return BREAKPOINT_SEPERATOR in self.shorthand_class - def parse_name(self): + def parse_name(self, name): + """ + Prepends any special characters with a backslash to escape them + """ parsed_name = "" - for char in self.shorthand_class: + for char in name: if char in SPECIAL_CHARS: parsed_name += f"\{char}" else: @@ -68,19 +70,20 @@ def get_breakpoint(self): return None - def get_shorthand_property(self): + def get_abbreviated_property(self): """ - Gets the CSS property from the shorthand CSS class and returns its mapped value. + Gets the CSS property from the shorthand CSS class and returns it. """ - property_shorthand = self.shorthand_class.split(PROPTERTY_SEPERATOR)[0] - if BREAKPOINT_SEPERATOR in property_shorthand: - property_shorthand = property_shorthand[property_shorthand.index(BREAKPOINT_SEPERATOR) + 1:] + css_prop_name = self.shorthand_class.split(PROPTERTY_SEPERATOR)[0] + + if BREAKPOINT_SEPERATOR in css_prop_name: + css_prop_name = css_prop_name[css_prop_name.index(BREAKPOINT_SEPERATOR) + 1:] - return property_shorthand + return css_prop_name - def get_real_property(self, prop_shorthand): - if prop_shorthand in self.class_mappings.keys(): - return self.class_mappings[prop_shorthand]["property"] + def get_prop_attributes(self, abbr_prop): + if abbr_prop in self.class_mappings.keys(): + return self.class_mappings[abbr_prop]["property"] def get_shorthand_value(self): """ @@ -97,29 +100,33 @@ def get_shorthand_value(self): def get_unit(self, value): for i, char in enumerate(value): - if char not in NUMBERS: + if char not in NUMBERS and char not in "/.": return value[i + 2:] - def get_value(self, value): - # Evaluate fractions + def eval_fraction(self, value): + slash_index = value.index("/") + for i in range(slash_index + 1, len(value)): + if value[i] not in NUMBERS: + expression = value[:i] + evaluated_value = round(int(expression.split("/")[0]) / int(expression.split("/")[1]), 2) + unit = self.get_unit(value) + return str(evaluated_value) + unit + + def get_true_value(self, value): if "/" in value: - slash_index = value.index("/") - for i in range(slash_index + 1, len(value)): - if value[i] not in NUMBERS: - expression = value[:i] - evaluated_value = round(int(expression.split("/")[0]) / int(expression.split("/")[1]), 2) - unit = self.get_unit(value) - value = str(evaluated_value) + unit - break + # Value is a fractional one, so evaluate the fraction and return the value. + return self.eval_fraction(value) - # Otherwise the value is good + # If this line is reached, we don't have to do anything to the value return value def generate(self): - output = "" is_media_query = False + """ Check if the shorthand class contains a breakpoint, if so, + get the value of the breakpoint and generate a CSS class that fulfils the media query specifications + """ if self.breakpoint_exists(): is_media_query = True mq_type = get_media_query_type() @@ -129,27 +136,29 @@ def generate(self): if breakpoint[0] == "@" and breakpoint not in self.breakpoint_values.keys(): breakpoint = self.get_value(breakpoint[1:]) - - # self.media_queries[breakpoint].append() output += f"@media ({mq_type}: {breakpoint}) {{\n" - if self.get_shorthand_property() in self.user_css_classes.keys(): - # This means the user is adding a breakpoint to one of their classes. - user_class_name = self.get_shorthand_property() + if self.get_abbreviated_property() in self.user_css_classes.keys(): + # This means the user is adding a breakpoint to one of their own predefined classes. + user_class_name = self.get_abbreviated_property() user_css_class = self.user_css_classes[user_class_name] - user_css_class.name = self.parsed_name(user_class_name) + user_css_class.name = self.parse_name(user_class_name) return user_css_class.create_media_query(mq_type, breakpoint) - - + if not self.is_shorthand_class(): + """ This is checked here because the user might have added a class to + an element with the name of md:flex-col. + Therefore if this IF statement is reached, we know the user is not applying a their class to media query, + and if they are not assigning any values to CSS properties, then we can return an empty string. + """ return "" - shorthand_prop = self.get_shorthand_property() - attributes = self.get_real_property(shorthand_prop) - if not attributes: - attributes = shorthand_prop - value = self.get_value(self.get_shorthand_value()) + + abbreviated_prop = self.get_abbreviated_property() + attributes = self.get_prop_attributes(abbreviated_prop) + + value = self.get_true_value(self.get_shorthand_value()) css_class = CSSClass(self.parsed_name) @@ -157,12 +166,15 @@ def generate(self): for attr in attributes: css_class.set(attr, value) else: + if not attributes: + attributes = abbreviated_prop css_class.set(attributes, value) + # Generate a valid CSS class compiled_class = css_class.compile() output += compiled_class - + # If the shorthand class used a media query then we need to add an extra brace to close of the media query. if is_media_query == True: output += "}\n" diff --git a/AnalogCSS/__pycache__/CSSClass.cpython-39.pyc b/AnalogCSS/__pycache__/CSSClass.cpython-39.pyc index 3f2b23a17636ce7b10865ded3fef35aa00809c45..7aa9bfaeae68693f922bc4c06734e1d9d963b67f 100644 GIT binary patch literal 2822 zcmb7GO>f&q5ZxuI4=c9gERphZ znL;XkO8P4b1Mx9`iO2Sob8kNN%~GN)+c}iNesDRvJM(7djpWKohvC`z^>2CS24nxw z%f-jX%QLj>Ho6x~F~#4bz4Q7^d3&tuM_6BY>K)%=S+hP@tnVq__tj11tKdEF2dbf( z?^(a0TB?n)sg_g+V@uso%NW~gMXh37ayP7%?VY{7oq^0UdFnCN5qN$+j586@n!qH_ zv=TNInN5urkgh)IOe9*`!MNx4{F3G(l8KN}q_J;g(vdcHEZ)jN4$(n;q=m(~kDc`P z_O^(!EOeLj4z%6enC%D?In*0nA-)o?w9QR&`LK>V;d!FOczS21?f<(F8!lh?P|P)O zI#(*}X`6{`q@#F01`IPL1u5x3sXw_*m2NXE4s@c8v|329pAQCe?0|%{B1#i0W7sG0 zE#1eWo?Q?FGO~^=ixUUj)FF8mCkNMo7^TBeJkXm9$VtLKRu^uTxDKu~IHmVlZC@KL zk49;nSTWQpmf|?qW{gPq+})73I&`w3lil1H9*1^3(i;GFe%zv8Co zfM>eWn63l>%P;&QIP*9=UQ<> zsgswc^aVj4n~D`G;-FK1N}`3(C&4LkNN~=6nkVX^kjiZzy1aukdiB*=t=~C+QnGXY z_!9y2iICdu2F_t+BO483ivdm^l|E9d+b}Iilnpv4D}zCtASz}#UN)Qx&dpV~1Yy%e zcMmOFM#oyqejARujo;*M?W)D#i704h56$bSC0~=n3cl`QbMixN$c+1l6r3KH7-B4b zkHM!2DB^k~K5|2W(e)}DS7v58e!XN==@SJ*I&-Q9ljYhJe7KTz6#p*ZR!M*48(Hua zg$u#rO<8CJhN@@}?Wz@U_JS1w zq-e9Vf(%F4GfD`Br1=ZQxA4#-5fsYlpWZsdTl2K#k|C+>doksAqST8#Ip;g)B$p;p zZVYl_%Hs3L{fryuwols6so_i;qE-zbC=0}{nXl_lJx9rUI zC|9RKsw%mckSlLTR~Y77N-hu*?I1NAvfpC@L=hi^>8TG&VsAK6 z4~Xdjh>6I?16BD2h{<6d6h34dr;Tse2|vDv_2ym5jn-sxE$#@Qh5F`dltVmD_ER&I zHck^Nt8c+cAf_t`<5Nb;P{E)A z7KUXf42P-82Q*&}QF`TI`lS_yDviR>5XU&ua+(>+5hJLhOE1KM%O%Hf#G2GHN^caQ fo1IpBt=+`0WhzGHZoF=D*?w9nv`v!#qOtz~ZoBVJ delta 769 zcmZuv&x;c=6iz0YA04-~EK;qjFvuc~pyEZLTkEfji%`|c~RJ#=Q;V3T2VAZzP#k+eeaw1vfntW)}m_FCpap*U!%|b zpmu2G9}kXRH~j!dr_%}A35*i~+3d=TXgC!e`H(%JbNPndUS${u9AQqNf=k(!-`GW2 z=K=NPb$-LwzWX@SM{>eX(U#oj*Y5FxY_o#3$)p~W$0T&RCEZY@q^)DTN{%T)$PKTu z(`4AsaLJ&bfTKM&c=CgNAt=3TIGGpCD43q0JZ>hgzr zJJCoiC=8kAQS6z>PNR|PNJ8Z&=jJU`X^22OLS|^-4BF7p@V64hQjwj-^CiQcySAq* zrIVXttfLXrg1#lORal6uAcy2ViFr(3Sxtf`_B+>9Cim`)MBI;pOQqEcavlb|KGZS3 zv|jolRqob!l=O$<1No5e<@Ye<|%-~{eWC!wh=T}22q=zu@!{JUMCAB&!84Z)+_@m<6h-UOrl_c0U}1X`Rfoo;i9pQ;l^9tv!eSDKSU7%B><|?RRZM(9_z?zv z1~xV%{sElAz`&87^saR8)qUze4#sRW8g?wp%XfCsdmitT^;XoG_U=B1U^%N)Yy>KZ zG2tMTE=0)_xLSn}85ZB*EiY4vHB_3HFv%-a6UdAybV#ZG>u_VtY3tI|_x!`f{D`)0 z+X+nRnwQ~kZv9`7(ZCD5Mc~gjvwpS-m1tm60;XUx4ylk_w}q`Jn8~#Ln1K~mP%~xV zL@|li%P0bakfRa?OLx=tO5Bex%lUNB9Fu!;+Psj1{w!xgHE(3L<2b}2+uc2T&2IPM E8$gI;r~m)} delta 68 zcmZo?pTf$Q$ji&c00fgRJxJtW+Q=u#$j1=Opvmlai&5|8e;}Bw%v8^4J9#ma+T?Rg Sy4;LxK*+%;0>qQqm>U6tA`#61 diff --git a/AnalogCSS/__pycache__/ShorthandClass.cpython-39.pyc b/AnalogCSS/__pycache__/ShorthandClass.cpython-39.pyc index 148c78097e738e6f7018fd093973928436f1cd41..42eec9644ec75bef0e4d9717e4efba5e9f19817d 100644 GIT binary patch delta 1390 zcmZ8gO>7%Q6rMM`w#WO|wNtwxHHp)>NjFU#S_#UJ097IVQx%0eR1mdT8}Al7O`K$Q z6Np)ZAP6CGp&B6${3w=?s$P(2E`U^tGZ(}S`3gcDxp0X<;>|iGYG$LYzX^s?=9`Sa+M=^s*ZSuCY4< zx+1Qtr$j+dXD{IK2qID?5!rzVI~meAp0q_nif z7aWe#C!@q1+%V*g#f{Jp=4Akx4FVR3pN(ARkV6fGsrQTD^$&+f(QDR8@Z&i0l!P$} zk4dl*?un0$Gw`Z-V9bp_i|Y`Tvn}&Faf7yLoLkrg&LYL@jUclurp#PYnQhUjvbbOl zr6=%Y7aIJ8XqttLkENRQGT3S|9{W!knqY`YV9EewX`W`WIy9LNg(X!5=hUJaHGqLlljvzE zqMRLpjJTF9!#VL@w!akfkEzDIVoFjLy)48uXT*2e;lTmi#At?<7!>vLTL*e0JSNi6l#@*3Mmv>n|Re2633q1 zL^RqJsv<>*6V(%^Le)q}MXFQ@@(+NJIB@6<3HgM2>jeQfdg8q`3F?gIH}B27`OW+K z#=UpU@od`?G$tSZ?mZsA<$MR-TR*H<7KA%7a28h9b-3bn+w-el5O}4%OOP{C))WnV z-*gX4dN@xjI8P8kBw8X8cVSoT-8N4GoWqBy8vc{2Ib&?(5C|g;7S5%=ggX9|z5{c( zl$rY!_~yT1&~DO7cu$eghM1T?66eK-)mTO{giWDq5wuCZExwj7i5U78{eB>k^G0(Z zp1?I%>I_i~?1js3%)fQ^o!0z?vsV^eL$gDg10R^nE7(#M=Xp|sJb?fcti5gZ9>6R3 zTlO@qfN3!AwQibv^YpU~k)Og3F)GVOb-2R!dG4<|{016xzf zG4hnbGGN~v$3}i;6&fI`MU>{I#A zNohmGW!%AA|?}}ZBv!O#xsJ0=t!jXvfu<)_`0<;+^%2grGMb_P7l#8;vlEV12 zn@@B#)JZPk+r`r`i#LmtP{upO$xBu8LvzDvF1tR%aEzhMFzn5)x8^UFmZ`R(-&*tA z9k12j@b!&hHC;A5&R}4r6dZA$?zn;Fg`w^&ZG?WH>-cTy)z>%4ICzafNE1xTf(dC* z#srkiiYz5rp`4g>p2%bajExIqZ!d!e7ePB)_G9Y-davG_%T4mNJ#CQfdVME`R?oho}AM diff --git a/AnalogCSS/__pycache__/get_config.cpython-39.pyc b/AnalogCSS/__pycache__/get_config.cpython-39.pyc index d3e3b9eda79499de363b42cce6954a78450338cb..b70ed82029983721cf3e67363cdcafac612680f3 100644 GIT binary patch delta 697 zcmb7>%}xR_6onla2r_mED_15>Ob|_wpd>2(M1qkm5#!n_1sa)lY&$Al`UIMJ786&- z2k=370@qF%aAtxV+f|!;zjMyLFV@7i5dit6;JkMxsFHcLzjswF4};UjQb0Mx&=Z)$ z9_|y0d+>&1bmuZcC44|54~uE7pE2r2%WoK^OvOQj`q#!m+T=OEXjU6)KgqitAt92~ zR<{eoZwI+9p@SLr%QyyBU{0j8MUyXUU|E%tz=XlLtMk+$D8}0Jx_wKPlkM6tba0O# zc<*68hH~uUFxE$^307kOO9Sd^Ckb$o9EPKsk849f9jQ-7SZs%=qjVdr#ZW66b)_yB zQIPegbDtA}2a?ey9ub`_#^r3lkpm@z%#*Gc6tPh3Gks>QM`C`#tevWpMXA_=|HL|s z63KW7ZJK*vGlKGhPH>?*Nvs~8PN1_x{3J0IgwcNqy_rp`8VUJE<{4z|-kV!zsqFJ%Z((?1r@JjcI4(mh)+Jn3^GNZ#hqIaNwkp#B+9|+ o!YhIhE#ifmae~#HR~$*4A1dC<=EyCD5TAULt%;YJ4-Pq)0emAUd;kCd diff --git a/AnalogCSS/__pycache__/get_user_css.cpython-39.pyc b/AnalogCSS/__pycache__/get_user_css.cpython-39.pyc index d91528d0a7a4e46593b202d938b3006c4dd16ca3..5ddacab7323d59bb5b3b57739e65e2a29d236b8d 100644 GIT binary patch delta 37 rcmeyt` diff --git a/AnalogCSS/__pycache__/syntax.cpython-39.pyc b/AnalogCSS/__pycache__/syntax.cpython-39.pyc index cd1247efedf4682923812f0f532d704a15b8cd2e..22a9a38981c3927afee79c5cfc7a23400bb5fe7f 100644 GIT binary patch delta 33 ncmeyu_>+-4k(ZZ?0SKI99!=z)&S*bzu^OvxZenKM#FN?poihq5 delta 27 hcmey#_=S->k(ZZ?0SF@M9!%t(&S*7pvD(CQ+5l{Q2#5dx diff --git a/AnalogCSS/__pycache__/tools.cpython-39.pyc b/AnalogCSS/__pycache__/tools.cpython-39.pyc index 5ef0cf317cb05a8adf80588545b9d497d378d0a5..d9669251113d7c26fe7ebe6729bde011113e9ef8 100644 GIT binary patch delta 387 zcmZqS{m#Xk$ji&c00i+#FB0u0^2#!XOw?TiQRFlxnP0Y;Gcg#!7$xn9<4%RQp&(A5=E2x}Y$Rx?gGr5~7Nrx4v`W9<>QD#Z% zO6DRCATNqNIX|x?HLs+I6UYM_2O+p8OESw&?qZ4;Pb}gCNeQ6KuVGeX6rOyJd6^Fj zP|8n}r3h?1OIC4y-YwRg{KS;vA~ujFb~K$p?k&!u)Wno{kWx7yw-{ss0}Bshk=Wz| zEd4;&2C$}bgZu__%mG$2A!#6AlRJtdu_(PDv8Xt;NMtfIn`R&nNSPpr5C#!qAOfTm p$unS+xPfA~IBatBQ%ZAE?HGZ)Vj&>G!N|eH1H>%c94uhS4gmY`Pvigq delta 647 zcmZ8dO=}ZD7@nD(O*S8!CVte9Scw;L6_cD4L4;DgRv{v?NXyWf#)fS+%*;{@6+PtQ zL1fvB$MzWLwSQ($1%HGf2)^%BQ98psyw5Z5_mBD_3`H2$37qe*&%`hf*XY~)!K-jZ zwihIBNID`>CtpM#(dF-9VEFJh;F%$SB}ep_d?1Hp!X%YUdXj(fDDWc>bb3f9+}xM` zh@b^2E1PrnFrBwwWOkO>-o|Lu+uci4zpSR2MJr+@f2WdJ%%w7RUf&W^k)-4Pjxmv6 z211W#LK_vg*7Z2sS5x~Esg9dM%5C^{T3mNd$c^UEXT;))lXS^ZToN6C{PRh1kKTPe zSa&s`nSo8y#PnzH%V4ami?89VO#ngz+NJ@kP);>&EP|Yf(7bK~`#(p~Vrz7@_(Zp^34IwquU_;xW_S2?5c89p z#TolNXn?&L@$)i#V$x~pC#jG|hZx$r82`#5q~BqPWhv-2Rv%( z3d%Q%Up#t)!|D#gDgqYQU4$OOzj$Z4H3U!hQ<){|83hk>1t5UUHQ{j<)B^5q^*2k! Bk;(u7 diff --git a/AnalogCSS/get_config.py b/AnalogCSS/get_config.py index ec4e035..6bf5be8 100644 --- a/AnalogCSS/get_config.py +++ b/AnalogCSS/get_config.py @@ -3,27 +3,51 @@ config_file = "analog_config.json" def get_breakpoint_values() -> dict: + """ + Gets the user defined breakpoint values + """ return read_json(config_file)["breakpoint_values"] def get_class_mappings() -> dict: + """ + Gets the class user defined CSS class mappings + """ return read_json(config_file)["class_mappings"] def get_custom_values() -> dict: + """ + Gets the user defined values + """ return read_json(config_file)["custom_values"] def get_media_query_type() -> dict: + """ + Gets the main media query type + """ return read_json(config_file)["media_query_type"] def get_user_css_file_paths() -> dict: + """ + Gets the paths the the user's CSS files. + """ return read_json(config_file)["user_css_file_paths"] def get_output_css_path() -> str: + """ + Gets the path of the CSS file that the user wants the program to output to + """ return read_json(config_file)["output_css_file_path"] def get_input_paths(): + """ + Gets the paths the user wants the program to monitor + """ return read_json(config_file)["input_paths"] def get_input_extensions(): + """ + Gets the type of file extensions the user wants the program to monitor + """ return read_json(config_file)["input_extensions"] diff --git a/AnalogCSS/tools.py b/AnalogCSS/tools.py index c3da868..64c0d7c 100644 --- a/AnalogCSS/tools.py +++ b/AnalogCSS/tools.py @@ -1,4 +1,8 @@ -import argparse +""" +This file contains a bunch of generic functions. +""" + +# import argparse import json from bs4 import BeautifulSoup @@ -6,14 +10,14 @@ NUMBERS = "0123456789" -def get_args(): - parser = argparse.ArgumentParser() - parser.add_argument("-o", help="Output CSS file.", dest="outfile") - args = parser.parse_args() +# def get_args(): +# parser = argparse.ArgumentParser() +# parser.add_argument("-o", help="Output CSS file.", dest="outfile") +# args = parser.parse_args() - if not args.outfile: - return "analog.css" - return args.outfile +# if not args.outfile: +# return "analog.css" +# return args.outfile def read_file(path): with open(path, "r") as f: @@ -41,11 +45,12 @@ def get_classes_from_file(file): ['class-1', 'class-2', class-3', etc...] """ soup = BeautifulSoup(file_contents, "html.parser") - class_list = list() + class_list = list() # A list of class names that the parser found for element in soup.find_all(): - if element.has_attr("class"): - for _class in element["class"]: - if _class not in class_list: - class_list.append(_class) + # If there is a class attribute in this element, extract all the class names from it. + if element.has_attr("class"): + for _class in element["class"]: + if _class not in class_list: + class_list.append(_class) return class_list \ No newline at end of file diff --git a/analog_css.py b/analog_css.py index 0285a7c..d2d1c26 100644 --- a/analog_css.py +++ b/analog_css.py @@ -1,4 +1,3 @@ -from webbrowser import get from AnalogCSS.tools import get_classes_from_file, append_to_file, write_file from AnalogCSS.FindFiles import find_files from AnalogCSS.get_config import get_output_css_path @@ -11,25 +10,33 @@ while True: output_path = get_output_css_path() try: - files = find_files() + files = find_files() # Find all the files the user wants the program to track. - generated_classes = list() + generated_classes = list() # A list to store the generated CSS classes. for file in files: - classes = get_classes_from_file(file) + class_names = get_classes_from_file(file) # Gets the CSS classes the user used in their markup. - for _class in classes: + # Loop over all the found class names and generate a CSS class with them. + for _class in class_names: shorthand_class = ShorthandClass(_class) generated_classes.append(shorthand_class.generate()) - write_file(output_path, "") + write_file(output_path, "") # Delete the contents of the output file. + + # Append all the generated classes to the output file for _class in generated_classes: append_to_file(output_path, _class) time.sleep(1) except KeyboardInterrupt: - print("\n[+] Stopped watching files") + # Make sure the program generates all the classes again before quitting. + print("[+] Generating classes one more time.") + for _class in generated_classes: + append_to_file(output_path, _class) + + print("\n[+] Done. Stopped watching files") exit() diff --git a/app.css b/app.css new file mode 100644 index 0000000..656e4d3 --- /dev/null +++ b/app.css @@ -0,0 +1,11 @@ +::before { + box-sizing: border-box; +} + +.flex { + display: flex; +} + +.flex-col { + flex-direction: column; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..1ef91b3 --- /dev/null +++ b/index.html @@ -0,0 +1,67 @@ + + + + + AnalogCSS + + + + +

    Analog CSS

    + +
    +
    + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas culpa, amet voluptatum molestias excepturi quibusdam deserunt id eligendi, delectus harum sequi ut reprehenderit tempore dolorem quod nobis quis aperiam neque! + Ducimus tenetur fugit necessitatibus ex perferendis harum tempora quod laboriosam, sapiente nisi iste amet sequi? Alias, autem atque deleniti natus minima assumenda sapiente doloremque hic laboriosam, recusandae neque ipsa praesentium! + Ea laudantium, incidunt deleniti reprehenderit natus eum, vel autem ullam vero quos exercitationem necessitatibus? Placeat ad iure earum nihil culpa, voluptatem repudiandae aliquam rerum nostrum nisi distinctio? Incidunt, molestiae animi? + Cupiditate, quae quasi velit ipsa eligendi voluptatem perferendis, laudantium, enim nihil error vitae at aperiam soluta eum non natus repellendus? Atque dolor repellat officiis similique vero voluptates debitis dolores beatae. + Quasi, possimus sequi maxime voluptates inventore nam ullam modi quidem similique in ipsam nisi suscipit. Atque voluptas ipsam unde ducimus blanditiis, officiis culpa porro perferendis aspernatur vel ratione facere illo? + Tempora laudantium tenetur ut reiciendis magni dolores ullam rem dolore amet cumque eius aut, numquam id quo dolorem, ipsa enim asperiores quaerat? Labore quae cupiditate exercitationem aut fuga ea minus. + Iste fugit quisquam dolore sapiente in quaerat vero totam, aspernatur aliquid distinctio officia eos? Ducimus explicabo voluptatibus iste modi sequi fugiat labore tenetur mollitia, officiis veritatis inventore vel possimus at? + Neque fugit dolor accusantium laudantium iusto perspiciatis blanditiis. Similique asperiores incidunt maxime dolore nam quisquam veritatis, magni nulla fugit, natus beatae. Architecto, ut! Molestiae soluta qui magnam totam at accusantium? + Iste quibusdam ut incidunt blanditiis similique? Magni, a quae, neque, qui fuga dolores quos non repellat beatae est porro corporis obcaecati recusandae numquam! Assumenda fuga laudantium expedita, molestias corporis nemo? + Architecto doloremque odit impedit ipsum recusandae non ipsa distinctio autem voluptatem assumenda quam obcaecati, cumque rerum maxime sapiente libero eveniet labore. Corrupti debitis voluptas nam fugiat consequatur fuga quae! Tenetur? +
    + +
    + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate alias dolorem molestiae tempore amet corporis placeat ut. Et minus dolores, repellendus esse voluptates animi nihil earum ea mollitia dolor. + Necessitatibus, rerum consectetur! Repellendus sit debitis est rerum itaque fugiat velit maxime odit perspiciatis a dolor nihil voluptatum commodi reiciendis, ducimus libero iure nulla alias culpa cum ad impedit excepturi! + Sunt accusamus fugit explicabo sit ex nam aut totam eligendi hic commodi rem, itaque deserunt odit beatae adipisci! Cupiditate blanditiis modi numquam tenetur fugiat est sint, nihil quia eum ut. + Ex labore, rem sunt at cumque quisquam officiis sint eius fuga! Est, pariatur reiciendis error nesciunt accusantium eos itaque eaque rerum, quidem aspernatur veniam officiis commodi? Molestiae quas eius adipisci. + Sunt quisquam aliquid iure ullam qui quaerat maiores repudiandae magni id reiciendis velit impedit accusantium culpa officia quibusdam est, error molestiae neque optio veniam expedita nisi dignissimos! Veritatis, ullam quasi! + Exercitationem nesciunt pariatur eaque assumenda quod dolorem eius suscipit voluptatibus aliquid neque a, quidem voluptates minus tenetur consequatur magnam odio dignissimos reprehenderit corrupti, impedit sed magni labore explicabo! Doloremque, amet. + Nisi deserunt natus quae quisquam. Iure quos labore impedit, animi nemo harum. Ad dolore qui commodi nam optio voluptates quis expedita, eum molestiae magnam at natus quisquam, quidem debitis sunt. + Praesentium excepturi laboriosam nihil, culpa maiores ducimus? Quo aliquid quasi blanditiis et voluptatum nobis a ad iste aut, illum natus maiores explicabo dolore odio unde reiciendis in recusandae illo? Odit. + Atque iusto dignissimos dolor, obcaecati cum assumenda doloribus ad rerum sequi, quis corporis eius quae corrupti sint libero repudiandae id saepe perspiciatis autem perferendis ut minima provident. Sequi, culpa voluptatibus? + Corporis sint ab nostrum magni corrupti vitae ad assumenda magnam. Iste a asperiores totam debitis officiis velit animi quaerat veniam recusandae eos sit quam repellendus, eveniet explicabo tenetur nemo vitae. +
    + +

    I think this is pretty cool

    +
    + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate alias dolorem molestiae tempore amet corporis placeat ut. Et minus dolores, repellendus esse voluptates animi nihil earum ea mollitia dolor. + Necessitatibus, rerum consectetur! Repellendus sit debitis est rerum itaque fugiat velit maxime odit perspiciatis a dolor nihil voluptatum commodi reiciendis, ducimus libero iure nulla alias culpa cum ad impedit excepturi! + Sunt accusamus fugit explicabo sit ex nam aut totam eligendi hic commodi rem, itaque deserunt odit beatae adipisci! Cupiditate blanditiis modi numquam tenetur fugiat est sint, nihil quia eum ut. + Ex labore, rem sunt at cumque quisquam officiis sint eius fuga! Est, pariatur reiciendis error nesciunt accusantium eos itaque eaque rerum, quidem aspernatur veniam officiis commodi? Molestiae quas eius adipisci. + Sunt quisquam aliquid iure ullam qui quaerat maiores repudiandae magni id reiciendis velit impedit accusantium culpa officia quibusdam est, error molestiae neque optio veniam expedita nisi dignissimos! Veritatis, ullam quasi! + Exercitationem nesciunt pariatur eaque assumenda quod dolorem eius suscipit voluptatibus aliquid neque a, quidem voluptates minus tenetur consequatur magnam odio dignissimos reprehenderit corrupti, impedit sed magni labore explicabo! Doloremque, amet. + Nisi deserunt natus quae quisquam. Iure quos labore impedit, animi nemo harum. Ad dolore qui commodi nam optio voluptates quis expedita, eum molestiae magnam at natus quisquam, quidem debitis sunt. + Praesentium excepturi laboriosam nihil, culpa maiores ducimus? Quo aliquid quasi blanditiis et voluptatum nobis a ad iste aut, illum natus maiores explicabo dolore odio unde reiciendis in recusandae illo? Odit. + Atque iusto dignissimos dolor, obcaecati cum assumenda doloribus ad rerum sequi, quis corporis eius quae corrupti sint libero repudiandae id saepe perspiciatis autem perferendis ut minima provident. Sequi, culpa voluptatibus? + Corporis sint ab nostrum magni corrupti vitae ad assumenda magnam. Iste a asperiores totam debitis officiis velit animi quaerat veniam recusandae eos sit quam repellendus, eveniet explicabo tenetur nemo vitae. +
    + +
    + Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate alias dolorem molestiae tempore amet corporis placeat ut. Et minus dolores, repellendus esse voluptates animi nihil earum ea mollitia dolor. + Necessitatibus, rerum consectetur! Repellendus sit debitis est rerum itaque fugiat velit maxime odit perspiciatis a dolor nihil voluptatum commodi reiciendis, ducimus libero iure nulla alias culpa cum ad impedit excepturi! + Sunt accusamus fugit explicabo sit ex nam aut totam eligendi hic commodi rem, itaque deserunt odit beatae adipisci! Cupiditate blanditiis modi numquam tenetur fugiat est sint, nihil quia eum ut. + Ex labore, rem sunt at cumque quisquam officiis sint eius fuga! Est, pariatur reiciendis error nesciunt accusantium eos itaque eaque rerum, quidem aspernatur veniam officiis commodi? Molestiae quas eius adipisci. + Sunt quisquam aliquid iure ullam qui quaerat maiores repudiandae magni id reiciendis velit impedit accusantium culpa officia quibusdam est, error molestiae neque optio veniam expedita nisi dignissimos! Veritatis, ullam quasi! + Exercitationem nesciunt pariatur eaque assumenda quod dolorem eius suscipit voluptatibus aliquid neque a, quidem voluptates minus tenetur consequatur magnam odio dignissimos reprehenderit corrupti, impedit sed magni labore explicabo! Doloremque, amet. + Nisi deserunt natus quae quisquam. Iure quos labore impedit, animi nemo harum. Ad dolore qui commodi nam optio voluptates quis expedita, eum molestiae magnam at natus quisquam, quidem debitis sunt. + Praesentium excepturi laboriosam nihil, culpa maiores ducimus? Quo aliquid quasi blanditiis et voluptatum nobis a ad iste aut, illum natus maiores explicabo dolore odio unde reiciendis in recusandae illo? Odit. + Atque iusto dignissimos dolor, obcaecati cum assumenda doloribus ad rerum sequi, quis corporis eius quae corrupti sint libero repudiandae id saepe perspiciatis autem perferendis ut minima provident. Sequi, culpa voluptatibus? + Corporis sint ab nostrum magni corrupti vitae ad assumenda magnam. Iste a asperiores totam debitis officiis velit animi quaerat veniam recusandae eos sit quam repellendus, eveniet explicabo tenetur nemo vitae. +
    +
    + + \ No newline at end of file From 03e967b962a23f7274115b74b290fd0321645069 Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Wed, 26 Jan 2022 14:54:31 -0500 Subject: [PATCH 06/10] Can now define a `unit` key in for properties You can now define a default unit for classes in `class_mappings` , like this: ```json "class_mappings": { "p": { "property": "padding", "unit": rem } } ``` --- AnalogCSS/ShorthandClass.py | 29 +++++------ AnalogCSS/ShorthandProperty.py | 43 ++++++++++++++++ AnalogCSS/ShorthandValue.py | 46 ++++++++++++++++++ .../__pycache__/ShorthandClass.cpython-39.pyc | Bin 5284 -> 5565 bytes .../ShorthandProperty.cpython-39.pyc | Bin 0 -> 1676 bytes .../__pycache__/ShorthandValue.cpython-39.pyc | Bin 0 -> 1786 bytes AnalogCSS/__pycache__/tools.cpython-39.pyc | Bin 1399 -> 1487 bytes AnalogCSS/tools.py | 2 + analog_config.json | 6 ++- analog_css.py | 1 + 10 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 AnalogCSS/ShorthandProperty.py create mode 100644 AnalogCSS/ShorthandValue.py create mode 100644 AnalogCSS/__pycache__/ShorthandProperty.cpython-39.pyc create mode 100644 AnalogCSS/__pycache__/ShorthandValue.cpython-39.pyc diff --git a/AnalogCSS/ShorthandClass.py b/AnalogCSS/ShorthandClass.py index 2c69a54..5a29d2f 100644 --- a/AnalogCSS/ShorthandClass.py +++ b/AnalogCSS/ShorthandClass.py @@ -1,3 +1,5 @@ +from AnalogCSS.ShorthandValue import ShorthandValue +from AnalogCSS.ShorthandProperty import ShorthandProperty from AnalogCSS.get_config import * from AnalogCSS.syntax import * from AnalogCSS.CSSClass import CSSClass @@ -35,7 +37,7 @@ def __init__(self, shorthand_class: str): # Gets the predefined CSS that the user wrote. self.user_css_classes = GetUserCSS(get_user_css_file_paths()).get_classes() - self.media_queries = dict() # {"breakpoint": list()} + self.abbr_prop = self.get_abbreviated_property() def is_shorthand_class(self): @@ -101,16 +103,7 @@ def get_shorthand_value(self): def get_unit(self, value): for i, char in enumerate(value): if char not in NUMBERS and char not in "/.": - return value[i + 2:] - - def eval_fraction(self, value): - slash_index = value.index("/") - for i in range(slash_index + 1, len(value)): - if value[i] not in NUMBERS: - expression = value[:i] - evaluated_value = round(int(expression.split("/")[0]) / int(expression.split("/")[1]), 2) - unit = self.get_unit(value) - return str(evaluated_value) + unit + return value[i:] def get_true_value(self, value): if "/" in value: @@ -155,11 +148,13 @@ def generate(self): return "" - abbreviated_prop = self.get_abbreviated_property() - attributes = self.get_prop_attributes(abbreviated_prop) - - value = self.get_true_value(self.get_shorthand_value()) - + + css_prop = ShorthandProperty(self.abbr_prop, self.get_shorthand_value()) + attributes = self.get_prop_attributes(self.abbr_prop) + value = str(css_prop.prop_value) + if css_prop.prop_unit: + value += css_prop.prop_unit + css_class = CSSClass(self.parsed_name) if type(attributes) == list: @@ -167,7 +162,7 @@ def generate(self): css_class.set(attr, value) else: if not attributes: - attributes = abbreviated_prop + attributes = self.abbr_prop css_class.set(attributes, value) # Generate a valid CSS class diff --git a/AnalogCSS/ShorthandProperty.py b/AnalogCSS/ShorthandProperty.py new file mode 100644 index 0000000..310a040 --- /dev/null +++ b/AnalogCSS/ShorthandProperty.py @@ -0,0 +1,43 @@ +from AnalogCSS.ShorthandValue import ShorthandValue +from AnalogCSS.get_config import get_class_mappings +from AnalogCSS.tools import NUMERICAL + +class ShorthandProperty: + def __init__(self, property_abbreviation, full_property_value): + self.prop_abbr = property_abbreviation + self.full_prop_value = ShorthandValue(full_property_value) + + + # Gets the class mappings from analog_config.json + self.class_mappings = get_class_mappings() + + self.prop_unit = None + self.prop_value = self.full_prop_value.value + + self.attributes = self.get_prop_attributes() + self.set_unit() + + def get_prop_attributes(self): + if self.prop_abbr in self.class_mappings.keys(): + return self.class_mappings[self.prop_abbr]["property"] + + def get_defined_unit(self): + if "unit" in self.class_mappings[self.prop_abbr].keys(): + return self.class_mappings[self.prop_abbr]["unit"] + return None + + def set_unit(self): + if self.full_prop_value.type == NUMERICAL: + if self.full_prop_value.unit: + self.prop_unit = self.full_prop_value.unit + else: + self.prop_unit = self.get_defined_unit() + + + def info(self): + print("[+] INFO: self.prop_value:" + self.prop_value) + print("[+] INFO: self.prop_unit:" + self.prop_unit) + + + + diff --git a/AnalogCSS/ShorthandValue.py b/AnalogCSS/ShorthandValue.py new file mode 100644 index 0000000..475fc79 --- /dev/null +++ b/AnalogCSS/ShorthandValue.py @@ -0,0 +1,46 @@ +import re +from tkinter import E +from AnalogCSS.tools import NUMBERS, NUMERICAL, STRING + +class ShorthandValue: + def __init__(self, value): + self.raw_value = value # This value will be unchanged. The other one will be parsed if it's a fraction. + self.value = value + self.type = self.get_value_type() + self.unit = self.get_unit_from_value() + self.parse_fraction() + + def is_fraction(self): + return "/" in self.value + + def get_value_type(self): + if self.value[0] in NUMBERS: + return NUMERICAL + else: + return STRING + + def parse_fraction(self): + if self.is_fraction() and self.type == NUMERICAL: + if self.value[-1] not in NUMBERS: + # This means the user is using a custom unit in their class name, so we need to do some parsing. + slash_index = self.value.index("/") + for i in range(slash_index + 1, len(self.value)): + if self.value[i] not in NUMBERS: + expression = self.value[:i] + evaluated_value = str(round(int(expression.split("/")[0]) / int(expression.split("/")[1]), 2)) + if self.unit: + self.value = evaluated_value + self.unit + self.value = evaluated_value + return + else: + # This means the user did not provide a unit in their class name, so we can just evaluate the raw expression. + self.value = str(round(int(self.value.split("/")[0]) / int(self.value.split("/")[1]), 2)) + + def get_unit_from_value(self): + for i, char in enumerate(self.value): + if char not in NUMBERS and char not in "/.": + if i == 0: + return None + return self.value[i:] + + \ No newline at end of file diff --git a/AnalogCSS/__pycache__/ShorthandClass.cpython-39.pyc b/AnalogCSS/__pycache__/ShorthandClass.cpython-39.pyc index 42eec9644ec75bef0e4d9717e4efba5e9f19817d..825cbc8df2f7e37095d6c7c965d78fbd97f2605e 100644 GIT binary patch delta 1814 zcmZuy$!{A~7@s%eWfm{7oyAF<))i@+X+lCvMMY?$R+=yjaHEIE;R$F%*ttj#}3YjR>~{D{jdT1WRsOJ*(F*Bh#n?wgWt*|V2`(Ts4|3XnNCp6f*_v1N4ic;` zIi}~0vY%rWupEdN#?X=u9hz`sZkJi4wz<02sJVXCzF+fvZ=5a0|GI!N!ia0uZJOY4 zX~m=`f>I467ukmV-*6ES&pV9PT+6;sPa`7*B#f-uo1QMwJbS2&oj#FvYT5RyM=4CP z-<7AQFxfEbtvNNH7SIoOb`Fp(f}6)`uKPtdv=?OWvmxz^b6u!^{<$jRJ|r)yhdD+P zIZ|PNYL6y$keBo*J%xI_OcxOGxLH8^5E70sx`ACk?uq@A$PwN2lqF>t3x zI(;6;;G{;+!g)M8vSqAZ)2)gAGJBl-^)}vx5+F}RAi6@aW?__??y?<9j_q>Kz-TmG zE0mz;lwbA|s!5(t_4rXxL-SyYR;rzTUSwMO{HYUlOxjSC>RoCs`L%}YuyWdY?RAVy z=p-EURU{{Dc*lL(w5z*-!d54~nYZTkHC10!CR?RGqY_YF1>LpG6Wb{sPq4e(jWN|Bv zxIFt|`DS@`{$pTh$f#WZVBseG5L>D~K#OcQGq62^mBw}BvmYur7@dK|)u25{a9imx z5F@(;OYhrN9=W;>W4+m#e+gCi#!Mg@L-HnCsQ5s2JQ@neFm`?zU86We(I_e=SZ}rn z&)SvjY@fX3dHhieRnzxrZL#Uw9vx@jWzU`*A{b(qk9`ZAcr)y2cDNAfA_=0B7*WM6 zfp0_=Q$!|NF-BtSOm4xzr05_LzPCk0{C>O;{LVaiehnP&&Op9}Xa>pARC0uGA(eqB z>{0HO8AK&LY2>fFrqft{dv0$0@TsrxcK{d67<`HN;GckEE!nf&R38>6OdqNGjfUgV l7%O!brsE*vabK2DC||8Ntfpg6<4$|n-UQS|hA*B8@qY{JqGbR8 delta 1544 zcmZuxO>7%Q6rR~1@7l4~uAQX$YXdZC*wiGY2U?)1KtL)GvVerDSfJG=J59D(ualW^ z)xcUD0^$TJ%#lkY^^y}phzk;D1P8=<4;)boN5rKk-W!XivasbhZ{Ey%?|bik;~&r6 z^S!WADG~U*8Qc%|XTJ1i-d=@WL?W7y^}$N@Y9vO-Y?~BqW@2^hwykw5DRi8+L&;SV z*-_yW5)}@Nwi`KX#CIQH=x=}UEV`0kl22kB9qbHfzM+e6S2l$Rc6oO<&G}E!_0*)*ZLz_>24z%$%=;tC3}CQ z(Te`6B7l%!te#;|}E)vRN9Hw28uKMq2zdpkH0r{d`DY z;%C3APdG-uW%u;;yhM|Z$YyzFXAi)OnDlO4HWp4_>=03`oxrG*&^(Vja3IyJ`3QoEE9(2kT-|hO$?%Ml zQKl}f83k&oe;V($FJih06dH_v-5Q}TMWfaLH8v#0V2m2?Yq&k0rPlDTh8I9M>fY!X z2ep=8RMoMS4px>|UrxiMyYb%7 diff --git a/AnalogCSS/__pycache__/ShorthandProperty.cpython-39.pyc b/AnalogCSS/__pycache__/ShorthandProperty.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14eea779b80fcd82e7365cf2699570f58c14e30a GIT binary patch literal 1676 zcmZ`(OK%e~5VpO$$!43T@0J!JRR|;&L~}tLDpa+q0D&M>MD(x-t+w?h-F6?r>r_gV zTl*ilw#WV@UpaAuD<@{WZPF^ilE>q*XXf)f986C;1jg?le}aKU$WPqd9tLc-VdgJ^ zaKdR!66#TkJd0Ukc!uVU*i0< z8QkC|tl*!QV6}Le+pv~+g*&j8`4ph3s<|PIJ&|=nA$y1T%$tEcy4i)9Zvh$50r82X z19pZSlg1f=)#OO60Xb&JCE&^fa$#ShtOA^KNiZ-?azz{Nl&W;Vl^+}&2!XcMOsgBm zz80QhEChO0wY#CX*6OB_RF=M`oRNxJz~B{jr4-RYSBANAf)Q`$Z~?VlLz#IPx4b31 zjxW|w!qX^_QI>iOLp1tKySgG`4lw<%!JDt%DxGJYlt%Fi3$*9o`k*pii%m3;HwKVkK8nn zMVPq>gwR>qe>@IyLMHx?_X*hH8XclsCD)iAA>KlA7qeNUP(v+1FM$QIjN~p@HH$!a z*oxAS>&)MSOF2fH&_%@la5DDWDr3Nh&9DJx5acnH?1YJ@nm2T?$+3YgkvdTNmTm%Q zk0uf5+ARqi7G=sF)EMt|+=vv2F~8gD*ru4A`s=-$%Ju-RXobcTu9gyyn3B1)yG zf}i45lX7E5X)AjSSFS6mM*GX-*}zK;*Tz;!gCz8Q<@kP*@otQK)%U-5gSa>m3+NB) zvxp)_Ox#B@stV2NI)>k!;LI`XHnnTEXfW%GH-@P8_1C07ti{o>{Z+RV>Z<--6anj5(X^rF7Z6; z2VmeZ5T?=p=Bv*Rj|ZlS%;E8qgU4SQZ}9c;lm5|=Hm(ki!amOG5t4+3AX&&INdA(A zLJH~Niq}aGS64QqkE<0-^STA8IsNGK|IX^oYnhC<}hbb zO_4k27Yt>AoMSl`Iq!l|=x7`IK_hIc_^0TUEE~68x}!wbnn<5b6608UkF?Vw)zLFm z=2s^iQkd=}R#k%fc&O8|2)J>oBzvY16!t4qU0hxr^~PnM^mLl{o~m-B;yh1_QSa%Q z9+yS$aS>l_l<@v5=mk)_4r&YkTK{XZjiPC%)lI1Mzp{Y9?BT}UE8G76`iE$ME|>6t zX*gwSNAm&GVo)Q*`-;2`9P5yxidGI0m>g%I>Xq%17}I&Wh5*pbHM4y}jYtI=*Yp zkzF!j3+gXquwd8)Q-7k9p!sudIbq#(PC@;KdU5VbegO;6-W;UZWx7GyB`o>p?E7rN zNt$yEkWTEAB-xz*jGBeezHaK)T%5PbhIAgVC9KGT)U{3U@KY^i&sXcDpMr^>cy7&k3s z^1`?(E=GwFSyC8LX@!b%T1X?(LL0Z5WT{qdGUeKuGVLmht1(tG9fs7jk{1(|R28<5 z*-oerW1Yyl%QhkIpq)2yR`-!G*nuwZzehT~XmhD#m#9?q*?-+?>eV~DeNUsKf^?^8eU>Afi8Jc%OH zilV%f(~S5|6rD`ttp1~@VQPq}_7x>q(X}hC*fyj7SJYV4Ce|Mx{Dv=l&%bN+cpq0u s*wD`r_e3eG93r0<15NvH$=8 literal 0 HcmV?d00001 diff --git a/AnalogCSS/__pycache__/tools.cpython-39.pyc b/AnalogCSS/__pycache__/tools.cpython-39.pyc index d9669251113d7c26fe7ebe6729bde011113e9ef8..ea883d22a24a98b6eec75c92e41e1284a7fbc16d 100644 GIT binary patch delta 625 zcmZ8dO>5Oa6wOQ~Uz3m47g~!{2-JlS!G-H06e&`vZ}IvB$-oUe@FLO^)I+`C3q)=s?ET;Irn4cocoJk`B5H*+`#Yar=R(jy^JArdCh+^5Svady_Y> zcc*(VcJ_PwU^d;Gyj)(sCqcJGCMz4LSuyQ{1Vl#NIXQggAnUC&S+?T4DYePe(GQBc zl|C{V+(M{Z`OunaVVlVRUKita@9yVvRril>hlcU6`$pqY@?ZZNvgPH2?wWqyxAA{6 zW^xe2PE=F(R@LO7q>B~lX}F`qlOl&qw?4w^jSPmaHo70?7ZP>5Oib^LtR0CqE2>;6 zp|ZJb7K4i?dR*%@h--0T(|~eZk4qvVA7XYK_D+^TQ)HQ3?|!p!rZ*@p4UvXegLWhJ meutTV#NPPFLho)b8aS=QbAn8*BQVRQ_!4CVkMFYKIDY^ngn^j= delta 525 zcmZut%}T>S5Y8mK$u>z-W2J{G-UM^;E=aF}NI~o=h+*qQsiaBSM0^47+U6Yu-@!NV z;Jr`a8+dg#LR-OInBg0~@0*`b@7oPzyX_kElJS=u@OiKoj|icGkQwoBh8PH&nK`v$ z3v|uO*vLQ@bL4108L^EH3d#<)(4{QUL!WXB+Za%G5iX6WGk-su2`%}fnpEkVr39haxhe80%`4R+r1ZSM!P8W?p(eMJEbS3q+l6Fz zeJoX=`CBVdBX5*}oXyf4ld5Rc{Xgn%9ayjDdbVN2R5KL2FN=K1vqEC2Y;EZLn+$b`1K1*y^RePynl3{dHNIv2=0Py`ry(%1O%XVsTz5)km_zGRhg=t s`jkf(K9yCdLstjActhPd&U#OAGA-~SO9w!-rjY<0Na6JkpKVy diff --git a/AnalogCSS/tools.py b/AnalogCSS/tools.py index 64c0d7c..8e2b281 100644 --- a/AnalogCSS/tools.py +++ b/AnalogCSS/tools.py @@ -9,6 +9,8 @@ from AnalogCSS.syntax import * NUMBERS = "0123456789" +NUMERICAL = "NUMERICAL" +STRING = "STRING" # def get_args(): # parser = argparse.ArgumentParser() diff --git a/analog_config.json b/analog_config.json index 257a872..dbc6ec5 100644 --- a/analog_config.json +++ b/analog_config.json @@ -14,11 +14,13 @@ "class_mappings": { "p": { - "property": "padding" + "property": "padding", + "unit": "rem" }, "px": { - "property": ["padding-left", "padding-right"] + "property": ["padding-left", "padding-right"], + "unit": "em" }, "m": { diff --git a/analog_css.py b/analog_css.py index d2d1c26..4382e32 100644 --- a/analog_css.py +++ b/analog_css.py @@ -33,6 +33,7 @@ except KeyboardInterrupt: # Make sure the program generates all the classes again before quitting. print("[+] Generating classes one more time.") + write_file(output_path, "") for _class in generated_classes: append_to_file(output_path, _class) From e369f67afdc38c98ccea72147f439760901143a8 Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Wed, 26 Jan 2022 16:33:49 -0500 Subject: [PATCH 07/10] set default configuration --- analog_config.json | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/analog_config.json b/analog_config.json index dbc6ec5..ca9bc6b 100644 --- a/analog_config.json +++ b/analog_config.json @@ -6,8 +6,7 @@ "input_extensions": [".html", ".php"], "custom_values": { - "dark_red": "rgb(255, 50, 50)", - "col": "column" + "col": "column", }, "media_query_type": "min-width", @@ -20,23 +19,27 @@ "px": { "property": ["padding-left", "padding-right"], - "unit": "em" + "unit": "rem" }, - "m": { - "property": "margin" + "py": { + "property": ["padding-top", "padding-bottom"], + "unit": "rem" }, - - "mt": { - "property": "margin-top" + + "m": { + "property": "margin", + "unit": "rem" }, - - "mb": { - "property": "margin-bottom" + + "my":{ + "property": ["margin-top", "margin-bottom"], + "unit": "rem" }, "mx":{ - "property": ["margin-left", "margin-right"] + "property": ["margin-left", "margin-right"], + "unit": "rem" }, "max-w": { @@ -74,9 +77,9 @@ "breakpoint_values": { "xs": "300px", - "sm": "500px", - "md": "900px", - "lg": "1300px", - "xl": "1600px" + "sm": "600px", + "md": "1000px", + "lg": "1400px", + "xl": "1700px" } -} \ No newline at end of file +} From 73ccc75a46ffd1a35dd56f46e64525691f5e6d1e Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Wed, 26 Jan 2022 16:54:02 -0500 Subject: [PATCH 08/10] Removed empty `class` attributes. --- index.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/index.html b/index.html index 1ef91b3..23912cc 100644 --- a/index.html +++ b/index.html @@ -6,11 +6,11 @@ - -

    Analog CSS

    + +

    Analog CSS

    -
    +
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas culpa, amet voluptatum molestias excepturi quibusdam deserunt id eligendi, delectus harum sequi ut reprehenderit tempore dolorem quod nobis quis aperiam neque! Ducimus tenetur fugit necessitatibus ex perferendis harum tempora quod laboriosam, sapiente nisi iste amet sequi? Alias, autem atque deleniti natus minima assumenda sapiente doloremque hic laboriosam, recusandae neque ipsa praesentium! Ea laudantium, incidunt deleniti reprehenderit natus eum, vel autem ullam vero quos exercitationem necessitatibus? Placeat ad iure earum nihil culpa, voluptatem repudiandae aliquam rerum nostrum nisi distinctio? Incidunt, molestiae animi? @@ -23,7 +23,7 @@

    Analog CSS

    Architecto doloremque odit impedit ipsum recusandae non ipsa distinctio autem voluptatem assumenda quam obcaecati, cumque rerum maxime sapiente libero eveniet labore. Corrupti debitis voluptas nam fugiat consequatur fuga quae! Tenetur?
    -
    +
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate alias dolorem molestiae tempore amet corporis placeat ut. Et minus dolores, repellendus esse voluptates animi nihil earum ea mollitia dolor. Necessitatibus, rerum consectetur! Repellendus sit debitis est rerum itaque fugiat velit maxime odit perspiciatis a dolor nihil voluptatum commodi reiciendis, ducimus libero iure nulla alias culpa cum ad impedit excepturi! Sunt accusamus fugit explicabo sit ex nam aut totam eligendi hic commodi rem, itaque deserunt odit beatae adipisci! Cupiditate blanditiis modi numquam tenetur fugiat est sint, nihil quia eum ut. @@ -37,7 +37,7 @@

    Analog CSS

    I think this is pretty cool

    -
    +
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate alias dolorem molestiae tempore amet corporis placeat ut. Et minus dolores, repellendus esse voluptates animi nihil earum ea mollitia dolor. Necessitatibus, rerum consectetur! Repellendus sit debitis est rerum itaque fugiat velit maxime odit perspiciatis a dolor nihil voluptatum commodi reiciendis, ducimus libero iure nulla alias culpa cum ad impedit excepturi! Sunt accusamus fugit explicabo sit ex nam aut totam eligendi hic commodi rem, itaque deserunt odit beatae adipisci! Cupiditate blanditiis modi numquam tenetur fugiat est sint, nihil quia eum ut. @@ -50,7 +50,7 @@

    I think this is pretty cool

    Corporis sint ab nostrum magni corrupti vitae ad assumenda magnam. Iste a asperiores totam debitis officiis velit animi quaerat veniam recusandae eos sit quam repellendus, eveniet explicabo tenetur nemo vitae.
    -
    +
    Lorem ipsum dolor sit amet consectetur adipisicing elit. Quas cupiditate alias dolorem molestiae tempore amet corporis placeat ut. Et minus dolores, repellendus esse voluptates animi nihil earum ea mollitia dolor. Necessitatibus, rerum consectetur! Repellendus sit debitis est rerum itaque fugiat velit maxime odit perspiciatis a dolor nihil voluptatum commodi reiciendis, ducimus libero iure nulla alias culpa cum ad impedit excepturi! Sunt accusamus fugit explicabo sit ex nam aut totam eligendi hic commodi rem, itaque deserunt odit beatae adipisci! Cupiditate blanditiis modi numquam tenetur fugiat est sint, nihil quia eum ut. @@ -64,4 +64,4 @@

    I think this is pretty cool

    - \ No newline at end of file + From b377448fca292504d380a6ae60d5d9c5b1395050 Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Wed, 26 Jan 2022 18:10:43 -0500 Subject: [PATCH 09/10] Created brief documentation --- README.md | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 81bc276..7b11598 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,93 @@ # AnalogCSS -A CSS framework for people who hate CSS +#### A programatic CSS utility framework to generate utility classes on the fly, without clouding up your stylesheet or markup. + +# Quick and basic usage instructions: +Download the code from this repo: https://github.com/Jammin-Coder/AnalogCSS/archive/refs/heads/main.zip +Unzip the `AnalogCSS-main.zip` folder, after it's extracted you should have an `AnalogCSS-main` folder. Open that folder and copy all of the contents into a directory of your choice. +There is a `.html` file inside of that directory, open it up in a code editor of your choice, and also open it in a web browser. As you can see, it's just a basic HTML document with a couple headers and some divs. Now it's time to style!! +As you can see at the top of the HTML file, we are linking to 2 CSS files, one is called `analog.css`, and one is called `app.css`. `analog.css` is the CSS file to which the program outputs generated CSS, and is not for you to write your styles in, lest they be deleted when the program runs. You can create any styles you want in `app.css`. NOTE: The order in which the CSS files are linked to makes a differance in deciding which styles should be applyed if there are confilcting styles being applyed to the same element. If you want all of the `analog.css` classes to have prevalence over the classes you write in `app.css`, then make sure to link to `app.css` AFTER linking to `analog.css`. + + + +## Run the program +To make AnalogCSS watch your HTML file, run `python analog_css.py`. This will start AnalogCSS, and thus will monitor your HTML files for new styles to generate. +At the moment, there are no styles, so... + +### Apply Analog styles. +The generale syntax of an AnalogCSS class is `[breakpoint:]=`, where `[breakpoint:]` is an optional breakpoint, `` is the name of the CSS property which you are tergeting, and `` is the value of the property. +If you are confused, read on! If you're not confused, you should still read on! + +In the `body` tag of the HTML file, add this class to it: `p=2` (you can replace `2` with whatever number you want, even decimals or fractions), then refresh the page. +You will notice the entire page now has a padding of `2rem`. + +# Understanding how it works. +There is a JSON file, `analog_config.json`, and in that file there is a JSON object called `class_mappings`. In this object, there are more objects +with names of your choice, and those names are mapped to properties. +```json +"p": { + "property": "padding", + "unit": "rem" +} +``` +For example In the class name you entered in the `body` tag, it says `p=`. AnalogCSS reads this class name, and determines that `p` means `padding` +since the `"property"` key of `"p"` is mapped to `"padding"`. It also knows to use `rem` as the unit becuase the `"unit"` key is mapped to `"rem"`. +The program then extracts the value that you assigned to `p`, and evaluates that it should be `2rem`. After that, this information is used to generate a CSS class with the name of `.p\=2` and the property of `padding: 2rem;`. If there is no corresponding class for the property, the program will read it as a litteral css property. For example if I made a class in my markup called `display=flex`, the program woud generate a class called `display\=flex` and have the attribute be `display: flex;`. +Regardless of the property type, this class is then written to `analog.css` and now the browser can apply it's styles. +Note there is a backslash(`\`) in the name becuase an eqals (`=`) is a special character, and not usually supposed to be used for class names. In this case it's OK since we don't have to ever work with or look at the contents of `analog.css`. + +If you would like to apply the same value to 2 properties, for example setting the `padding-left` and `padding-right` of an element to the same value, you can supply the propertie names in an array in the `property` field of the shorthand class object, like this: +```json +"px": { + "property": ["padding-left", "padding-right"], + "unit": "rem" +} +``` +This will allow you to use the `px=` class to apply padding to the side of elements. + +### What if you want to apply styles with different units? +Not a problem at all! You can specify a unit directly in the class name! Like this: +```html +
    +``` +Since `em` is appended to the value, the program will know to use `em` instead of `rem`. You don't even need to specify a `"unit"` field in the classes JSON object, so long as the value you provide to the class name is a valid value for the corresponding class. + +## Breakpoints +To use breakpoints in AnalogCSS, simply prepend one of the following breakpoints to your AnalogCSS class: +`xs`, +`sm`, +`md`, +`lg`, +`xl` +followed by a colon (`:`) like this: +```html +
    +``` +Assuming there is an `"m"` object for `margin` in the `"class_mappings"`, this will generate a class that sets the margin of the element to `0.5em` when the screen is below the small (`sm`) breakpoint, but once the screen's width is greater than the small breakpoint, it will have a margin of `1em`. +The breakpoints are defined in the `"breakpoints"` object in `analog_config.json`. +If you would like to use a breakpoint without adding it to `"breakpoints"`, the simply prepend `@breakpoint-value:` to your class name, like this: +```html +
    + Below 400px I have a margin of 0.5em, but greater than 400px I have a margin of 1em. +
    +``` +This will yeild a similar result to using the `sm` breakpoint, but you can change the breakpoint directly in your markup. + +### Applying your own classes at specific breakpoints +Say you have a class in your own CSS file (`app.css` or other) that changes an element's theme to dark when the screen reaches the large breakpoint: +```css +.dark-mode { + background-color: #333; + color: white; +} +``` +Instead of writing a media query for this, you could just do this: +```html +
    + I go to the dark side if the screen is bigger than the supplied breakpoint! +
    +``` +Again, you can use custom breakpoint values for this. + +# More documentation to come! +Feel free star and watch this repository if you are interested in following the development of this framework, as I plan to work on it frequently! + From a7a386136160610acbc48786f603e0cddd458c8e Mon Sep 17 00:00:00 2001 From: "T.R Batt" <73239367+Jammin-Coder@users.noreply.github.com> Date: Wed, 26 Jan 2022 18:19:23 -0500 Subject: [PATCH 10/10] Create LICENSE.md --- LICENSE.md | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work.