Skip to content
Draft
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
63 changes: 63 additions & 0 deletions app/controllers/quran_explorer_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
class QuranExplorerController < ApplicationController
before_action :load_chapter, only: [:surah, :ayah]
before_action :load_verse, only: [:ayah, :word]
before_action :load_word, only: [:word]

def index
@chapters = Chapter.includes(:translated_names).order(:chapter_number)
end

def surah
@chapter_info = ChapterInfo.where(chapter_id: @chapter.id, language_id: 38).first # English
@verses = @chapter.verses.includes(:translations, :audio_files).limit(10)
@stats = {
verses_count: @chapter.verses_count,
words_count: @chapter.verses.sum(:words_count) || 0,
pages: @chapter.pages,
rukus_count: @chapter.rukus_count
}
rescue => e
Rails.logger.error "Error loading surah #{@chapter.id}: #{e.message}"
@stats = { verses_count: 0, words_count: 0, pages: 'N/A', rukus_count: 'N/A' }
end

def ayah
@translations = @verse.translations.includes(:resource_content, :language)
@tafsirs = @verse.tafsirs.includes(:resource_content, :language)
@audio_files = @verse.audio_files.includes(:recitation)
@words = @verse.words.includes(:word_translations, :root, :lemma, :stem).order(:position)
@morphology_words = @verse.morphology_words.includes(:grammar_concepts)
end

def word
@translations = @word.word_translations.includes(:language)
@morphology_word = @word.morphology_word
@related_words = Word.where(root_id: @word.root_id).where.not(id: @word.id).limit(10) if @word.root_id
end

private

def load_chapter
@chapter = Chapter.find_by(chapter_number: params[:surah_id]) || Chapter.find(params[:surah_id])
redirect_to quran_explorer_path unless @chapter
end

def load_verse
if params[:ayah_id]
@verse = @chapter.verses.find_by(verse_number: params[:ayah_id])
elsif params[:verse_key]
@verse = Verse.find_by(verse_key: params[:verse_key])
@chapter = @verse.chapter if @verse
end
redirect_to quran_explorer_surah_path(@chapter.chapter_number) unless @verse
end

def load_word
if params[:word_id]
@word = @verse.words.find(params[:word_id])
elsif params[:word_position]
@word = @verse.words.find_by(position: params[:word_position])
end
redirect_to quran_explorer_ayah_path(@chapter.chapter_number, @verse.verse_number) unless @word
end
end
2 changes: 2 additions & 0 deletions app/views/landing/_header.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
</div>

<div class="tw-flex tw-gap-2 md:tw-gap-4 tw-items-center">
<%= link_to 'Explorer', quran_explorer_path, class: 'tw-text-black tw-hidden md:tw-flex' %>
<%= link_to 'Resources', resources_path, class: 'tw-text-black tw-hidden md:tw-flex' %>
<%= link_to 'Tools', tools_path, class: 'tw-text-black tw-hidden md:tw-flex' %>
<%= link_to 'Community', 'https://discord.gg/HAcGh8mfmj', target: '_blank', class: 'tw-text-black tw-hidden md:tw-flex' %>
Expand Down Expand Up @@ -60,6 +61,7 @@
</div>
<div class="offcanvas-body">
<div class="tw-flex tw-flex-col tw-gap-3 tw-font-bold tw-mt-4">
<%= link_to 'Explorer', quran_explorer_path, class: 'tw-text-black tw-text-lg' %>
<%= link_to 'Resources', resources_path, class: 'tw-text-black tw-text-lg' %>
<%= link_to 'Tools', tools_path, class: 'tw-text-black tw-text-lg' %>
<%= link_to 'Credits', credits_path, class: 'tw-text-black tw-text-lg]' %>
Expand Down
231 changes: 231 additions & 0 deletions app/views/quran_explorer/ayah.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
<div class="tw-min-h-screen tw-bg-gray-50">
<div class="tw-max-w-7xl tw-mx-auto tw-px-4 tw-py-8">
<!-- Breadcrumb -->
<nav class="tw-mb-6">
<%= link_to quran_explorer_path, class: "tw-text-blue-600 hover:tw-text-blue-800" do %>
Explorer
<% end %>
<span class="tw-mx-2 tw-text-gray-400">/</span>
<%= link_to quran_explorer_surah_path(@chapter.chapter_number), class: "tw-text-blue-600 hover:tw-text-blue-800" do %>
<%= @chapter.name_simple %>
<% end %>
<span class="tw-mx-2 tw-text-gray-400">/</span>
<span class="tw-text-gray-600">Verse <%= @verse.verse_number %></span>
</nav>

<!-- Header -->
<div class="tw-bg-white tw-rounded-lg tw-shadow-md tw-p-8 tw-mb-8">
<div class="tw-text-center tw-mb-6">
<h1 class="tw-text-2xl tw-font-bold tw-text-gray-900 tw-mb-2">
<%= @chapter.name_simple %> <%= @verse.verse_number %>
</h1>
<p class="tw-text-gray-600">
Verse <%= @verse.verse_number %> of <%= @chapter.verses_count %> •
<%= @verse.words_count %> words
</p>
</div>

<!-- Navigation -->
<div class="tw-flex tw-justify-center tw-gap-4 tw-mb-6">
<% if @verse.verse_number > 1 %>
<%= link_to quran_explorer_ayah_path(@chapter.chapter_number, @verse.verse_number - 1),
class: "tw-bg-gray-200 hover:tw-bg-gray-300 tw-px-4 tw-py-2 tw-rounded tw-text-sm tw-shadow-sm" do %>
← Previous Verse
<% end %>
<% end %>

<%= link_to quran_explorer_surah_path(@chapter.chapter_number),
class: "tw-bg-blue-600 hover:tw-bg-blue-700 tw-text-white tw-px-4 tw-py-2 tw-rounded tw-text-sm tw-shadow-sm" do %>
Back to Surah
<% end %>

<% if @verse.verse_number < @chapter.verses_count %>
<%= link_to quran_explorer_ayah_path(@chapter.chapter_number, @verse.verse_number + 1),
class: "tw-bg-gray-200 hover:tw-bg-gray-300 tw-px-4 tw-py-2 tw-rounded tw-text-sm tw-shadow-sm" do %>
Next Verse →
<% end %>
<% end %>
</div>
</div>

<!-- Arabic Text -->
<div class="tw-bg-white tw-rounded-lg tw-shadow-md tw-p-8 tw-mb-8">
<h2 class="tw-text-xl tw-font-bold tw-text-gray-900 tw-mb-6">Arabic Text</h2>

<!-- Different Scripts -->
<div class="tw-space-y-6">
<div>
<h3 class="tw-text-sm tw-font-medium tw-text-gray-700 tw-mb-3">Uthmani Script</h3>
<div class="tw-text-3xl tw-text-gray-900 tw-leading-relaxed tw-p-4 tw-bg-gray-50 tw-rounded-lg" dir="rtl">
<%= @verse.text_uthmani %>
</div>
</div>

<% if @verse.text_qpc_hafs.present? %>
<div>
<h3 class="tw-text-sm tw-font-medium tw-text-gray-700 tw-mb-3">QPC Hafs Script</h3>
<div class="tw-text-3xl tw-text-gray-900 tw-leading-relaxed tw-p-4 tw-bg-gray-50 tw-rounded-lg" dir="rtl">
<%= @verse.text_qpc_hafs %>
</div>
</div>
<% end %>

<% if @verse.text_indopak.present? %>
<div>
<h3 class="tw-text-sm tw-font-medium tw-text-gray-700 tw-mb-3">IndoPak Script</h3>
<div class="tw-text-3xl tw-text-gray-900 tw-leading-relaxed tw-p-4 tw-bg-gray-50 tw-rounded-lg" dir="rtl">
<%= @verse.text_indopak %>
</div>
</div>
<% end %>
</div>
</div>

<!-- Word-by-Word Analysis -->
<div class="tw-bg-white tw-rounded-lg tw-shadow-md tw-p-8 tw-mb-8">
<h2 class="tw-text-xl tw-font-bold tw-text-gray-900 tw-mb-6">Word-by-Word Analysis</h2>

<div class="tw-grid tw-grid-cols-1 sm:tw-grid-cols-2 lg:tw-grid-cols-3 xl:tw-grid-cols-4 tw-gap-4">
<% @words.each do |word| %>
<%= link_to quran_explorer_word_path(@chapter.chapter_number, @verse.verse_number, word.position),
class: "tw-block tw-p-4 tw-border tw-border-gray-200 tw-rounded-lg hover:tw-border-blue-500 hover:tw-shadow-md tw-transition-all tw-duration-200" do %>
<div class="tw-text-center">
<div class="tw-text-2xl tw-text-gray-900 tw-mb-2" dir="rtl">
<%= word.text_uthmani %>
</div>

<% if word.en_translation&.text.present? %>
<div class="tw-text-sm tw-text-gray-700 tw-mb-2">
<%= word.en_translation.text %>
</div>
<% end %>

<div class="tw-text-xs tw-text-gray-500">
Position <%= word.position %>
<% if word.root %>
• Root: <%= word.root.text_uthmani %>
<% end %>
</div>
</div>
<% end %>
<% end %>
</div>
</div>

<!-- Translations -->
<% if @translations.any? %>
<div class="tw-bg-white tw-rounded-lg tw-shadow-md tw-p-8 tw-mb-8">
<h2 class="tw-text-xl tw-font-bold tw-text-gray-900 tw-mb-6">Translations</h2>

<div class="tw-space-y-6">
<% @translations.each do |translation| %>
<div class="tw-border-l-4 tw-border-blue-500 tw-pl-6">
<div class="tw-flex tw-items-center tw-justify-between tw-mb-2">
<h3 class="tw-font-medium tw-text-gray-900">
<%= translation.language.name %>
</h3>
<span class="tw-text-sm tw-text-gray-500">
<%= translation.resource_content&.name %>
</span>
</div>
<div class="tw-text-gray-700">
<%= simple_format(translation.text) %>
</div>
</div>
<% end %>
</div>
</div>
<% end %>

<!-- Tafsir -->
<% if @tafsirs.any? %>
<div class="tw-bg-white tw-rounded-lg tw-shadow-md tw-p-8 tw-mb-8">
<h2 class="tw-text-xl tw-font-bold tw-text-gray-900 tw-mb-6">Tafsir (Commentary)</h2>

<div class="tw-space-y-6">
<% @tafsirs.each do |tafsir| %>
<div class="tw-border-l-4 tw-border-green-500 tw-pl-6">
<div class="tw-flex tw-items-center tw-justify-between tw-mb-2">
<h3 class="tw-font-medium tw-text-gray-900">
<%= tafsir.resource_content&.name %>
</h3>
<span class="tw-text-sm tw-text-gray-500">
<%= tafsir.language.name %>
</span>
</div>
<div class="tw-text-gray-700 prose tw-max-w-none">
<%= raw(tafsir.text) %>
</div>
</div>
<% end %>
</div>
</div>
<% end %>

<!-- Audio -->
<% if @audio_files.any? %>
<div class="tw-bg-white tw-rounded-lg tw-shadow-md tw-p-8 tw-mb-8">
<h2 class="tw-text-xl tw-font-bold tw-text-gray-900 tw-mb-6">Audio Recitations</h2>

<div class="tw-space-y-4">
<% @audio_files.each do |audio| %>
<div class="tw-border tw-border-gray-200 tw-rounded-lg tw-p-4">
<div class="tw-flex tw-items-center tw-justify-between tw-mb-2">
<h3 class="tw-font-medium tw-text-gray-900">
<%= audio.recitation.reciter_name %>
</h3>
<span class="tw-text-sm tw-text-gray-500">
<%= audio.recitation.style %>
</span>
</div>
<% if audio.audio_url.present? %>
<audio controls class="tw-w-full">
<source src="<%= audio.audio_url %>" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<% end %>
</div>
<% end %>
</div>
</div>
<% end %>

<!-- Grammar & Morphology -->
<% if @morphology_words.any? %>
<div class="tw-bg-white tw-rounded-lg tw-shadow-md tw-p-8">
<h2 class="tw-text-xl tw-font-bold tw-text-gray-900 tw-mb-6">Grammar & Morphology</h2>

<div class="tw-space-y-4">
<% @morphology_words.each do |morph_word| %>
<div class="tw-border tw-border-gray-200 tw-rounded-lg tw-p-4">
<div class="tw-flex tw-items-center tw-gap-4 tw-mb-2">
<div class="tw-text-lg tw-font-medium" dir="rtl">
<%= morph_word.text %>
</div>
<div class="tw-text-sm tw-text-gray-600">
Position <%= morph_word.position %>
</div>
</div>

<% if morph_word.description.present? %>
<div class="tw-text-gray-700 tw-mb-2">
<%= morph_word.description %>
</div>
<% end %>

<% if morph_word.grammar_concepts.any? %>
<div class="tw-flex tw-flex-wrap tw-gap-2">
<% morph_word.grammar_concepts.each do |concept| %>
<span class="tw-bg-purple-100 tw-text-purple-700 tw-px-2 tw-py-1 tw-rounded tw-text-xs">
<%= concept.description %>
</span>
<% end %>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
Loading