|
@@ -18,7 +18,7 @@ class Property:
|
|
|
|
|
|
def __post_init__(self) -> None:
|
|
def __post_init__(self) -> None:
|
|
words = [s.split('-') for s in self.members]
|
|
words = [s.split('-') for s in self.members]
|
|
- prefix = words[0] # pylint: disable=redefined-outer-name
|
|
|
|
|
|
+ prefix = words[0]
|
|
for w in words:
|
|
for w in words:
|
|
i = 0
|
|
i = 0
|
|
while i < len(prefix) and i < len(w) and prefix[i] == w[i]:
|
|
while i < len(prefix) and i < len(w) and prefix[i] == w[i]:
|
|
@@ -63,98 +63,109 @@ def get_soup(url: str) -> BeautifulSoup:
|
|
return BeautifulSoup(html, 'html.parser')
|
|
return BeautifulSoup(html, 'html.parser')
|
|
|
|
|
|
|
|
|
|
-soup = get_soup('https://tailwindcss.com/docs')
|
|
|
|
-for li in soup.select('li[class="mt-12 lg:mt-8"]'):
|
|
|
|
- title = li.select_one('h5').text
|
|
|
|
- links = li.select('li a')
|
|
|
|
- if title in {'Getting Started', 'Core Concepts', 'Customization', 'Base Styles', 'Official Plugins'}:
|
|
|
|
- continue
|
|
|
|
- print(f'{title}:')
|
|
|
|
- for a in links:
|
|
|
|
- soup = get_soup(f'https://tailwindcss.com{a["href"]}')
|
|
|
|
- title = soup.select_one('#header h1').text
|
|
|
|
- description = soup.select_one('#header .mt-2').text
|
|
|
|
- members = soup.select('.mt-10 td[class*=text-sky-400]')
|
|
|
|
- properties.append(Property(title, description, [p.text.split(' ')[0] for p in members]))
|
|
|
|
- print(f'\t{title} ({len(members)})')
|
|
|
|
-
|
|
|
|
-for file in (Path(__file__).parent / 'nicegui' / 'tailwind_types').glob('*.py'):
|
|
|
|
- file.unlink()
|
|
|
|
-(Path(__file__).parent / 'nicegui' / 'tailwind_types' / '__init__.py').touch()
|
|
|
|
-for property_ in properties:
|
|
|
|
- if not property_.members:
|
|
|
|
- continue
|
|
|
|
- with (Path(__file__).parent / 'nicegui' / 'tailwind_types' / f'{property_.snake_title}.py').open('w') as f:
|
|
|
|
- f.write('from typing import Literal\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write(f'{property_.pascal_title} = Literal[\n')
|
|
|
|
- for short_member in property_.short_members:
|
|
|
|
- f.write(f" '{short_member}',\n")
|
|
|
|
- f.write(']\n')
|
|
|
|
-
|
|
|
|
-with (Path(__file__).parent / 'nicegui' / 'tailwind.py').open('w') as f:
|
|
|
|
- f.write('# pylint: disable=too-many-lines\n')
|
|
|
|
- f.write('from __future__ import annotations\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write('from typing import TYPE_CHECKING, List, Optional, Union, overload\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write('if TYPE_CHECKING:\n')
|
|
|
|
- f.write(' from .element import Element\n')
|
|
|
|
- for property_ in sorted(properties, key=lambda p: p.title):
|
|
|
|
- if not property_.members:
|
|
|
|
|
|
+def process_properties():
|
|
|
|
+ soup = get_soup('https://tailwindcss.com/docs')
|
|
|
|
+ for li in soup.select('li[class="mt-12 lg:mt-8"]'):
|
|
|
|
+ title = li.select_one('h5').text
|
|
|
|
+ links = li.select('li a')
|
|
|
|
+ if title in {'Getting Started', 'Core Concepts', 'Customization', 'Base Styles', 'Official Plugins'}:
|
|
continue
|
|
continue
|
|
- f.write(f' from .tailwind_types.{property_.snake_title} import {property_.pascal_title}\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write('class PseudoElement:\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write(' def __init__(self) -> None:\n')
|
|
|
|
- f.write(' self._classes: List[str] = []\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write(' def classes(self, add: str) -> None:\n')
|
|
|
|
- f.write(' """Add the given classes to the element."""\n')
|
|
|
|
- f.write(' self._classes.append(add)\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write('class Tailwind:\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write(" def __init__(self, _element: Optional[Element] = None) -> None:\n")
|
|
|
|
- f.write(' self.element: Union[PseudoElement, Element] = PseudoElement() if _element is None else _element\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write(' @overload\n')
|
|
|
|
- f.write(' def __call__(self, tailwind: Tailwind) -> Tailwind:\n')
|
|
|
|
- f.write(' ...\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write(' @overload\n')
|
|
|
|
- f.write(' def __call__(self, *classes: str) -> Tailwind:\n')
|
|
|
|
- f.write(' ...\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write(' def __call__(self, *args) -> Tailwind: # type: ignore\n')
|
|
|
|
- f.write(' if not args:\n')
|
|
|
|
- f.write(' return self\n')
|
|
|
|
- f.write(' if isinstance(args[0], Tailwind):\n')
|
|
|
|
- f.write(' args[0].apply(self.element) # type: ignore\n')
|
|
|
|
- f.write(' else:\n')
|
|
|
|
- f.write(" self.element.classes(' '.join(args))\n")
|
|
|
|
- f.write(' return self\n')
|
|
|
|
- f.write('\n')
|
|
|
|
- f.write(" def apply(self, element: Element) -> None:\n")
|
|
|
|
- f.write(' """Apply the tailwind classes to the given element."""\n')
|
|
|
|
- f.write(' element._classes.extend(self.element._classes) # pylint: disable=protected-access\n')
|
|
|
|
- f.write(' element.update()\n')
|
|
|
|
|
|
+ print(f'{title}:')
|
|
|
|
+ for a in links:
|
|
|
|
+ soup = get_soup(f'https://tailwindcss.com{a["href"]}')
|
|
|
|
+ title = soup.select_one('#header h1').text
|
|
|
|
+ description = soup.select_one('#header .mt-2').text
|
|
|
|
+ members = soup.select('.mt-10 td[class*=text-sky-400]')
|
|
|
|
+ properties.append(Property(title, description, [p.text.split(' ')[0] for p in members]))
|
|
|
|
+ print(f'\t{title} ({len(members)})')
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def generate_type_files():
|
|
|
|
+ for file in (Path(__file__).parent / 'nicegui' / 'tailwind_types').glob('*.py'):
|
|
|
|
+ file.unlink()
|
|
|
|
+ (Path(__file__).parent / 'nicegui' / 'tailwind_types' / '__init__.py').touch()
|
|
for property_ in properties:
|
|
for property_ in properties:
|
|
|
|
+ if not property_.members:
|
|
|
|
+ continue
|
|
|
|
+ with (Path(__file__).parent / 'nicegui' / 'tailwind_types' / f'{property_.snake_title}.py').open('w') as f:
|
|
|
|
+ f.write('from typing import Literal\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write(f'{property_.pascal_title} = Literal[\n')
|
|
|
|
+ for short_member in property_.short_members:
|
|
|
|
+ f.write(f" '{short_member}',\n")
|
|
|
|
+ f.write(']\n')
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def generate_tailwind_file():
|
|
|
|
+ with (Path(__file__).parent / 'nicegui' / 'tailwind.py').open('w') as f:
|
|
|
|
+ f.write('# pylint: disable=too-many-lines\n')
|
|
|
|
+ f.write('from __future__ import annotations\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write('from typing import TYPE_CHECKING, List, Optional, Union, overload\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write('if TYPE_CHECKING:\n')
|
|
|
|
+ f.write(' from .element import Element\n')
|
|
|
|
+ for property_ in sorted(properties, key=lambda p: p.title):
|
|
|
|
+ if not property_.members:
|
|
|
|
+ continue
|
|
|
|
+ f.write(f' from .tailwind_types.{property_.snake_title} import {property_.pascal_title}\n')
|
|
|
|
+ f.write('\n')
|
|
f.write('\n')
|
|
f.write('\n')
|
|
- prefix = property_.common_prefix
|
|
|
|
- if property_.members:
|
|
|
|
- f.write(f" def {property_.snake_title}(self, value: {property_.pascal_title}) -> Tailwind:\n")
|
|
|
|
- f.write(f' """{property_.description}"""\n')
|
|
|
|
- if '' in property_.short_members:
|
|
|
|
- f.write(f" self.element.classes('{prefix}' + value if value else '{prefix.rstrip('''-''')}')\n")
|
|
|
|
|
|
+ f.write('class PseudoElement:\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write(' def __init__(self) -> None:\n')
|
|
|
|
+ f.write(' self._classes: List[str] = []\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write(' def classes(self, add: str) -> None:\n')
|
|
|
|
+ f.write(' """Add the given classes to the element."""\n')
|
|
|
|
+ f.write(' self._classes.append(add)\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write('class Tailwind:\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write(" def __init__(self, _element: Optional[Element] = None) -> None:\n")
|
|
|
|
+ f.write(' self.element: Union[PseudoElement, Element] = PseudoElement() if _element is None else _element\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write(' @overload\n')
|
|
|
|
+ f.write(' def __call__(self, tailwind: Tailwind) -> Tailwind:\n')
|
|
|
|
+ f.write(' ...\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write(' @overload\n')
|
|
|
|
+ f.write(' def __call__(self, *classes: str) -> Tailwind:\n')
|
|
|
|
+ f.write(' ...\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write(' def __call__(self, *args) -> Tailwind: # type: ignore\n')
|
|
|
|
+ f.write(' if not args:\n')
|
|
|
|
+ f.write(' return self\n')
|
|
|
|
+ f.write(' if isinstance(args[0], Tailwind):\n')
|
|
|
|
+ f.write(' args[0].apply(self.element) # type: ignore\n')
|
|
|
|
+ f.write(' else:\n')
|
|
|
|
+ f.write(" self.element.classes(' '.join(args))\n")
|
|
|
|
+ f.write(' return self\n')
|
|
|
|
+ f.write('\n')
|
|
|
|
+ f.write(" def apply(self, element: Element) -> None:\n")
|
|
|
|
+ f.write(' """Apply the tailwind classes to the given element."""\n')
|
|
|
|
+ f.write(' element._classes.extend(self.element._classes) # pylint: disable=protected-access\n')
|
|
|
|
+ f.write(' element.update()\n')
|
|
|
|
+ for property_ in properties:
|
|
|
|
+ f.write('\n')
|
|
|
|
+ prefix = property_.common_prefix
|
|
|
|
+ if property_.members:
|
|
|
|
+ f.write(f" def {property_.snake_title}(self, value: {property_.pascal_title}) -> Tailwind:\n")
|
|
|
|
+ f.write(f' """{property_.description}"""\n')
|
|
|
|
+ if '' in property_.short_members:
|
|
|
|
+ f.write(f" self.element.classes('{prefix}' + value if value else '{prefix.rstrip('''-''')}')\n")
|
|
|
|
+ else:
|
|
|
|
+ f.write(f" self.element.classes('{prefix}' + value)\n")
|
|
|
|
+ f.write(f' return self\n') # pylint: disable=f-string-without-interpolation
|
|
else:
|
|
else:
|
|
- f.write(f" self.element.classes('{prefix}' + value)\n")
|
|
|
|
- f.write(f' return self\n') # pylint: disable=f-string-without-interpolation
|
|
|
|
- else:
|
|
|
|
- f.write(f" def {property_.snake_title}(self) -> Tailwind:\n")
|
|
|
|
- f.write(f' """{property_.description}"""\n')
|
|
|
|
- f.write(f" self.element.classes('{prefix}')\n")
|
|
|
|
- f.write(f' return self\n') # pylint: disable=f-string-without-interpolation
|
|
|
|
|
|
+ f.write(f" def {property_.snake_title}(self) -> Tailwind:\n")
|
|
|
|
+ f.write(f' """{property_.description}"""\n')
|
|
|
|
+ f.write(f" self.element.classes('{prefix}')\n")
|
|
|
|
+ f.write(f' return self\n') # pylint: disable=f-string-without-interpolation
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+if __name__ == "__main__":
|
|
|
|
+ process_properties()
|
|
|
|
+ generate_type_files()
|
|
|
|
+ generate_tailwind_file()
|