Content Calendar, Content Gap Analysis, and Content Optimization

This commit is contained in:
ajaysi
2025-05-27 09:15:08 +05:30
parent 4049d19787
commit 889021c078
100 changed files with 18504 additions and 1251 deletions

View File

@@ -0,0 +1,174 @@
"""
Card components for Twitter UI.
Provides consistent card layouts for features and tweets.
"""
import streamlit as st
from typing import Dict, Any, Optional, List
from ..styles.theme import Theme
class BaseCard:
"""Base class for all card components."""
def __init__(
self,
title: str,
description: str,
icon: Optional[str] = None,
status: Optional[str] = None,
actions: Optional[List[Dict[str, Any]]] = None
):
self.title = title
self.description = description
self.icon = icon
self.status = status
self.actions = actions or []
def render(self) -> None:
"""Render the card with consistent styling."""
with st.container():
st.markdown(f"""
<div class="card">
<div style="display: flex; align-items: center; margin-bottom: {Theme.SPACING["sm"]};">
{f'<span style="font-size: 1.5em; margin-right: {Theme.SPACING["sm"]};">{self.icon}</span>' if self.icon else ''}
<h3 style="margin: 0;">{self.title}</h3>
</div>
<p style="color: {Theme.COLORS["text_secondary"]}; margin: {Theme.SPACING["sm"]} 0;">
{self.description}
</p>
{f'<span class="status-badge status-{self.status}">{self.status.title()}</span>' if self.status else ''}
</div>
""", unsafe_allow_html=True)
if self.actions:
cols = st.columns(len(self.actions))
for i, action in enumerate(self.actions):
with cols[i]:
if st.button(
action["label"],
key=f"action_{i}",
help=action.get("help"),
use_container_width=True
):
action["callback"]()
class FeatureCard(BaseCard):
"""Card component for displaying features."""
def __init__(
self,
title: str,
description: str,
icon: str,
status: str = "active",
features: Optional[List[Dict[str, Any]]] = None,
on_click: Optional[callable] = None
):
super().__init__(title, description, icon, status)
self.features = features or []
self.on_click = on_click
def render(self) -> None:
"""Render the feature card with enhanced styling."""
with st.container():
st.markdown(f"""
<div class="card feature-card">
<div style="display: flex; align-items: center; margin-bottom: {Theme.SPACING["sm"]};">
<span style="font-size: 1.5em; margin-right: {Theme.SPACING["sm"]};">{self.icon}</span>
<h3 style="margin: 0;">{self.title}</h3>
</div>
<p style="color: {Theme.COLORS["text_secondary"]}; margin: {Theme.SPACING["sm"]} 0;">
{self.description}
</p>
<span class="status-badge status-{self.status}">{self.status.title()}</span>
</div>
""", unsafe_allow_html=True)
if self.features:
for feature in self.features:
st.markdown(f"""
<div style="margin-left: {Theme.SPACING["lg"]}; margin-top: {Theme.SPACING["sm"]};">
<p style="margin: 0;">
<strong>{feature["name"]}</strong>: {feature["description"]}
</p>
</div>
""", unsafe_allow_html=True)
if self.on_click:
if st.button(
f"Launch {self.title}",
key=f"launch_{self.title.lower().replace(' ', '_')}",
use_container_width=True
):
self.on_click()
class TweetCard(BaseCard):
"""Card component for displaying tweets."""
def __init__(
self,
content: str,
engagement_score: float,
hashtags: List[str],
emojis: List[str],
metrics: Optional[Dict[str, Any]] = None,
on_copy: Optional[callable] = None,
on_save: Optional[callable] = None
):
super().__init__(
title="Tweet",
description=content,
icon="🐦",
actions=[
{
"label": "Copy",
"callback": on_copy or (lambda: None),
"help": "Copy tweet to clipboard"
},
{
"label": "Save",
"callback": on_save or (lambda: None),
"help": "Save tweet for later"
}
]
)
self.engagement_score = engagement_score
self.hashtags = hashtags
self.emojis = emojis
self.metrics = metrics or {}
def render(self) -> None:
"""Render the tweet card with metrics and actions."""
with st.container():
st.markdown(f"""
<div class="card tweet-card">
<div style="display: flex; align-items: center; margin-bottom: {Theme.SPACING["sm"]};">
<span style="font-size: 1.5em; margin-right: {Theme.SPACING["sm"]};">{self.icon}</span>
<h3 style="margin: 0;">Tweet</h3>
</div>
<p style="color: {Theme.COLORS["text"]}; margin: {Theme.SPACING["sm"]} 0;">
{self.description}
</p>
<div style="display: flex; gap: {Theme.SPACING["sm"]}; margin: {Theme.SPACING["sm"]} 0;">
{''.join(f'<span style="color: {Theme.COLORS["primary"]};">{tag}</span>' for tag in self.hashtags)}
</div>
<div style="display: flex; gap: {Theme.SPACING["sm"]}; margin: {Theme.SPACING["sm"]} 0;">
{''.join(f'<span>{emoji}</span>' for emoji in self.emojis)}
</div>
<div style="margin-top: {Theme.SPACING["md"]};">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>Engagement Score: {self.engagement_score}%</span>
<div style="display: flex; gap: {Theme.SPACING["sm"]};">
<button class="stButton" onclick="copyTweet()">Copy</button>
<button class="stButton" onclick="saveTweet()">Save</button>
</div>
</div>
</div>
</div>
""", unsafe_allow_html=True)
if self.metrics:
cols = st.columns(len(self.metrics))
for i, (metric, value) in enumerate(self.metrics.items()):
with cols[i]:
st.metric(metric, f"{value}%")

View File

@@ -0,0 +1,255 @@
"""
Form components for Twitter UI.
Provides consistent form layouts and input validation.
"""
import streamlit as st
from typing import Dict, Any, Optional, List, Callable
from ..styles.theme import Theme
class BaseForm:
"""Base class for all form components."""
def __init__(
self,
title: str,
description: Optional[str] = None,
on_submit: Optional[Callable] = None
):
self.title = title
self.description = description
self.on_submit = on_submit
self.fields: Dict[str, Any] = {}
def add_field(
self,
key: str,
label: str,
field_type: str = "text",
required: bool = False,
help_text: Optional[str] = None,
options: Optional[List[str]] = None,
default: Any = None,
validation: Optional[Callable] = None
) -> None:
"""Add a field to the form."""
self.fields[key] = {
"label": label,
"type": field_type,
"required": required,
"help_text": help_text,
"options": options,
"default": default,
"validation": validation
}
def validate(self) -> bool:
"""Validate all form fields."""
for key, field in self.fields.items():
if field["required"] and not st.session_state.get(key):
st.error(f"{field['label']} is required")
return False
if field["validation"] and not field["validation"](st.session_state.get(key)):
return False
return True
def render(self) -> None:
"""Render the form with consistent styling."""
with st.container():
st.markdown(f"""
<div class="form-container">
<h3 style="margin-bottom: {Theme.SPACING['sm']};">{self.title}</h3>
{f'<p style="color: {Theme.COLORS["text_secondary"]}; margin-bottom: {Theme.SPACING["md"]};">{self.description}</p>' if self.description else ''}
</div>
""", unsafe_allow_html=True)
for key, field in self.fields.items():
if field["type"] == "text":
st.text_input(
field["label"],
key=key,
help=field["help_text"],
value=field["default"]
)
elif field["type"] == "textarea":
st.text_area(
field["label"],
key=key,
help=field["help_text"],
value=field["default"]
)
elif field["type"] == "select":
st.selectbox(
field["label"],
options=field["options"],
key=key,
help=field["help_text"],
index=field["options"].index(field["default"]) if field["default"] in field["options"] else 0
)
elif field["type"] == "multiselect":
st.multiselect(
field["label"],
options=field["options"],
key=key,
help=field["help_text"],
default=field["default"]
)
elif field["type"] == "number":
st.number_input(
field["label"],
key=key,
help=field["help_text"],
value=field["default"]
)
elif field["type"] == "slider":
st.slider(
field["label"],
key=key,
help=field["help_text"],
value=field["default"]
)
elif field["type"] == "checkbox":
st.checkbox(
field["label"],
key=key,
help=field["help_text"],
value=field["default"]
)
if st.button("Submit", use_container_width=True):
if self.validate() and self.on_submit:
self.on_submit()
class TweetForm(BaseForm):
"""Form component for tweet generation."""
def __init__(
self,
on_submit: Optional[Callable] = None,
default_tone: str = "professional",
default_length: str = "medium"
):
super().__init__(
title="Generate Tweet",
description="Create engaging tweets with AI assistance",
on_submit=on_submit
)
# Add tweet content field
self.add_field(
"tweet_content",
"Tweet Content",
field_type="textarea",
required=True,
help_text="Enter your tweet content or topic"
)
# Add tone selection
self.add_field(
"tone",
"Tweet Tone",
field_type="select",
options=["professional", "casual", "humorous", "informative", "inspirational"],
default=default_tone,
help_text="Select the tone for your tweet"
)
# Add length selection
self.add_field(
"length",
"Tweet Length",
field_type="select",
options=["short", "medium", "long"],
default=default_length,
help_text="Select the desired length of your tweet"
)
# Add hashtag options
self.add_field(
"hashtags",
"Hashtags",
field_type="multiselect",
options=["#AI", "#Tech", "#Innovation", "#Business", "#Marketing"],
help_text="Select relevant hashtags"
)
# Add emoji options
self.add_field(
"emojis",
"Emojis",
field_type="multiselect",
options=["🚀", "💡", "🎯", "🔥", ""],
help_text="Select emojis to include"
)
# Add engagement settings
self.add_field(
"engagement_boost",
"Engagement Boost",
field_type="slider",
default=50,
help_text="Adjust the engagement optimization level"
)
class SettingsForm(BaseForm):
"""Form component for user settings."""
def __init__(
self,
on_submit: Optional[Callable] = None,
default_settings: Optional[Dict[str, Any]] = None
):
super().__init__(
title="User Settings",
description="Customize your Twitter experience",
on_submit=on_submit
)
settings = default_settings or {}
# Add API settings
self.add_field(
"api_key",
"Twitter API Key",
field_type="text",
help_text="Enter your Twitter API key",
default=settings.get("api_key", "")
)
# Add theme settings
self.add_field(
"theme",
"Theme",
field_type="select",
options=["light", "dark", "system"],
default=settings.get("theme", "system"),
help_text="Select your preferred theme"
)
# Add notification settings
self.add_field(
"notifications",
"Enable Notifications",
field_type="checkbox",
default=settings.get("notifications", True),
help_text="Receive notifications for important updates"
)
# Add auto-save settings
self.add_field(
"auto_save",
"Auto-save Drafts",
field_type="checkbox",
default=settings.get("auto_save", True),
help_text="Automatically save tweet drafts"
)
# Add language settings
self.add_field(
"language",
"Language",
field_type="select",
options=["English", "Spanish", "French", "German", "Japanese"],
default=settings.get("language", "English"),
help_text="Select your preferred language"
)

View File

@@ -0,0 +1,222 @@
"""
Navigation components for Twitter UI.
Provides consistent navigation and layout structure.
"""
import streamlit as st
from typing import Dict, Any, Optional, List
from ..styles.theme import Theme
class Sidebar:
"""Sidebar navigation component."""
def __init__(
self,
title: str = "Twitter Tools",
logo: Optional[str] = None,
menu_items: Optional[List[Dict[str, Any]]] = None
):
self.title = title
self.logo = logo
self.menu_items = menu_items or []
def add_menu_item(
self,
label: str,
icon: str,
page: str,
badge: Optional[str] = None
) -> None:
"""Add a menu item to the sidebar."""
self.menu_items.append({
"label": label,
"icon": icon,
"page": page,
"badge": badge
})
def render(self) -> None:
"""Render the sidebar with consistent styling."""
with st.sidebar:
# Logo and title
if self.logo:
st.image(self.logo, width=50)
st.markdown(f"""
<h2 style="margin: {Theme.SPACING["sm"]} 0;">{self.title}</h2>
""", unsafe_allow_html=True)
# Menu items
for item in self.menu_items:
st.markdown(f"""
<div class="menu-item">
<span style="font-size: 1.2em; margin-right: {Theme.SPACING["sm"]};">{item["icon"]}</span>
<span>{item["label"]}</span>
{f'<span class="badge">{item["badge"]}</span>' if item.get("badge") else ""}
</div>
""", unsafe_allow_html=True)
if st.button(
item["label"],
key=f"nav_{item['page']}",
use_container_width=True
):
st.session_state["current_page"] = item["page"]
class Header:
"""Header navigation component."""
def __init__(
self,
title: str,
subtitle: Optional[str] = None,
actions: Optional[List[Dict[str, Any]]] = None
):
self.title = title
self.subtitle = subtitle
self.actions = actions or []
def add_action(
self,
label: str,
icon: str,
callback: callable,
help_text: Optional[str] = None
) -> None:
"""Add an action button to the header."""
self.actions.append({
"label": label,
"icon": icon,
"callback": callback,
"help_text": help_text
})
def render(self) -> None:
"""Render the header with consistent styling."""
# Build action buttons HTML
action_buttons = []
for action in self.actions:
help_text = action.get("help_text", "")
action_buttons.append(f"""
<button class="header-action" title="{help_text}">
<span style="font-size: 1.2em; margin-right: {Theme.SPACING["xs"]};">{action["icon"]}</span>
{action["label"]}
</button>
""")
st.markdown(f"""
<div class="header">
<div>
<h1 style="margin: 0;">{self.title}</h1>
{f'<p style="color: {Theme.COLORS["text_secondary"]}; margin: {Theme.SPACING["xs"]} 0;">{self.subtitle}</p>' if self.subtitle else ""}
</div>
<div style="display: flex; gap: {Theme.SPACING["sm"]};">
{''.join(action_buttons)}
</div>
</div>
""", unsafe_allow_html=True)
# Add action button callbacks
for i, action in enumerate(self.actions):
if st.button(
action["label"],
key=f"header_action_{i}",
help=action.get("help_text")
):
action["callback"]()
class Tabs:
"""Tab navigation component."""
def __init__(
self,
tabs: Optional[List[Dict[str, Any]]] = None,
default_tab: Optional[str] = None
):
self.tabs = tabs or []
self.default_tab = default_tab
def add_tab(
self,
label: str,
icon: Optional[str] = None,
content: Optional[callable] = None
) -> None:
"""Add a tab to the navigation."""
self.tabs.append({
"label": label,
"icon": icon,
"content": content
})
def render(self) -> None:
"""Render the tabs with consistent styling."""
if not self.tabs:
return
# Create tab labels with icons
tab_labels = [
f"{tab['icon']} {tab['label']}" if tab.get('icon') else tab['label']
for tab in self.tabs
]
# Get current tab from session state or use default
current_tab = st.session_state.get("current_tab", self.default_tab or self.tabs[0]["label"])
# Render tabs
selected_tab = st.tabs(tab_labels)[tab_labels.index(current_tab)]
# Update session state
st.session_state["current_tab"] = current_tab
# Render tab content
with selected_tab:
for tab in self.tabs:
if tab["label"] == current_tab and tab.get("content"):
tab["content"]()
class Breadcrumbs:
"""Breadcrumb navigation component."""
def __init__(
self,
items: Optional[List[Dict[str, Any]]] = None
):
self.items = items or []
def add_item(
self,
label: str,
page: Optional[str] = None,
icon: Optional[str] = None
) -> None:
"""Add a breadcrumb item."""
self.items.append({
"label": label,
"page": page,
"icon": icon
})
def render(self) -> None:
"""Render the breadcrumbs with consistent styling."""
if not self.items:
return
breadcrumb_items = []
for i, item in enumerate(self.items):
icon_html = f'<span style="font-size: 1.2em; margin-right: {Theme.SPACING["xs"]};">{item["icon"]}</span>' if item.get("icon") else ""
link_html = f'<a href="#" onclick="setPage(\'{item["page"]}\')">{item["label"]}</a>' if item.get("page") else f'<span>{item["label"]}</span>'
separator = f'<span style="margin: 0 {Theme.SPACING["xs"]};">/</span>' if i < len(self.items) - 1 else ""
breadcrumb_items.append(f"""
<span class="breadcrumb-item">
{icon_html}
{link_html}
</span>
{separator}
""")
st.markdown(f"""
<div class="breadcrumbs">
{''.join(breadcrumb_items)}
</div>
""", unsafe_allow_html=True)