Mattias Bodlund 3 days ago
parent
commit
94cb418734
10 changed files with 35 additions and 638 deletions
  1. +2
    -0
      README.txt
  2. +1
    -527
      app/assets/stylesheets/application.css
  3. +0
    -1
      app/controllers/admin/nodes_controller.rb
  4. +1
    -1
      app/helpers/admin/nodes_helper.rb
  5. +15
    -14
      app/models/node.rb
  6. +6
    -5
      app/views/admin/nodes/_form.html.erb
  7. +2
    -37
      app/views/languages/index.html.erb
  8. +4
    -8
      app/views/layouts/application.html.erb
  9. +4
    -3
      config/locales/en.yml
  10. +0
    -42
      update_css.rb

+ 2
- 0
README.txt View File

@ -23,3 +23,5 @@ Gem
------------------- -------------------
bundle config set --local without 'development test' bundle config set --local without 'development test'
https://miro.com/app/board/uXjVG_Og9ms=/?utm_source=notification&utm_medium=email&utm_campaign=daily-updates&utm_content=view-board-cta&lid=599kz7rhrs0e
https://miro.com/app/board/uXjVG_Og9ms=/

+ 1
- 527
app/assets/stylesheets/application.css View File

@ -100,61 +100,6 @@
background-color: #0058a3; background-color: #0058a3;
} }
header {
view-transition-name: none;
}
main {
view-transition-name: main;
}
footer {
view-transition-name: none;
}
::view-transition-old(root),
::view-transition-new(root) {
animation: none; /* takes them out of the overlay tree */
}
::view-transition-old(main) {
z-index: 1;
}
::view-transition-new(main) {
z-index: 2;
}
@keyframes slide-in {
from {
transform: translateY(100dvh);
}
to {
transform: translateY(0);
}
}
@keyframes slide-out {
from {
transform: translateY(0);
}
to {
transform: translateY(-100dvh);
}
}
/* Forward nav (normal clicks) */
html[data-turbo-visit-direction="forward"] {
&::view-transition-new(main) { animation: slide-in .3s ease-out both; }
&::view-transition-old(main) { animation: slide-out .3s ease-in both; }
}
/* Back button reverses the sense */
html[data-turbo-visit-direction="back"] {
&::view-transition-new(main) { animation: none }
&::view-transition-old(main) { animation: none }
}
body { body {
background-color: var(--clr-dark-yellow); background-color: var(--clr-dark-yellow);
@ -163,6 +108,7 @@ body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0; gap: 0;
min-height: 100vh;
min-height: 100dvh; min-height: 100dvh;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
touch-action: manipulation; touch-action: manipulation;
@ -224,478 +170,6 @@ footer {
color: var(--clr-white); color: var(--clr-white);
} }
.language__selector-select {
position: relative;
display: inline-block;
}
.hidden-select {
position: absolute;
opacity: 0;
width: 100%;
height: 100%;
top: 0;
left: 0;
cursor: pointer;
z-index: 1;
font-size: var(--fs-base);
border: 2px solid red;
}
.hidden-select-value {
background-color: var(--clr-black);
color: var(--clr-white);
font-size: var(--fs-base);
font-weight: 700;
font-family: var(--ff-ikea);
line-height: 1;
border-radius: 400px;
height: 43px;
padding: 0 20px;
display: inline-flex;
align-items: center;
& > div {
display: inline-flex;
align-items: baseline;
gap: 0.4em;
pointer-events: none;
}
& svg {
width: 8px;
height: auto;
}
}
.button__base {
appearance: none;
background-color: var(--clr-black);
border: 2px solid var(--clr-black);
color: var(--clr-white);
font-size: var(--fs-base);
font-family: var(--ff-ikea);
font-weight: 700;
height: 2.75rem;
border-radius: 2.75rem;
width: 100%;
cursor: pointer;
text-decoration: none;
display: flex;
align-items: center;
justify-content: center;
padding: 0 1em;
box-sizing: border-box;
transition: transform 0.08s ease-in-out;
user-select: none;
-webkit-user-select: none;
-webkit-tap-highlight-color: transparent;
&:not(.wiggle):active {
transform: scale(0.96);
}
}
@keyframes wiggle {
0%, 100% { transform: translateX(0); }
15% { transform: translateX(-6px); }
30% { transform: translateX(6px); }
45% { transform: translateX(-4px); }
60% { transform: translateX(4px); }
75% { transform: translateX(-2px); }
}
.wiggle {
animation: wiggle 0.45s ease-in-out;
}
.button__base-light {
background-color: transparent;
color: var(--clr-black);
}
main {
padding: 50px 0.75rem 1rem 0.75rem;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: end;
&:has(.with-backdrop) {
background-color: var(--clr-dark-yellow);
}
}
.background-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
& img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
opacity: 0;
transition: opacity 0.4s ease-in-out;
&.loaded {
opacity: 1;
}
}
}
@media (min-width: 474px) {
main {
justify-content: center;
}
}
.intro-container {
display: grid;
grid-template-columns: 1;
grid-template-rows: auto;
/*gap: 8px;*/
}
.intro-content-container,
.question-container {
display: grid;
grid-template-columns: 1;
grid-template-rows: auto;
/*gap: 8px;*/
width: 100%;
}
.intro-container,
.question-container {
max-width: 450px;
margin: 0 auto;
}
.intro-content-header,
.intro-content-body {
padding: 1rem 0.75rem;
border-radius: 0.75rem;
}
.intro-content-header {
background-color: var(--clr-white);
font-size: var(--fs-2xl);
line-height: 1.2;
font-weight: 700;
}
.intro-content-body {
background-color: var(--clr-medium-yellow);
font-size: var(--fs-base);
line-height: 1.4;
}
.question-step {
font-size: var(--fs-s);
font-weight: 700;
line-height: 1;
display: flex;
& div {
background-color: var(--clr-medium-yellow);
padding: 0.625rem 0.75rem;
border-radius: 400px;
}
}
.question-header {
background-color: var(--clr-medium-yellow);
border-radius: 1rem;
font-size: var(--fs-xl);
line-height: 1.2;
font-weight: 700;
padding: 1rem 0.75rem;
}
.error {
padding: 1rem 0.75rem;
border-radius: 1rem;
background-color: var(--clr-text-highlight);
color: var(--clr-black);
font-size: var(--fs-s);
line-height: 1.2;
}
.question-answer {
font-size: var(--fs-lg);
line-height: 1.4;
& label {
display: block;
padding: 1rem 0.75rem;
border-radius: 1rem;
background-color: var(--clr-white);
cursor: pointer;
user-select: none;
-webkit-user-select: none;
-webkit-tap-highlight-color: transparent;
& div {
position: relative;
display: inline-block;
padding: 0 0.2em;
margin: 0 -0.2em;
}
& div::after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--clr-text-highlight);
clip-path: inset(0 100% 0 0);
transition: clip-path 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
z-index: 1;
mix-blend-mode: darken;
}
}
& input[type=radio] {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
&:has(input[type=radio]:checked) {
& label>div::after {
clip-path: inset(0 0 0 0);
}
}
& + .question-answer {
margin-top: 8px;
}
}
.question-container {
& em {
font-style: normal;
background-color: var(--clr-text-highlight);
padding: 1px 2px;
margin-right: -2px;
}
& strong {
font-weight: 700;
}
}
.question-result, .result-stats {
background-color: var(--clr-medium-yellow);
border-radius: 0.75rem;
font-size: var(--fs-base);
line-height: 1.4;
padding: 1rem 0.75rem;
}
.result-actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5rem;
& a {
background-color: var(--clr-medium-yellow);
border-color: var(--clr-medium-yellow);
color: var(--clr-black)
}
}
.answers-distribution {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
height: 45dvh;
max-height: 300px;
& > div {
box-sizing: border-box;
padding: 1rem 0.75rem;
background-color: var(--clr-medium-yellow);
border-radius: 0.75rem;
color: var(--clr-dark-yellow);
font-size: var(--fs-s);
font-weight: 700;
line-height: 1.3;
align-self: end;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 0;
transition: background-color 200ms ease-in-out, color 200ms ease-in-out;
&.answered {
background-color: var(--clr-white);
color: var(--clr-black);
}
}
& .explanation {
display: none;
}
& .percentage {
font-size: var(--fs-4xl);
line-height: 1;
opacity: 0;
&::after {
content: '%';
font-size: 2.5rem;
}
}
}
.breakable {
overflow-wrap: break-word;
word-wrap: break-word;
hyphens: auto;
}
.result-msg {
background-color: var(--clr-white);
border-radius: 0.75rem;
font-size: var(--fs-base);
line-height: 1.4;
padding: 1.25rem 0.75rem;
& h1 {
font-size: var(--fs-3xl);
line-height: 1.1;
margin: 0 0 0.4em 0;
overflow-wrap: break-word;
word-wrap: break-word;
hyphens: auto;
}
& div:first-child {
font-weight: 700;
}
}
label.question-answer {
display: flex;
align-items: start;
height: 6.75rem;
cursor: pointer;
padding: 1rem 0.75rem;
border-radius: 1rem;
background-color: var(--clr-white);
& input {
flex-grow: 1;
border: none;
outline: none;
font-size: var(--fs-lg);
line-height: 1.4;
padding: 0;
}
&:has(.field_with_errors) {
outline: 4px solid var(--clr-text-highlight);
outline-offset: -4px;
}
}
label {
cursor: pointer;
}
.animation-element {
box-sizing: border-box;
opacity: 0;
padding-top: 8px;
&:last-child {
padding-top: 12px;
}
& > * {
box-sizing: border-box;
}
}
.typewriter-cursor::after {
content: '|';
animation: typewriter-blink 1s infinite;
color: currentColor;
font-weight: 400;
position: absolute;
}
@keyframes typewriter-blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
/*.cursor {
animation: blink 1000ms infinite;
color: var(--clr-black);
font-weight: 400;
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}*/
@media (min-width: 815px) {
header {
top: 1.25rem;
left: 1.875rem;
}
main {
padding: calc(50px + 1.25rem) 1.25rem 1.875rem 1.25rem;
}
footer {
top: 1.25rem;
right: 1.875rem;
}
}
[data-locale] { [data-locale] {
display: none; display: none;
} }


+ 0
- 1
app/controllers/admin/nodes_controller.rb View File

@ -36,7 +36,6 @@ class Admin::NodesController < Admin::AdminController
@node = Node.new(node_params) @node = Node.new(node_params)
@node.status = :status_draft @node.status = :status_draft
@node.template = @node.root.site? ? Node::NODE_TEMPLATES.first : Node::TILE_TEMPLATES.first
base_title = t('ui.untitled') base_title = t('ui.untitled')
title = base_title title = base_title


+ 1
- 1
app/helpers/admin/nodes_helper.rb View File

@ -7,7 +7,7 @@ module Admin::NodesHelper
result << [parent.title, parent.id] if parent.root? result << [parent.title, parent.id] if parent.root?
parent.children.ordered.each do |child| parent.children.ordered.each do |child|
result << ["#{"\u00A0\u00A0" * (child.depth)}#{child.title}".html_safe, child.id, { disabled: (child == node or child.ancestor_ids.include?(node.id)) }]
result << ["#{"-" * (child.depth)} #{child.title}".html_safe, child.id, { disabled: (child == node or child.ancestor_ids.include?(node.id)) }]
result = result + node_structure_for_select(child, node) result = result + node_structure_for_select(child, node)
end end


+ 15
- 14
app/models/node.rb View File

@ -12,27 +12,28 @@ class Node < ApplicationRecord
extend Mobility extend Mobility
translates :slug, translates :slug,
:tags,
locale_accessors: I18n.available_locales,
fallbacks: {zh: :en, hr: :en, cs: :en, da: :en, nl: :en, fi: :en, fr: :en, fr_ca: :en, de: :en, hu: :en, it: :en, ja: :en, ko: :en, nb: :en, pl: :en, pt: :en, ro: :en, sr: :en, sk: :en, sl: :en, es: :en, sv: :en, uk: :en}
:tags,
locale_accessors: I18n.available_locales,
fallbacks: {zh: :en, hr: :en, cs: :en, da: :en, nl: :en, fi: :en, fr: :en, fr_ca: :en, de: :en, hu: :en, it: :en, ja: :en, ko: :en, nb: :en, pl: :en, pt: :en, ro: :en, sr: :en, sk: :en, sl: :en, es: :en, sv: :en, uk: :en}
translates :title, translates :title,
:url,
:href,
:page_title,
:page_description,
locale_accessors: I18n.available_locales,
fallbacks: {zh: :en, hr: :en, cs: :en, da: :en, nl: :en, fi: :en, fr: :en, fr_ca: :en, de: :en, hu: :en, it: :en, ja: :en, ko: :en, nb: :en, pl: :en, pt: :en, ro: :en, sr: :en, sk: :en, sl: :en, es: :en, sv: :en, uk: :en}
:url,
:href,
:page_title,
:page_description,
locale_accessors: I18n.available_locales,
fallbacks: {zh: :en, hr: :en, cs: :en, da: :en, nl: :en, fi: :en, fr: :en, fr_ca: :en, de: :en, hu: :en, it: :en, ja: :en, ko: :en, nb: :en, pl: :en, pt: :en, ro: :en, sr: :en, sk: :en, sl: :en, es: :en, sv: :en, uk: :en}
NODE_TEMPLATES = %w"tmpl_article tmpl_index tmpl_list"
enum :status, { status_published: 0, status_draft: 1, status_archived: 2 } enum :status, { status_published: 0, status_draft: 1, status_archived: 2 }
enum :template, { tmpl_index: 0,
tmpl_article: 1,
tmpl_list: 2
}
enum :template, {
tmpl_article: 0,
tmpl_chance: 1,
tmpl_choice: 2,
tmpl_bonus: 3
}
include PgSearch::Model include PgSearch::Model
pg_search_scope :pg_search, pg_search_scope :pg_search,


+ 6
- 5
app/views/admin/nodes/_form.html.erb View File

@ -65,11 +65,12 @@
} unless form.object.root? %> } unless form.object.root? %>
<%= render partial: 'material/select_field', <%= render partial: 'material/select_field',
locals: {
f: form,
attr: :template,
include_blank: form.object.root?,
choices: Node.templates.slice(*(Node::NODE_TEMPLATES)).map { |k,v| [t(k, scope: :'nodes.templates'), k] }.sort } %>
locals: {
f: form,
attr: :template,
include_blank: false,
choices: Node.templates.map { |k,v| [t(k, scope: :'nodes.templates'), k] }.sort
} %>
<%= render partial: 'material/tom_select_field', <%= render partial: 'material/tom_select_field',
locals: { locals: {


+ 2
- 37
app/views/languages/index.html.erb View File

@ -1,38 +1,3 @@
<%-
content_for :title, t('project_name')
%>
<div class="intro-container">
<div class="animation-element" data-controller="locale" data-locale-url-value="<%= url_for(controller: 'languages', action: 'update') %>">
<div class="language__selector-select">
<%= select_tag :language,
options_for_select(languages_for_select, accept_language),
id: 'language_select',
class: 'hidden-select',
data: {
action: 'change->locale#changeLocale',
locale_target: 'select'
} %>
<div class="hidden-select-value">
<div>
<span data-locale-target="current"><%= t accept_language, scope: 'languages' %></span>
<%= svg 'ico-arrow-down' %>
</div>
</div>
</div>
</div>
<div id="intro" class="intro-content-container">
<%= render partial: 'intro' %>
</div>
</div>
<%- content_for :title, t('project_name') %>
<h1>Intro</h1>

+ 4
- 8
app/views/layouts/application.html.erb View File

@ -4,14 +4,10 @@
<title><%= content_for?(:title) ? yield(:title) : t(:project_name) %></title> <title><%= content_for?(:title) ? yield(:title) : t(:project_name) %></title>
<meta charset="utf-8"> <meta charset="utf-8">
<%= tag :meta, name: 'description', content: content_for?(:meta_description) ? yield(:meta_description) : (@node.present?? @node.page_description : '') %>
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="turbo-prefetch" content="false">
<meta name="turbo-cache-control" content="no-cache">
<meta name="view-transition" content="same-origin">
<meta name="theme-color" content="#F0B902">
<%= tag.meta name: 'description', content: content_for?(:meta_description) ? yield(:meta_description) : (@node.present?? @node.page_description : '') %>
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
<%= csp_meta_tag %> <%= csp_meta_tag %>
@ -27,7 +23,7 @@
<body> <body>
<header data-quiz-images="<%= quiz_image_urls.to_json if defined?(quiz_image_urls) %>">
<header>
<%= link_to svg('ikea-foundation-203x22'), url_for(controller: 'languages', action: (I18n.default_locale == I18n.locale ? 'index' : 'show')) %> <%= link_to svg('ikea-foundation-203x22'), url_for(controller: 'languages', action: (I18n.default_locale == I18n.locale ? 'index' : 'show')) %>
</header> </header>


+ 4
- 3
config/locales/en.yml View File

@ -210,9 +210,10 @@ en:
en: English en: English
de: German de: German
templates: templates:
tmpl_index: Get started
tmpl_list: Result
tmpl_article: Question
tmpl_article: Side
tmpl_chance: Chance
tmpl_choice: Choice
tmpl_bonus: Bonus chance
categories: categories:
box: Box box: Box
folder: Folder folder: Folder


+ 0
- 42
update_css.rb View File

@ -1,42 +0,0 @@
FILES = [
"app/assets/stylesheets/admin.css",
"app/assets/stylesheets/application.css",
"app/assets/stylesheets/assets.css",
"app/assets/stylesheets/attachments.css",
"app/assets/stylesheets/form.css",
"app/assets/stylesheets/forms.css",
"app/assets/stylesheets/lists.css",
"app/assets/stylesheets/nodes.css",
"app/assets/stylesheets/popup-menu.css",
"app/assets/stylesheets/sessions.css",
"app/assets/stylesheets/tom-select.css"
]
FILES.each do |file_path|
full_path = File.join(Dir.pwd, file_path)
next unless File.exist?(full_path)
content = File.read(full_path)
# 1. Recalculate rem values
# Improved regex to handle .75rem as well as 0.75rem and 1rem
content.gsub!(/(\d*\.\d+|\d+)rem/) do |match|
numeric_part = $1
val = numeric_part.to_f
new_val = (val * 0.625).to_r.to_f
formatted_val = new_val.to_s.gsub(/\.0$/, "")
# If the original was .75rem, we might want to keep the dot-only style,
# but 0.46875rem is more standard and safer.
"#{formatted_val}rem"
end
# 2. Update font-size/font from 10px to 16px
# Only inside font or font-size declarations
content.gsub!(/(font(?:-size)?\s*:\s*[^;]+;)/i) do |decl|
decl.gsub(/\b10px\b/, "16px")
end
File.write(full_path, content)
puts "Updated #{file_path}"
end

Loading…
Cancel
Save