eidosui 0.4.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- # Markdown plugin extensions
1
+ # Markdown plugin extensions
@@ -1,134 +1,124 @@
1
1
  """GitHub-style alerts extension for markdown"""
2
2
 
3
3
  import re
4
- from markdown.extensions import Extension
5
- from markdown.blockprocessors import BlockProcessor
6
4
  import xml.etree.ElementTree as etree
7
5
  from xml.etree.ElementTree import SubElement
8
6
 
7
+ from markdown.blockprocessors import BlockProcessor
8
+ from markdown.extensions import Extension
9
+
9
10
 
10
11
  class AlertBlockProcessor(BlockProcessor):
11
12
  """Process GitHub-style alert blocks"""
12
-
13
+
13
14
  # Pattern to match > [!TYPE] at the start of a blockquote
14
- RE_ALERT = re.compile(r'^> \[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]', re.MULTILINE)
15
-
15
+ RE_ALERT = re.compile(r"^> \[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]", re.MULTILINE)
16
+
16
17
  # Alert type configurations
17
18
  ALERT_TYPES = {
18
- 'NOTE': {
19
- 'class': 'eidos-alert eidos-alert-info',
20
- 'icon': 'ℹ️',
21
- 'title': 'Note'
19
+ "NOTE": {"class": "eidos-alert eidos-alert-info", "icon": "ℹ️", "title": "Note"},
20
+ "TIP": {
21
+ "class": "eidos-alert eidos-alert-success",
22
+ "icon": "💡",
23
+ "title": "Tip",
22
24
  },
23
- 'TIP': {
24
- 'class': 'eidos-alert eidos-alert-success',
25
- 'icon': '💡',
26
- 'title': 'Tip'
25
+ "IMPORTANT": {
26
+ "class": "eidos-alert eidos-alert-warning",
27
+ "icon": "❗",
28
+ "title": "Important",
27
29
  },
28
- 'IMPORTANT': {
29
- 'class': 'eidos-alert eidos-alert-warning',
30
- 'icon': '❗',
31
- 'title': 'Important'
30
+ "WARNING": {
31
+ "class": "eidos-alert eidos-alert-warning",
32
+ "icon": "⚠️",
33
+ "title": "Warning",
32
34
  },
33
- 'WARNING': {
34
- 'class': 'eidos-alert eidos-alert-warning',
35
- 'icon': '⚠️',
36
- 'title': 'Warning'
35
+ "CAUTION": {
36
+ "class": "eidos-alert eidos-alert-error",
37
+ "icon": "🔴",
38
+ "title": "Caution",
37
39
  },
38
- 'CAUTION': {
39
- 'class': 'eidos-alert eidos-alert-error',
40
- 'icon': '🔴',
41
- 'title': 'Caution'
42
- }
43
40
  }
44
-
41
+
45
42
  def test(self, parent, block):
46
43
  """Test if the block is a GitHub-style alert"""
47
44
  return bool(self.RE_ALERT.match(block))
48
-
45
+
49
46
  def run(self, parent, blocks):
50
47
  """Process the alert block"""
51
48
  block = blocks.pop(0)
52
-
49
+
53
50
  # Extract alert type
54
51
  match = self.RE_ALERT.match(block)
55
52
  if not match:
56
53
  return False
57
-
54
+
58
55
  alert_type = match.group(1)
59
- alert_config = self.ALERT_TYPES.get(alert_type, self.ALERT_TYPES['NOTE'])
60
-
56
+ alert_config = self.ALERT_TYPES.get(alert_type, self.ALERT_TYPES["NOTE"])
57
+
61
58
  # Create the alert container
62
- alert_div = SubElement(parent, 'div')
63
- alert_div.set('class', alert_config['class'])
64
-
59
+ alert_div = SubElement(parent, "div")
60
+ alert_div.set("class", alert_config["class"])
61
+
65
62
  # Add the header with icon and title
66
- header = SubElement(alert_div, 'div')
67
- header.set('class', 'eidos-alert-header')
68
-
69
- icon_span = SubElement(header, 'span')
70
- icon_span.set('class', 'eidos-alert-icon')
71
- icon_span.text = alert_config['icon']
72
-
73
- title_span = SubElement(header, 'span')
74
- title_span.set('class', 'eidos-alert-title')
75
- title_span.text = alert_config['title']
76
-
77
- # Process the content
78
- content_div = SubElement(alert_div, 'div')
79
- content_div.set('class', 'eidos-alert-content')
80
-
63
+ header = SubElement(alert_div, "div")
64
+ header.set("class", "eidos-alert-header")
65
+
66
+ icon_span = SubElement(header, "span")
67
+ icon_span.set("class", "eidos-alert-icon")
68
+ icon_span.text = alert_config["icon"]
69
+
70
+ title_span = SubElement(header, "span")
71
+ title_span.set("class", "eidos-alert-title")
72
+ title_span.text = alert_config["title"]
73
+
74
+ content_div = SubElement(alert_div, "div")
75
+ content_div.set("class", "eidos-alert-content")
76
+
81
77
  # Remove the alert marker and process the remaining content
82
- content = self.RE_ALERT.sub('', block)
83
-
84
- # Handle multi-line content
85
- lines = content.split('\n')
78
+ content = self.RE_ALERT.sub("", block)
79
+
80
+ lines = content.split("\n")
86
81
  processed_lines = []
87
-
82
+
88
83
  for line in lines:
89
84
  # Remove leading '>' from each line
90
- if line.startswith('>'):
85
+ if line.startswith(">"):
91
86
  line = line[1:].lstrip()
92
87
  processed_lines.append(line)
93
-
94
- # Join the content and parse it
95
- content_text = '\n'.join(processed_lines).strip()
96
-
88
+
89
+ content_text = "\n".join(processed_lines).strip()
90
+
97
91
  # Parse the content as markdown
98
92
  if content_text:
99
- # Create a temporary element to hold parsed content
100
- temp_element = etree.Element('div')
93
+ temp_element = etree.Element("div")
101
94
  self.parser.parseBlocks(temp_element, [content_text])
102
-
103
- # Move all children to our content div
95
+
104
96
  for child in temp_element:
105
97
  content_div.append(child)
106
-
107
- # If no children were added, add the text directly
98
+
108
99
  if len(content_div) == 0:
109
- p = SubElement(content_div, 'p')
100
+ p = SubElement(content_div, "p")
110
101
  p.text = content_text
111
-
102
+
112
103
  # Continue processing subsequent blocks that might be part of the alert
113
- while blocks and blocks[0].startswith('>'):
104
+ while blocks and blocks[0].startswith(">"):
114
105
  continuation = blocks.pop(0)
115
- # Remove leading '>' and process
116
- continuation_text = continuation[1:].lstrip() if continuation.startswith('>') else continuation
117
-
106
+ continuation_text = continuation[1:].lstrip() if continuation.startswith(">") else continuation
107
+
118
108
  if continuation_text:
119
- p = SubElement(content_div, 'p')
109
+ p = SubElement(content_div, "p")
120
110
  p.text = continuation_text
121
-
111
+
122
112
  return True
123
113
 
124
114
 
125
115
  class AlertExtension(Extension):
126
116
  """Add GitHub-style alerts to markdown"""
127
-
117
+
128
118
  def extendMarkdown(self, md):
129
119
  """Add the alert processor to the markdown instance"""
130
120
  md.parser.blockprocessors.register(
131
121
  AlertBlockProcessor(md.parser),
132
- 'github_alerts',
133
- 175 # Priority - process before blockquote
134
- )
122
+ "github_alerts",
123
+ 175, # Priority - process before blockquote
124
+ )
@@ -1,58 +1,53 @@
1
1
  """Core markdown rendering with theme integration"""
2
2
 
3
3
  import markdown
4
- from typing import Optional, List, Union
4
+
5
5
  from .extensions.alerts import AlertExtension
6
6
 
7
7
 
8
8
  class MarkdownRenderer:
9
9
  """Core markdown rendering with theme integration"""
10
-
11
- def __init__(self, extensions: Optional[List[Union[str, markdown.Extension]]] = None):
10
+
11
+ def __init__(self, extensions: list[str | markdown.Extension] | None = None):
12
12
  """Initialize the renderer with optional extensions.
13
-
13
+
14
14
  Args:
15
15
  extensions: List of markdown extension names or instances to enable
16
16
  """
17
17
  self.extensions = extensions or []
18
18
  # Add some useful default extensions
19
19
  default_extensions = [
20
- 'fenced_code',
21
- 'tables',
22
- 'nl2br',
23
- 'sane_lists',
24
- AlertExtension() # Add GitHub-style alerts
20
+ "fenced_code",
21
+ "tables",
22
+ "nl2br",
23
+ "sane_lists",
24
+ AlertExtension(), # GitHub-style alerts
25
25
  ]
26
26
  self.extensions.extend(default_extensions)
27
-
28
- # Initialize the markdown processor
27
+
29
28
  self.md = markdown.Markdown(extensions=self.extensions)
30
-
29
+
31
30
  def render(self, markdown_text: str) -> str:
32
31
  """Convert markdown to themed HTML.
33
-
32
+
34
33
  Args:
35
34
  markdown_text: Raw markdown text to render
36
-
35
+
37
36
  Returns:
38
37
  HTML string wrapped with eidos-md class for styling
39
38
  """
40
- # Reset the markdown processor to clear any state
41
- self.md.reset()
42
-
43
- # Convert markdown to HTML
39
+ self.md.reset() # TODO: this is a hack to clear the state of the markdown processor
40
+
44
41
  html_content = self.md.convert(markdown_text)
45
-
46
- # Wrap in a div with our markdown class for styling
42
+
47
43
  return f'<div class="eidos-md">{html_content}</div>'
48
-
44
+
49
45
  def add_extension(self, extension: str) -> None:
50
46
  """Add a markdown extension.
51
-
47
+
52
48
  Args:
53
49
  extension: Name of the markdown extension to add
54
50
  """
55
51
  if extension not in self.extensions:
56
52
  self.extensions.append(extension)
57
- # Recreate the markdown processor with new extensions
58
- self.md = markdown.Markdown(extensions=self.extensions)
53
+ self.md = markdown.Markdown(extensions=self.extensions)
eidos/styles.py CHANGED
@@ -6,16 +6,19 @@ Only includes classes that are actually defined in the CSS file.
6
6
 
7
7
  from typing import Final
8
8
 
9
+
9
10
  class Theme:
10
11
  """Theme-related CSS classes from styles.css."""
12
+
11
13
  body: Final[str] = "eidos-body"
12
14
 
15
+
13
16
  class Buttons:
14
17
  """Button-related CSS classes from styles.css."""
15
-
18
+
16
19
  # Base button class (required for all buttons)
17
20
  base: Final[str] = "eidos-btn"
18
-
21
+
19
22
  # Button variants
20
23
  primary: Final[str] = "eidos-btn-primary"
21
24
  secondary: Final[str] = "eidos-btn-secondary"
@@ -25,6 +28,7 @@ class Buttons:
25
28
  error: Final[str] = "eidos-btn-error"
26
29
  cta: Final[str] = "eidos-btn-cta"
27
30
 
31
+
28
32
  class Typography:
29
33
  """Typography-related CSS classes from styles.css."""
30
34
 
@@ -35,9 +39,10 @@ class Typography:
35
39
  h5: Final[str] = "eidos-h5"
36
40
  h6: Final[str] = "eidos-h6"
37
41
 
42
+
38
43
  class Semantic:
39
44
  """Semantic HTML element CSS classes from styles.css."""
40
-
45
+
41
46
  # Text formatting
42
47
  strong: Final[str] = "eidos-strong"
43
48
  i: Final[str] = "eidos-i"
@@ -47,34 +52,53 @@ class Semantic:
47
52
  var: Final[str] = "eidos-var"
48
53
  mark: Final[str] = "eidos-mark"
49
54
  time: Final[str] = "eidos-time"
50
-
55
+
51
56
  # Code elements
52
57
  code: Final[str] = "eidos-code"
53
58
  pre: Final[str] = "eidos-pre"
54
59
  kbd: Final[str] = "eidos-kbd"
55
60
  samp: Final[str] = "eidos-samp"
56
-
61
+
57
62
  # Structural elements
58
63
  blockquote: Final[str] = "eidos-blockquote"
59
64
  cite: Final[str] = "eidos-cite"
60
65
  address: Final[str] = "eidos-address"
61
66
  hr: Final[str] = "eidos-hr"
62
-
67
+
63
68
  # Interactive elements
64
69
  details: Final[str] = "eidos-details"
65
70
  summary: Final[str] = "eidos-summary"
66
71
  details_content: Final[str] = "eidos-details-content"
67
-
72
+
68
73
  # Definition list
69
74
  dl: Final[str] = "eidos-dl"
70
75
  dt: Final[str] = "eidos-dt"
71
76
  dd: Final[str] = "eidos-dd"
72
-
77
+
73
78
  # Figure
74
79
  figure: Final[str] = "eidos-figure"
75
80
  figcaption: Final[str] = "eidos-figcaption"
76
81
 
82
+
83
+ class Tables:
84
+ """Table-related CSS classes from styles.css."""
85
+
86
+ # Base table class
87
+ table: Final[str] = "eidos-table"
88
+
89
+ # Table sections
90
+ thead: Final[str] = "eidos-thead"
91
+ tbody: Final[str] = "eidos-tbody"
92
+ tfoot: Final[str] = "eidos-tfoot"
93
+
94
+ # Table elements
95
+ tr: Final[str] = "eidos-tr"
96
+ th: Final[str] = "eidos-th"
97
+ td: Final[str] = "eidos-td"
98
+
99
+
77
100
  # Create singleton instance for easy access
78
101
  buttons = Buttons()
79
102
  typography = Typography()
80
- semantic = Semantic()
103
+ semantic = Semantic()
104
+ tables = Tables()