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
Binary file added app/assets/images/partners/faceter_mini.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions app/assets/stylesheets/components/_cards.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
}
}

// A link inside the card body sits under .stretched-link's overlay and cannot
// be clicked. Lifting it above restores it without giving up the whole-card
// click target -- which is what the arrow at the bottom is for.
.pillar-card .card-body p a {
position: relative;
z-index: 2;
}

.pillar-card .icon-chip {
align-items: center;
background: rgba($indigo, .08);
Expand Down
150 changes: 109 additions & 41 deletions app/helpers/pages_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,70 @@

# Helpers for the static marketing pages: the page title, and the partner wall.
module PagesHelper
# The partner wall, in Ruby rather than hardcoded into a template.
# The partner wall, grouped, because "partners" was doing too much work as one
# word. A chip vendor that ships OpenIPC out of the box, a company that
# installs cameras for a living, a university team and the host of our
# finances are all on the wall for different reasons, and a page usually wants
# some of those reasons rather than all of them: /business shows who builds
# and integrates hardware, and nobody else.
#
# Both lists were transcribed from the wall on /introduction as it stands
# today, not from an older copy: entries that page has commented out are
# commented out here too, with the same URLs, so nothing appears or disappears
# silently when /introduction is eventually retired. Uncommenting a line here
# is how one comes back.
# Entries commented out here are commented out on the old /introduction wall
# too, with the same URLs, so nothing appears or disappears silently.
# Uncommenting a line is how one comes back.
#
# Shown to every visitor.
INTERNATIONAL_PARTNERS = [
{ name: 'Open Source Collective', url: 'https://www.oscollective.org/', img: 'partners/osc_mini.png' },
{ name: 'GitHub', url: 'https://github.com/', img: 'partners/github_mini.png' },
{ name: 'RunCam', url: 'https://runcam.com/', img: 'partners/runcam_mini.png' },
{ name: 'CCDCAM', url: 'https://ccdcam.com/', img: 'partners/ccdcam_mini.png' },
{ name: 'wfb-ng', url: 'https://github.com/svpcom/wfb-ng/', img: 'partners/wfb-ng_mini.png' },
{ name: 'RubyFPV', url: 'https://rubyfpv.com/', img: 'partners/rubyfpv_mini.png' },
{ name: 'Mario FPV', url: 'https://www.youtube.com/@mariofpv', img: 'partners/mariofpv_mini.png' },
{ name: 'Linux Chenxing', url: 'https://linux-chenxing.org/', img: 'partners/linuxchenxing_mini.png' },
{ name: 'TUDSaT', url: 'https://www.tudsat.space/', img: 'partners/tudsat_mini.png' },
{ name: 'WüSpace', url: 'https://wuespace.de/', img: 'partners/wuespace_mini.png' },
{ name: 'Really', url: 'https://opencollective.com/really-541ee976', img: 'partners/really_mini.png' }
# Commented out on /introduction, so commented out here:
# { name: 'EMAX', url: 'https://emaxmodel.com/', img: 'partners/emax_mini.png' },
# { name: 'GoodCam', url: 'https://www.goodcam.io/', img: 'partners/goodcam_mini.png' },
#
# partners/baresip_mini.png exists as an asset but has never been on the
# wall. Left off rather than introduced by a refactor.
].freeze
# partners/baresip_mini.png exists as an asset but has never been on the wall.
# Left off rather than introduced by a refactor.
PARTNER_GROUPS = {
# Who hosts our money and our code.
global: [
{ name: 'Open Source Collective', url: 'https://www.oscollective.org/', img: 'partners/osc_mini.png' },
{ name: 'GitHub', url: 'https://github.com/', img: 'partners/github_mini.png' }
],
# Ships hardware with OpenIPC on it.
manufacturers: [
{ name: 'RunCam', url: 'https://runcam.com/', img: 'partners/runcam_mini.png' },
{ name: 'CCDCAM', url: 'https://ccdcam.com/', img: 'partners/ccdcam_mini.png' }
# Commented out on /introduction, so commented out here:
# { name: 'EMAX', url: 'https://emaxmodel.com/', img: 'partners/emax_mini.png' },
],
# Builds systems on it for other people. RU_INTEGRATORS is appended to this
# group for Russian-speaking visitors only -- see partner_groups.
integrators: [
{ name: 'GoodCam', url: 'https://www.goodcam.io/', img: 'partners/goodcam_mini.png' },
{ name: 'AnyCam', url: 'https://anycam.io/', img: 'partners/anycam_mini.png' },
{ name: 'Faceter', url: 'https://faceter.cam/', img: 'partners/faceter_mini.png' },
{ name: 'Really', url: 'https://opencollective.com/really-541ee976', img: 'partners/really_mini.png' }
],
# The FPV projects we grew up alongside.
fpv: [
{ name: 'wfb-ng', url: 'https://github.com/svpcom/wfb-ng/', img: 'partners/wfb-ng_mini.png' },
{ name: 'RubyFPV', url: 'https://rubyfpv.com/', img: 'partners/rubyfpv_mini.png' },
{ name: 'Mario FPV', url: 'https://www.youtube.com/@mariofpv', img: 'partners/mariofpv_mini.png' }
],
# Student and university teams flying or teaching on OpenIPC.
education: [
{ name: 'TUDSaT', url: 'https://www.tudsat.space/', img: 'partners/tudsat_mini.png' },
{ name: 'WuSpace', url: 'https://wuespace.de/', img: 'partners/wuespace_mini.png' }
],
# Kept in the system, rendered nowhere. There is no page for trade shows and
# exhibitions yet; when there is, it asks for :exhibitions and both the logo
# and the link are already here. Deliberately absent from HOME_PARTNER_ROWS
# and from every partner_groups call -- a test holds it that way.
exhibitions: [
{ name: 'Expo Electronica', url: 'https://expoelectronica.ru/en/', img: 'partners/expo-electronica_mini.png' }
],
# Reverse engineering and silicon research we build on.
research: [
{ name: 'Linux Chenxing', url: 'https://linux-chenxing.org/', img: 'partners/linuxchenxing_mini.png' }
]
}.freeze

# Integrators are territory-specific: these serve Russia and are shown only to
# Russian-language visitors. Showing them to everyone was explicitly not
# wanted, and the reverse -- gating them in CSS on /introduction with
# `html:not([lang="ru"])` -- never worked, because no logo on that page ever
# carried the `ru` class the rule selects on.
#
# NOTE FOR REVIEW: this whole block is currently commented out on
# /introduction, so no visitor sees any of it today. Rendering it for :ru
# brings it back. That is what the relaunch plan asks for, but it is a content
# decision rather than a technical one -- say so if it should stay hidden.
# wanted, and the reverse -- gating them in CSS with `html:not([lang="ru"])`
# -- never worked, because no logo ever carried the `ru` class the rule
# selects on.
RU_INTEGRATORS = [
{ name: 'GoodCam', url: 'https://www.goodcam.io/', img: 'partners/goodcam_mini.png' },
{ name: 'SkyCam', url: 'https://skycam.cam/', img: 'partners/skycam_mini.png' },
{ name: 'Vixand', url: 'https://vixand.ru/', img: 'partners/vixand_mini.png' },
{ name: 'Improve IT', url: 'https://3it.ru/', img: 'partners/improve_mini.png' },
Expand All @@ -51,7 +74,6 @@ module PagesHelper
{ name: 'Sputnik', url: 'https://sputnik.systems/', img: 'partners/sputnik_mini.png' },
{ name: 'Techno-Shield', url: 'https://msvoko.ru/', img: 'partners/techno-shield_mini.png' },
{ name: 'KeyTelecom', url: 'https://keytele.com/', img: 'partners/keytelecom_mini.png' },
{ name: 'AnyCam', url: 'https://anycam.io/', img: 'partners/anycam_mini.png' },
{ name: 'WebGlazok', url: 'https://webglazok.com/', img: 'partners/webglazok_mini.png' },
{ name: 'Yucca', url: 'https://yucca.app/en', img: 'partners/yucca_mini.png' },
{ name: 'IPEYE', url: 'https://ipeye.ru/', img: 'partners/ipeye_mini.png' },
Expand All @@ -68,7 +90,6 @@ module PagesHelper
# { name: 'Flagman', url: 'https://flagman.org/', img: 'partners/flagman_mini.png' },
# { name: 'Meldana', url: 'https://meldana.com/', img: 'partners/meldana_mini.png' },
# { name: 'Binary Machines', url: 'https://bmachines.ru/', img: 'partners/binary-machines_mini.png' },
# { name: 'Expo Electronica', url: 'https://expoelectronica.ru/en/', img: 'partners/expo-electronica_mini.png' },
# { name: 'GAINS', url: 'https://gains.company/', img: 'partners/gain_mini.png' }
].freeze

Expand Down Expand Up @@ -104,13 +125,60 @@ def latency_bar_style(path)
"left: #{left.round(1)}%; width: #{width.round(1)}%"
end

# The Russian integrator list is appended here and nowhere else, so every
# caller gets the same territory rule whether it asks for a group or a row.
def logos_in(key)
logos = PARTNER_GROUPS.fetch(key)
logos += RU_INTEGRATORS if key == :integrators && I18n.locale.eql?(:ru)
logos
end

def page_title
[@page_title, 'OpenIPC'].join(' - ')
end

def partner_logos
logos = INTERNATIONAL_PARTNERS
logos += RU_INTEGRATORS if I18n.locale.eql?(:ru)
logos
# How the homepage arranges the six groups. At six rows half of them were a
# single logo under a heading, which reads as a gap rather than a group --
# research is one logo, and integrators is one until the visitor is Russian.
# Three rows, in the order the wall is meant to be read: who ships and
# installs the hardware, who hosts us, and who we work alongside.
#
# /business still asks for its two groups directly. Splitting rows out again
# is a line here, not a rewrite.
# Order matters twice over: the rows appear in the order written here, and
# within a row the groups are laid out in the order they are listed.
HOME_PARTNER_ROWS = {
global: %i[global],
trade: %i[manufacturers integrators],
friends: %i[research fpv education]
}.freeze

# Rows of [label, logos], in the order HOME_PARTNER_ROWS declares. A row whose
# groups are all empty is dropped rather than rendered as a heading over
# nothing -- which is what a territory-specific group looks like in a locale
# that has no entries for it yet.
#
# Note this does not go through partner_logos: there, no arguments means
# every group, so a row that named no groups would quietly render all of them.
def partner_rows(rows)
rows.filter_map do |label, keys|
logos = keys.flat_map { |key| logos_in(key) }
[label, logos] if logos.any?
end
end

# The named groups, in the order asked for, each as [key, logos]. Groups that
# would render empty are dropped rather than left as a heading over nothing.
# With no arguments, every group.
def partner_groups(*keys)
keys = PARTNER_GROUPS.keys if keys.empty?
keys.filter_map do |key|
logos = logos_in(key)
[key, logos] if logos.any?
end
end

def partner_logos(*keys)
partner_groups(*keys).flat_map(&:last)
end
end
5 changes: 2 additions & 3 deletions app/views/layouts/_footer.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<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>
<li><a href="https://github.com/OpenIPC/wiki"><%= t('nav.wiki') %></a></li>
</ul>
</div>
<div class="col-6 col-lg-3">
Expand All @@ -46,7 +46,6 @@
<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">
Expand All @@ -55,7 +54,7 @@
<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://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>
Expand Down
4 changes: 2 additions & 2 deletions app/views/layouts/_navbar.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<%= 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' %>
<%= dropdown_link t('nav.wiki'), 'https://github.com/OpenIPC/wiki' %>
</ul>
</li>
<%= navbar_link t('nav.business'), '/business' %>
Expand All @@ -50,7 +50,7 @@
</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>
<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' %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/admin.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
</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://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>
Expand Down
8 changes: 6 additions & 2 deletions app/views/pages/business.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@
<% end %>
</div>

<%# Who builds on it (territory-specific integrator set) %>
<%# Who builds on it. Manufacturers and integrators only: a commercial
reader is asking who ships and who installs, and our code host and
our university teams are not an answer to that. %>
<h2 class="h4 mb-4"><%= t('.partners_title') %></h2>
<%= render 'shared/logo_wall', logos: partner_logos %>
<% partner_groups(:manufacturers, :integrators).each do |key, logos| %>
<%= render 'shared/logo_wall', logos: logos, title: t("site.partners.#{key}") %>
<% end %>

<%# Engagement steps %>
<h2 class="h4 mt-6 mb-4"><%= t('.how_title') %></h2>
Expand Down
8 changes: 1 addition & 7 deletions app/views/pages/donate.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,13 @@
<p class="text-body-secondary mb-0"><%= t('.accounting') %></p>
</div>
<div class="col-lg-6">
<div class="card p-2 mb-3">
<div class="card p-2">
<div class="card-body">
<h2 class="h5"><i class="bi bi-heart-fill text-danger me-2"></i><%= t('.oc_title') %></h2>
<p class="text-body-secondary"><%= t('.oc_text_html') %></p>
<a href="https://opencollective.com/openipc/contribute/backer-14335/checkout" class="btn btn-primary"><%= t('.oc_button') %></a>
</div>
</div>
<div class="card p-2">
<div class="card-body">
<h2 class="h5"><i class="bi bi-currency-bitcoin text-warning me-2"></i><%= t('.crypto_title') %></h2>
<p class="text-body-secondary mb-0"><%= t('.crypto_text_html') %></p>
</div>
</div>
</div>
</div>

Expand Down
5 changes: 2 additions & 3 deletions app/views/pages/ecosystem.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
projects: [
{ name: 'openhisilicon', desc: t('.proj_openhisilicon'), repo: "#{gh}/openhisilicon", stage: 'wip' },
{ name: 'openxiongmai', desc: t('.proj_openxiongmai'), repo: "#{gh}/openxiongmai", stage: 'rnd' },
{ name: 'qemu-hisilicon', desc: t('.proj_qemu'), repo: 'https://github.com/widgetii/qemu-hisilicon', stage: 'wip' }
{ name: 'qemu-hisilicon', desc: t('.proj_qemu'), repo: "#{gh}/qemu-hisilicon", stage: 'wip' }
]
},
{
Expand All @@ -36,8 +36,7 @@
{ name: 'waybeam_venc', desc: t('.proj_waybeam'), repo: "#{gh}/waybeam_venc", stage: 'done' },
{ name: 'devourer', desc: t('.proj_devourer'), repo: "#{gh}/devourer", stage: 'done' },
{ name: 'PixelPilot_rk', desc: t('.proj_pixelpilot'), repo: "#{gh}/PixelPilot_rk", stage: 'done' },
{ name: 'aviateur', desc: t('.proj_aviateur'), repo: "#{gh}/aviateur", stage: 'done' },
{ name: 'telemetry', desc: t('.proj_telemetry'), repo: "#{gh}/telemetry", stage: 'done' }
{ name: 'aviateur', desc: t('.proj_aviateur'), repo: "#{gh}/aviateur", stage: 'done' }
]
},
{
Expand Down
Loading
Loading