Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.bootstrap.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ $bootstrap-icons-font-dir: '/fonts';

@import 'base';
@import 'components/navbar';
@import 'components/footer';
@import 'components/sections';
@import 'components/cards';
@import 'components/stage-badge';
Expand Down
49 changes: 49 additions & 0 deletions app/assets/stylesheets/components/_footer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
footer.site-footer {
background: $ink;
color: rgba(255, 255, 255, .78);

h2, h3 {
color: #fff;
font-size: .875rem;
font-weight: 600;
letter-spacing: .04em;
text-transform: uppercase;
}

a {
color: rgba(255, 255, 255, .78);
text-decoration: none;

&:hover, &:focus {
color: #fff;
text-decoration: underline;
}
}

ul {
list-style: none;
margin: 0;
padding: 0;

li {
margin-bottom: .375rem;
}
}

// Existing social icons are black SVGs — invert them on the dark footer.
.social-links img {
filter: invert(1);
opacity: .75;
transition: opacity .15s ease-out;
}

.social-links a:hover img,
.social-links a:focus img {
opacity: 1;
}

.footer-bottom {
border-top: 1px solid rgba(255, 255, 255, .08);
color: rgba(255, 255, 255, .55);
}
}
46 changes: 14 additions & 32 deletions app/assets/stylesheets/pages/_legacy.scss
Original file line number Diff line number Diff line change
@@ -1,39 +1,21 @@
// Rules belonging to the pre-relaunch pages. They are kept intact, and separate,
// so the cutover that removes those pages can delete this file rather than pick
// rules out of the ones above.
// Rules belonging to the pre-relaunch pages.
//
// Two of the three that were here have gone with the pages they styled: the h2
// title treatment, whose long selector only ever matched pages inside the
// .container wrapper, and the CSS territory gate on /introduction's partner
// wall -- which never matched anything anyway, since no logo on that page
// carried the `ru` class it selected on. PagesHelper#partner_logos does that
// job now, in Ruby, with a test.
//
// What remains is used by pages that are still here.

// Section headings inside a grid column. Fifteen existing pages rely on this --
// our-team, our-channels, the calculators, majestic-endpoints and the rest --
// so it cannot go until they do. The new pages do not use it: their headings
// take their colour from the body, not the brand.
// Section headings inside a grid column. Still used by our-team,
// majestic-endpoints, green-life, merchandise, the calculators and the rest.
// The relaunched pages do not use it: their headings take their colour from the
// body rather than the brand.
.col > h3 {
color: var(--bs-blue);
font-size: 1.3rem;
margin-bottom: 1rem;
margin-top: 1.5rem;
}

// Territory-gating for the partner wall on /introduction, done in CSS because
// that page hardcodes every logo in the markup. The integrators in the .ru
// group serve Russia and are shown only to Russian-language visitors.
//
// The replacement is PagesHelper#partner_logos, which makes the same split in
// Ruby and can therefore be tested. Until /introduction goes, this rule is what
// enforces it -- deleting it early would show the Russian integrators to
// everyone, which is precisely what the maintainers asked not to happen.
html:not([lang="ru"]) article.introduction .col.logo.ru {
display: none;
}

// Page titles on the pre-relaunch pages: brand-coloured and 700, as they have
// always been. _base.scss styles `article > header > h2` at 600 and inherits
// the body colour, which is the new design; this selector is longer, so it wins
// wherever it applies -- and it applies exactly to pages rendered inside the
// .container wrapper, which is every page that is not full-bleed. The two rules
// therefore split cleanly along the same line as the layout's fullwidth switch,
// and this one disappears when the pages it belongs to do.
body > main > .container > article > header > h2 {
color: var(--bs-blue);
font-weight: 700;
margin: 1rem 0 1.5rem;
}
30 changes: 0 additions & 30 deletions app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ class PagesController < ApplicationController
def show
end

def about
@page_title = t('pages.about_us.title')
render 'pages/our_channels'
end

def business
@page_title = t('pages.business.title')
render 'pages/business'
Expand Down Expand Up @@ -69,11 +64,6 @@ def low_latency
render 'pages/low_latency'
end

def introduction
@page_title = t('pages.introduction.title')
render 'pages/introduction'
end

def majestic_endpoints
@page_title = t('pages.majestic_endpoints.title')
render 'pages/majestic_endpoints'
Expand All @@ -84,21 +74,6 @@ def merchandise
render 'pages/merchandise'
end

def our_channels
@page_title = t('pages.our_channels.title')
render 'pages/our_channels'
end

def our_software
@page_title = t('pages.our_software.title')
render 'pages/our_software'
end

def our_projects
@page_title = t('pages.our_projects.title')
render 'pages/our_projects'
end

def our_team
@page_title = t('pages.our_team.title')
render 'pages/our_team'
Expand All @@ -114,11 +89,6 @@ def stages_of_firmware_development
render 'pages/stages_of_firmware_development'
end

def support_open_source
@page_title = t('pages.support_open_source.title')
render 'pages/support_open_source'
end

def utilities
@page_title = t('pages.utilities.title')
render 'pages/utilities'
Expand Down
9 changes: 7 additions & 2 deletions app/models/snapshot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,19 @@ def purge_file_now
file.attachment&.purge
end

# dig, not credentials.mac.blacklisted. Without config/master.key -- which is
# what a fresh checkout and the test environment have -- credentials.mac is
# nil, and the reader raised NoMethodError on every upload rather than simply
# having nothing to blacklist. Production has the key, so this never showed
# there; it made the API impossible to exercise anywhere else.
def blacklisted_mac
return unless mac_address.in?(Rails.application.credentials.mac.blacklisted)
return unless mac_address.in?(Rails.application.credentials.dig(:mac, :blacklisted) || [])
errors.add :base, 'This IP address is blacklisted.'
raise BlacklistedMac
end

def time_interval
return if ip_address.in?(Rails.application.credentials.ip.whitelisted)
return if ip_address.in?(Rails.application.credentials.dig(:ip, :whitelisted) || [])

s = Snapshot.select(:created_at).where(mac_address: mac_address).order(:created_at).last
if s && s.created_at > INTERVAL_LIMIT.ago + 2.minutes # hysteresis
Expand Down
82 changes: 64 additions & 18 deletions app/views/layouts/_footer.html.erb
Original file line number Diff line number Diff line change
@@ -1,27 +1,73 @@
<%#
Lifted out of application.html.erb unchanged, for the same reason as the
navbar. Every icon resolves through asset_path -- production runs with
config.assets.compile = false, so a literal /assets/... path is a 404, which
is what 2ec9baa fixed here and what any rewrite of this file has to preserve.
Four columns on dark, replacing the single copyright line.

Two links from the draft of this footer are not here, both for reasons that
postdate it:

/binaries answers 410 since 2cf8bc9. Linking a retired URL from every page
on the site would be a curious way to retire it.

/majestic-endpoints left the menu in 3f0753c. The page is a pointer to the
camera's own WebUI now rather than somewhere to browse to; its URL stays for
inbound links, and the site does not advertise it.

Every icon resolves through asset_path. Production runs with
config.assets.compile = false, so a literal /assets/... path is a 404 -- which
is exactly what 2ec9baa fixed in the footer this one replaces, and what the
draft would have reintroduced.
%>
<footer class="small p-4 mt-4 text-secondary">
<footer class="site-footer small pt-6 pb-4" data-bs-theme="dark">
<div class="container">
<div class="row justify-content-between mb-3">
<div class="col">
<p>Copyright 2019-<%= Date.today.year %> <a href="https://openipc.org/">OpenIPC</a>.</p>
<div class="row g-4 mb-5">
<div class="col-6 col-lg-3">
<h2><%= t('footer.column_platform') %></h2>
<ul>
<li><a href="/get-started"><%= t('nav.get_started') %></a></li>
<li><a href="/supported-hardware"><%= t('nav.supported_hardware') %></a></li>
<li><a href="https://github.com/OpenIPC/firmware"><%= t('footer.firmware_source') %></a></li>
<li><a href="/web-interface"><%= t('nav.webui') %></a></li>
<li><a href="/stages-of-firmware-development"><%= t('nav.stages') %></a></li>
</ul>
</div>
<div class="col text-end">
<div class="btn-group">
<a class="btn" href="https://github.com/openipc" title="OpenIPC on GitHub"><img src="<%= asset_path("github-black.svg") %>" alt="Image: GitHub logo"></a>
<a class="btn" href="https://opencollective.com/openipc" title="OpenIPC on OpenCollective"><img src="<%= asset_path("opencollective-black.svg") %>" alt="Image: OpenCollective logo"></a>
<a class="btn" href="https://t.me/openipc" title="OpenIPC on Telegram"><img src="<%= asset_path("telegram-black.svg") %>" alt="Image: Telegram logo"></a>
<a class="btn" href="https://www.google.com/search?q=WeChat+ID%3A+OpenIPC" title="OpenIPC on WeChat"><img src="<%= asset_path("wechat-black.svg") %>" alt="Image: WeChat logo"></a>
<a class="btn" href="https://www.youtube.com/@openipc" title="OpenIPC on YouTube"><img src="<%= asset_path("youtube-black.svg") %>" alt="Image: YouTube logo"></a>
<a class="btn" href="https://twitter.com/openipc" title="OpenIPC on Twitter"><img src="<%= asset_path("twitter-black.svg") %>" alt="Image: Twitter logo"></a>
<a class="btn" href="https://www.instagram.com/openipc/" title="OpenIPC on Instagram"><img src="<%= asset_path("instagram-black.svg") %>" alt="Image: Instagram logo"></a>
<div class="col-6 col-lg-3">
<h2><%= t('footer.column_ecosystem') %></h2>
<ul>
<li><a href="/ecosystem"><%= t('nav.ecosystem_overview') %></a></li>
<li><a href="/low-latency"><%= t('nav.low_latency') %></a></li>
<li><a href="/open-wall"><%= t('nav.openwall') %></a></li>
<li><a href="/utilities"><%= t('nav.utilities') %></a></li>
<li><a href="https://github.com/openipc/wiki"><%= t('nav.wiki') %></a></li>
</ul>
</div>
<div class="col-6 col-lg-3">
<h2><%= t('footer.column_project') %></h2>
<ul>
<li><a href="/business"><%= t('nav.business') %></a></li>
<li><a href="/donate"><%= t('nav.donate') %></a></li>
<li><a href="/our-team"><%= t('nav.team') %></a></li>
<li><a href="/green_life"><%= t('nav.green_life') %></a></li>
<li><a href="/merchandise"><%= t('pages.merchandise.title') %></a></li>
</ul>
</div>
<div class="col-6 col-lg-3">
<h2><%= t('footer.column_community') %></h2>
<ul>
<li><a href="/community"><%= t('nav.community_chat') %></a></li>
</ul>
<div class="social-links d-flex flex-wrap gap-1 mt-3">
<a class="btn btn-sm" href="https://github.com/openipc" title="OpenIPC on GitHub"><img src="<%= asset_path('github-black.svg') %>" alt="Image: GitHub logo"></a>
<a class="btn btn-sm" href="https://opencollective.com/openipc" title="OpenIPC on OpenCollective"><img src="<%= asset_path('opencollective-black.svg') %>" alt="Image: OpenCollective logo"></a>
<a class="btn btn-sm" href="https://t.me/openipc" title="OpenIPC on Telegram"><img src="<%= asset_path('telegram-black.svg') %>" alt="Image: Telegram logo"></a>
<a class="btn btn-sm" href="https://www.google.com/search?q=WeChat+ID%3A+OpenIPC" title="OpenIPC on WeChat"><img src="<%= asset_path('wechat-black.svg') %>" alt="Image: WeChat logo"></a>
<a class="btn btn-sm" href="https://www.youtube.com/@openipc" title="OpenIPC on YouTube"><img src="<%= asset_path('youtube-black.svg') %>" alt="Image: YouTube logo"></a>
<a class="btn btn-sm" href="https://twitter.com/openipc" title="OpenIPC on Twitter"><img src="<%= asset_path('twitter-black.svg') %>" alt="Image: Twitter logo"></a>
<a class="btn btn-sm" href="https://www.instagram.com/openipc/" title="OpenIPC on Instagram"><img src="<%= asset_path('instagram-black.svg') %>" alt="Image: Instagram logo"></a>
</div>
</div>
</div>
<p class="small"><%= t('site.disclaimer') %></p>
<div class="footer-bottom pt-4">
<p class="mb-1">Copyright 2019-<%= Date.today.year %> <a href="https://openipc.org/">OpenIPC</a>. <%= t('footer.license_note') %> <span class="text-data"><%= t('footer.tagline') %></span></p>
<p class="x-small mb-0"><%= t('site.disclaimer') %></p>
</div>
</div>
</footer>
62 changes: 38 additions & 24 deletions app/views/layouts/_navbar.html.erb
Original file line number Diff line number Diff line change
@@ -1,43 +1,57 @@
<%#
Lifted out of application.html.erb unchanged. The links, their order and the
locale switcher are exactly what the layout carried; only the wrapper moved,
so that the relaunch can rewrite the navigation in one reviewable file rather
than inside a diff that also touches <head> and the footer.
The relaunched navigation: Get Started | Hardware | Low Latency | Ecosystem |
For Business | Community.

expand-xl rather than expand-lg. Six top-level entries plus the language
switcher do not fit an lg breakpoint without wrapping, and a wrapped navbar
reads as broken rather than as full.

/majestic-endpoints is deliberately not here. 3f0753c removed it from the menu
when the page stopped being a list to browse and became a pointer to the
camera's own WebUI; the URL stays for the inbound links, the menu entry does
not come back.
%>
<nav class="navbar navbar-dark navbar-expand-lg">
<nav class="navbar navbar-dark navbar-expand-xl sticky-top" data-bs-theme="dark">
<div class="container">
<a class="navbar-brand" href="/"><%= image_tag 'openipc-logo-white.svg', alt: 'Image: OpenIPC logo', height: 32 %></a>
<button aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation" class="navbar-toggler" data-bs-target="#navbarNav" data-bs-toggle="collapse" type="button">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNav">
<ul class="navbar-nav">
<%= navbar_link t('nav.introduction'), '/introduction' %>
<%= navbar_link t('nav.supported_hardware'), '/supported-hardware' %>
<%= navbar_link t('nav.support_opensource'), '/support-open-source' %>
<!-- %= navbar_link t('nav.openwall'), '/open-wall' % -->
<!-- %= navbar_link t('nav.store'), "https://store.openipc.org/" % -->
<ul class="navbar-nav align-items-xl-center">
<%= navbar_link t('nav.get_started'), '/get-started' %>
<%= navbar_link t('nav.hardware'), '/supported-hardware' %>
<%= navbar_link t('nav.low_latency'), '/low-latency' %>
<li class="nav-item dropdown">
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownAbout" role="button"><%= t('nav.about') %></a>
<ul aria-labelledby="dropdownAbout" class="dropdown-menu dropdown-menu-lg-end">
<%= dropdown_link t('nav.team'), '/our-team' %>
<%= dropdown_link t('nav.projects'), '/our-projects' %>
<%= dropdown_link t('nav.software'), '/our-software' %>
<%= dropdown_link t('nav.green_life'), '/green_life' %>
<%= dropdown_link t('nav.channels'), '/our-channels' %>
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownEcosystem" role="button"><%= t('nav.ecosystem') %></a>
<ul aria-labelledby="dropdownEcosystem" class="dropdown-menu dropdown-menu-xl-end">
<%= dropdown_link t('nav.ecosystem_overview'), '/ecosystem' %>
<%= dropdown_link t('nav.openwall'), '/open-wall' %>
<%= dropdown_link t('nav.webui'), '/web-interface' %>
<%= dropdown_link t('nav.wiki'), 'https://github.com/openipc/wiki' %>
</ul>
</li>
<li class="nav-item dropdown">
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownTools" role="button"><%= t('nav.tools') %></a>
<ul aria-labelledby="dropdownTools" class="dropdown-menu dropdown-menu-lg-end">
<%= dropdown_link t('nav.stages'), '/stages-of-firmware-development' %>
<li><hr class="dropdown-divider"></li>
<li><h6 class="dropdown-header"><%= t('nav.header_web_tools') %></h6></li>
<%= dropdown_link t('nav.partition_calc'), '/tools/firmware-partitions-calculation' %>
<%= dropdown_link t('nav.hires_timer'), '/tools/high-resolution-timer' %>
<%= dropdown_link t('nav.qr_code_generator'), '/tools/qr-code-generator' %>
<%= dropdown_link t('nav.utilities'), '/utilities' %>
<li><hr class="dropdown-divider"></li>
<%= dropdown_link t('nav.wiki'), 'https://github.com/openipc/wiki' %>
</ul>
</li>
<%= navbar_link t('nav.business'), '/business' %>
<li class="nav-item dropdown">
<a aria-expanded="false" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdownCommunity" role="button"><%= t('nav.community') %></a>
<ul aria-labelledby="dropdownCommunity" class="dropdown-menu dropdown-menu-xl-end">
<%= dropdown_link t('nav.community_chat'), '/community' %>
<%= dropdown_link t('nav.donate'), '/donate' %>
<%= dropdown_link t('nav.team'), '/our-team' %>
<%= dropdown_link t('nav.green_life'), '/green_life' %>
</ul>
</li>
<li class="nav-item">
<a class="nav-link" href="https://github.com/openipc" title="OpenIPC on GitHub"><i class="bi bi-github" style="font-size: 1.25rem"></i><span class="d-xl-none ms-2">GitHub</span></a>
</li>
</ul>
<%= render 'layouts/locale_switcher' %>
</div>
Expand Down
6 changes: 0 additions & 6 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,6 @@
<% end %>
</main>

<div class="">
<div class="container">
<%= render "pages/donate" %>
</div>
</div>

<%= render 'layouts/footer' %>
</body>
</html>
14 changes: 0 additions & 14 deletions app/views/pages/_donate.html.erb

This file was deleted.

2 changes: 0 additions & 2 deletions app/views/pages/aaa.html.erb

This file was deleted.

Loading
Loading