Skip to content

Commit

Permalink
Manage locales
Browse files Browse the repository at this point in the history
  • Loading branch information
virolea committed Sep 2, 2024
1 parent 2295033 commit 323379f
Show file tree
Hide file tree
Showing 27 changed files with 8,298 additions and 6,085 deletions.
561 changes: 1 addition & 560 deletions app/assets/builds/rosetta/application.css

Large diffs are not rendered by default.

13,253 changes: 7,871 additions & 5,382 deletions app/assets/builds/rosetta/application.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions app/assets/javascripts/rosetta/application.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
import "@hotwired/turbo-rails";
import "./controllers";
9 changes: 9 additions & 0 deletions app/assets/javascripts/rosetta/controllers/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Application } from "@hotwired/stimulus";

const application = Application.start();

// Configure Stimulus development experience
application.debug = false;
window.Stimulus = application;

export { application };
37 changes: 37 additions & 0 deletions app/assets/javascripts/rosetta/controllers/dialog_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
static targets = ["dialog", "title", "titleSource", "content"];

open(e) {
e.preventDefault();
const link = e.currentTarget;
this.dialogTarget.showModal();
this.loadingContent = this.contentTarget.innerHTML;
this.contentTarget.src = link.href;
}

safeClose(e) {
if (this.contentTarget.contains(e.target)) return;
this.close();
}

close(e) {
this.dialogTarget.close();
this.resetContent();
}

titleSourceTargetConnected(e) {
const title = e.textContent;
this.setTitle(title);
}

resetContent() {
this.contentTarget.innerHTML = this.loadingContent;
this.setTitle("");
}

setTitle(value) {
this.titleTarget.textContent = value;
}
}
4 changes: 4 additions & 0 deletions app/assets/javascripts/rosetta/controllers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { application } from "./application";

import DialogController from "./dialog_controller";
application.register("dialog", DialogController);
21 changes: 21 additions & 0 deletions app/assets/stylesheets/rosetta/application.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
.btn {
@apply rounded-md px-3 py-2 text-sm font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2;
}
.btn-primary {
@apply bg-indigo-600 text-white hover:bg-indigo-500 focus-visible:outline-indigo-600;
}
.btn-secondary {
@apply bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50;
}
.label {
@apply text-sm font-medium leading-6 text-gray-900;
}
.input {
@apply block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6;
}
.badge {
@apply inline-flex items-center rounded-md bg-gray-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10;
}
}
32 changes: 32 additions & 0 deletions app/controllers/rosetta/locales_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module Rosetta
class LocalesController < ApplicationController
def index
@locales = Locale.all
end

def new
@locale = Locale.new
end

def create
@locale = Locale.new(locale_params)

if @locale.save
redirect_to locales_path
else

render turbo_stream: turbo_stream.replace(
:dialog_content,
partial: "form",
locals: { locale: @locale }
)
end
end

private

def locale_params
params.require(:locale).permit(:name, :code)
end
end
end
1 change: 1 addition & 0 deletions app/helpers/rosetta/application_helper.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
module Rosetta
module ApplicationHelper
include DialogHelper
end
end
11 changes: 11 additions & 0 deletions app/helpers/rosetta/dialog_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module Rosetta
module DialogHelper
def within_modal(&block)
turbo_frame_tag :dialog_content, &block
end

def modal_title(title)
tag.h1(title, class: "hidden", data: { dialog_target: "titleSource" })
end
end
end
15 changes: 15 additions & 0 deletions app/models/rosetta/locale.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Rosetta
class Locale < ApplicationRecord
CODE_FORMAT = /\A[a-zA-Z]+(-[a-zA-Z]+)?\z/

validates :name, :code, presence: true
validates :code, uniqueness: true
validates :code, format: { with: CODE_FORMAT, message: "must only contain letters separated by an optional dash" }

class << self
def available_locales
pluck(:code).map(&:to_sym)
end
end
end
end
20 changes: 20 additions & 0 deletions app/views/layouts/rosetta/_dialog.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<dialog class="absolute max-w-4xl w-full mx-auto p-12 top-4 left-0 m-0 h-full bg-transparent" data-dialog-target="dialog" data-action="close->dialog#resetContent click->dialog#safeClose">
<div class="bg-white shadow ring-1 ring-black ring-opacity-5 max-w-xl mt-4 mx-auto rounded-lg overflow-hidden w-full">
<div class="flex justify-between bg-gray-50 py-4 px-6 text-gray-900 font-semibold border-b border-gray-300">
<h4 data-dialog-target="title"></h4>

<button type="button" class="rounded-md text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2" data-action="dialog#close">
<span class="sr-only">Close</span>
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>

<div class="p-4">
<%= turbo_frame_tag "dialog_content", data: { dialog_target: "content" } do %>
<%= yield %>
<% end %>
</div>
</div>
</dialog>
7 changes: 7 additions & 0 deletions app/views/layouts/rosetta/_navbar.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<nav class="border-b border-gray-200 bg-white">
<div class="mx-auto max-w-4xl px-4 sm:px-6 lg:px-8">
<div class="flex items-center">
<%= link_to "Rosetta", root_path, class: "text-xl font-bold" %>
</div>
</div>
</nav>
19 changes: 16 additions & 3 deletions app/views/layouts/rosetta/application.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html class="h-full">
<head>
<title>Rosetta</title>
<%= csrf_meta_tags %>
Expand All @@ -10,9 +10,22 @@
<%= stylesheet_link_tag "rosetta/application", media: "all" %>
<%= javascript_include_tag "rosetta/application", defer: true %>
</head>
<body>
<body class="h-full" data-controller="dialog">
<div class="min-h-full">
<%= render "layouts/rosetta/navbar" %>

<%= yield %>
<main class="mx-auto max-w-4xl px-4 sm:px-6 lg:px-8 py-10">
<%= yield %>
</main>
</div>

<%= render "layouts/rosetta/dialog" do %>
<div class="flex justify-around py-12">
<svg class="animate-spin h-5 w-5 text-black" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
</div>
<% end %>
</body>
</html>
33 changes: 33 additions & 0 deletions app/views/rosetta/locales/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<%= form_with model: locale, class: "grid gap-2" do |f| %>
<% if @locale.errors[:code].any? %>
<div class="rounded-md bg-red-50 p-4">
<div class="flex">
<div class="flex-shrink-0">
<svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z" clip-rule="evenodd" />
</svg>
</div>
<div class="ml-3">
<div class="text-sm text-red-700">
Please check the format of your locale code, and make sure it does not already exist.
</div>
</div>
</div>
</div>
<% end %>

<div>
<%= f.label :name, class: "label" %>
<%= f.text_field :name, class: "input max-w-xs", required: true %>
</div>

<div>
<%= f.label :code, class: "label" %>
<%= f.text_field :code, class: "input max-w-24", required: true %>
<p class="mt-1 text-sm leading-6 text-gray-600">
Must only contain letters separated by an optional dash, e.g. <span class="badge">en-GB</span>.
</p>
</div>

<%= f.submit class: "btn btn-primary mt-2" %>
<% end %>
13 changes: 13 additions & 0 deletions app/views/rosetta/locales/_locale.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<tr>
<td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6">
<%= locale.name %>
</td>
<td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
<span class="badge">
<%= locale.code %>
</span>
</td>
<td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
<a href="#" class="text-indigo-600 hover:text-indigo-900">Edit<span class="sr-only">, <%= locale.name %></span></a>
</td>
</tr>
31 changes: 31 additions & 0 deletions app/views/rosetta/locales/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<div class="sm:flex sm:items-center">
<div class="sm:flex-auto">
<h1 class="text-base font-semibold leading-6 text-gray-900">Locales</h1>
<p class="mt-2 text-sm text-gray-700">
Manage the locales for your project.
</p>
</div>

<div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
<%= link_to "Add locale", new_locale_path, class: "btn btn-primary", data: { action: "dialog#open" } %>
</div>
</div>

<div class="mt-8">
<div class="overflow-hidden shadow ring-1 ring-black ring-opacity-5 sm:rounded-lg">
<table class="min-w-full divide-y divide-gray-300">
<thead class="bg-gray-50">
<tr>
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">Name</th>
<th scope="col" class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">Key</th>
<th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-6">
<span class="sr-only">Edit</span>
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200 bg-white">
<%= render @locales %>
</tbody>
</table>
</div>
</div>
4 changes: 4 additions & 0 deletions app/views/rosetta/locales/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<%= within_modal do %>
<%= modal_title "Add a new locale" %>
<%= render "form", locale: @locale %>
<% end %>
3 changes: 3 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
Rosetta::Engine.routes.draw do
root to: "locales#index"

resources :locales
end
12 changes: 12 additions & 0 deletions db/migrate/20240830123523_create_rosetta_locales.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateRosettaLocales < ActiveRecord::Migration[7.2]
def change
create_table :rosetta_locales do |t|
t.string :name
t.string :code
t.boolean :published, default: false

t.timestamps
end
add_index :rosetta_locales, :code, unique: true
end
end
2 changes: 2 additions & 0 deletions lib/rosetta/engine.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "turbo-rails"

module Rosetta
class Engine < ::Rails::Engine
isolate_namespace Rosetta
Expand Down
Loading

0 comments on commit 323379f

Please sign in to comment.