Skip to content
Merged

V3 #3

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2b80666
add view privacy policy view
DrJfrost Mar 3, 2026
c716ba8
feat: added Terms of Use view and update URL routing
fromagge Mar 3, 2026
ebc682b
feat: enhance v3 styling with body background and class updates
fromagge Mar 3, 2026
74db632
full privacy policy design view page
DrJfrost Mar 3, 2026
1682ee4
merge v3 to privacy policy
DrJfrost Mar 3, 2026
1bbea51
fix v3 url privacy policy
DrJfrost Mar 3, 2026
ec05f9d
feat: add commit statistics feature to library detail and examples se…
fromagge Mar 3, 2026
af8c10a
Merge branch 'v3' into 2087-stats-block-component
fromagge Mar 3, 2026
091bfa6
refactor: update styles for detail card carousel and full-width stats…
fromagge Mar 3, 2026
8c171a0
refactor: remove unused comments and clean up HTML structure in examp…
fromagge Mar 3, 2026
45895c3
fix: revert to flag for libraries
fromagge Mar 3, 2026
e11a721
Integration of colors for syntax highlighting
DrJfrost Mar 3, 2026
80bd307
fix Integration of colors for syntax highlighting.
DrJfrost Mar 3, 2026
5893d76
Greg's settings and migrating content to its respective folder privac…
DrJfrost Mar 6, 2026
7400b71
Merge pull request #2121 from boostorg/privacy-policy-pag
DrJfrost Mar 6, 2026
8981132
Add V3 images (#2135)
rbbeeston Mar 6, 2026
2a1a250
Merge branch 'v3' into 2109-webpage-ui-terms-of-use-page
fromagge Mar 9, 2026
aa683c3
feat: add v3 mixin for pages
fromagge Mar 9, 2026
edeee6c
Merge branch 'v3' into 2087-stats-block-component
fromagge Mar 9, 2026
7362952
nit
fromagge Mar 9, 2026
ed42f18
Merge pull request #2122 from boostorg/2087-stats-block-component
fromagge Mar 9, 2026
5bec6e2
Merge pull request #2120 from boostorg/2109-webpage-ui-terms-of-use-page
fromagge Mar 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions config/urls.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
DocLibsTemplateView,
ImageView,
MarkdownTemplateView,
TermsOfUseView,
PrivacyPolicyView,
V3ComponentDemoView,
ModernizedDocsView,
RedirectToDocsView,
Expand Down Expand Up @@ -347,13 +349,13 @@
),
path(
"privacy/",
MarkdownTemplateView.as_view(),
PrivacyPolicyView.as_view(),
name="privacy",
kwargs={"markdown_local": "privacy-policy"},
),
path(
"terms-of-use/",
MarkdownTemplateView.as_view(),
TermsOfUseView.as_view(),
name="terms-of-use",
kwargs={"markdown_local": "terms-of-use"},
),
Expand Down
37 changes: 37 additions & 0 deletions core/mixins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from waffle import flag_is_active


class V3Mixin:
"""Renders a v3 template when the 'v3' waffle flag is active.

Hooks into dispatch() to short-circuit the normal view flow (e.g.
MarkdownTemplateView's markdown rendering) when v3 is active.

Subclasses declare:
v3_template_name: str — template to render when v3 is active

And override get_v3_context_data() to supply view-specific context.
"""

v3_template_name = None

def dispatch(self, request, *args, **kwargs):
if self.v3_template_name and flag_is_active(request, "v3"):
self._v3_active = True
return self.render_v3_response()
self._v3_active = False
return super().dispatch(request, *args, **kwargs)

def get_v3_context_data(self, **kwargs):
"""Override in subclasses to provide v3-specific context."""
return {}

def render_v3_response(self):
"""Render the v3 template through Django's standard TemplateView pipeline."""
context = self.get_context_data(**self.get_v3_context_data())
return self.render_to_response(context)

def get_template_names(self):
if getattr(self, "_v3_active", False):
return [self.v3_template_name]
return super().get_template_names()
62 changes: 59 additions & 3 deletions core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
)
from versions.models import Version, docs_path_to_boost_name

from .mixins import V3Mixin
from .asciidoc import convert_adoc_to_html
from .boostrenderer import (
convert_img_paths,
Expand Down Expand Up @@ -240,6 +241,24 @@ def get(self, request, *args, **kwargs):
return self.render_to_response(context)


class TermsOfUseView(V3Mixin, MarkdownTemplateView):
"""Renders the v3 Terms of Use page when the v3 flag is active, else markdown template."""

v3_template_name = "v3/terms_of_use.html"

def get_v3_context_data(self, **kwargs):
return {"last_updated": "2024-02-22"}


class PrivacyPolicyView(V3Mixin, MarkdownTemplateView):
"""Renders the v3 Privacy Policy page when the v3 flag is active, else markdown template."""

v3_template_name = "v3/privacy_policy.html"

def get_v3_context_data(self, **kwargs):
return {"last_updated": "2024-02-17"}


class ContentNotFoundException(Exception):
pass

Expand Down Expand Up @@ -1043,8 +1062,13 @@ class V3ComponentDemoView(TemplateView):
template_name = "base.html"

def get_context_data(self, **kwargs):
from libraries.models import LibraryVersion
from libraries.utils import build_library_intro_context
from django.urls import reverse
from libraries.models import Library, LibraryVersion
from libraries.utils import (
build_library_intro_context,
get_commit_data_by_release_for_library,
commit_data_to_stats_bars,
)

CODE_DEMO_BEAST = """int main()
{
Expand Down Expand Up @@ -1213,7 +1237,7 @@ def get_context_data(self, **kwargs):
},
},
{
"quote": "I use Boost daily. I absolutely love it. It's wonderful. I could not do my job w/o it. Much of it is in the new C++11 standard too.",
"quote": "I use Boost d1aily. I absolutely love it. It's wonderful. I could not do my job w/o it. Much of it is in the new C++11 standard too.",
"author": {
"name": "Name Surname",
"avatar_url": "/static/img/v3/demo_page/Avatar.png",
Expand Down Expand Up @@ -1242,4 +1266,36 @@ def get_context_data(self, **kwargs):
)
if lv:
context["library_intro"] = build_library_intro_context(lv)

# Commits per release: dropdown of libraries, Beast first and default
raw_library = self.request.GET.get("library")
library_slug = (raw_library or "beast").strip().lower()
# Build dropdown choices: Beast first, then others alphabetically by name
beast = Library.objects.filter(slug="beast").first()
rest = Library.objects.exclude(slug="beast").order_by("name")[:99]
choices = []
if beast:
choices.append((beast.slug, beast.display_name))
for lib in rest:
choices.append((lib.slug, lib.display_name))
context["example_library_choices"] = choices

library = Library.objects.filter(slug__iexact=library_slug).first()
if library:
commit_data = get_commit_data_by_release_for_library(library)
context["example_library_commits_bars"] = commit_data_to_stats_bars(
commit_data[-10:] if len(commit_data) > 10 else commit_data
)
context["example_library_name"] = library.display_name
context["example_library_slug"] = library.slug
context["example_library_detail_url"] = reverse(
"library-detail",
kwargs={
"version_slug": "latest",
"library_slug": library.slug,
},
)
else:
context["example_library_not_found"] = library_slug
context["example_library_slug"] = library_slug
return context
49 changes: 48 additions & 1 deletion libraries/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from dateutil.parser import ParserError, parse
from django.conf import settings
from django.db.models import Count
from django.db.models import Count, F
from django.db.models.functions import Lower
from django.urls import reverse
from django.utils.text import slugify
Expand All @@ -32,6 +32,53 @@

logger = structlog.get_logger()

STATS_COMMITS_BAR_HEIGHT_MAX_PX = 120
STATS_COMMITS_BAR_HEIGHT_MIN_PX = 8


def get_commit_data_by_release_for_library(library, limit=20):
"""Return list of { release, commit_count } for a library, ordered by release (oldest first).

Used by the library detail page and by the V3 examples “commits per release” lookup.
"""
from .models import LibraryVersion

qs = (
LibraryVersion.objects.filter(
library=library,
version__in=Version.objects.minor_versions(),
)
.annotate(count=Count("commit"), version_name=F("version__name"))
.order_by("-version__name")
)[:limit]
return [
{"release": x.version_name.strip("boost-"), "commit_count": x.count}
for x in reversed(list(qs))
]


def commit_data_to_stats_bars(commit_data):
"""Convert commit_data_by_release (list of { release, commit_count }) to stats bar format.

Returns list of { label, height_px } with heights scaled to STATS_COMMITS_BAR_HEIGHT_*.
"""
if not commit_data:
return []
counts = [d["commit_count"] for d in commit_data]
max_count = max(counts) or 1
return [
{
"label": d["release"],
"height_px": max(
STATS_COMMITS_BAR_HEIGHT_MIN_PX,
round(
(d["commit_count"] / max_count) * STATS_COMMITS_BAR_HEIGHT_MAX_PX
),
),
}
for d in commit_data
]


def decode_content(content):
"""Decode bytes to string."""
Expand Down
28 changes: 8 additions & 20 deletions libraries/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import structlog

from django.contrib import messages
from django.db.models import F, Count, Prefetch
from django.db.models import Prefetch
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
Expand Down Expand Up @@ -35,6 +35,8 @@
get_documentation_url_redirect,
get_prioritized_version,
get_version_from_cookie,
get_commit_data_by_release_for_library,
commit_data_to_stats_bars,
)
from .constants import LATEST_RELEASE_URL_PATH_STR

Expand Down Expand Up @@ -247,8 +249,11 @@ def get_context_data(self, **kwargs):
else self.object.github_url
)

# Populate the commit graphs
context["commit_data_by_release"] = self.get_commit_data_by_release()
commit_data = get_commit_data_by_release_for_library(self.object)
context["commit_data_by_release"] = commit_data
context["library_commits_stats_bars"] = commit_data_to_stats_bars(
commit_data[-10:] if len(commit_data) > 10 else commit_data
)
try:
context["dependency_diff"] = self.get_dependency_diff(library_version)
except BoostImportedDataException:
Expand All @@ -270,23 +275,6 @@ def get_dependency_diff(self, library_version):
)
return diffs.get(library_version.library.name, {})

def get_commit_data_by_release(self):
qs = (
LibraryVersion.objects.filter(
library=self.object,
version__in=Version.objects.minor_versions(),
)
.annotate(count=Count("commit"), version_name=F("version__name"))
.order_by("-version__name")
)[:20]
return [
{
"release": x.version_name.strip("boost-"),
"commit_count": x.count,
}
for x in reversed(list(qs))
]

def _prepare_commit_data(self, commit_data, data_type):
commit_data_list = []
for data in commit_data:
Expand Down
3 changes: 3 additions & 0 deletions static/css/v3/components.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
@import './event-cards.css';
@import './content.css';
@import './why-boost-cards.css';
@import './stats.css';
@import './category-tags.css';
@import './code-block.css';
@import './search-card.css';
@import './privacy-policy.css';
@import './library-intro-card.css';
@import './terms-of-use.css';
@import './thread-archive-card.css';
Loading