postnhost 0.0.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/{LICENSE.txt → LICENSE} +6 -6
- data/README.md +343 -15
- data/Rakefile +66 -6
- data/app/assets/builds/postnhost/application.css +2 -0
- data/app/assets/builds/postnhost/application.js +50190 -0
- data/app/assets/config/postnhost_manifest.js +2 -0
- data/app/assets/images/postnhost/demo.webp +0 -0
- data/app/assets/images/postnhost/icons/alert-circle.svg +3 -0
- data/app/assets/images/postnhost/icons/arrow-left-long.svg +3 -0
- data/app/assets/images/postnhost/icons/arrow-left.svg +3 -0
- data/app/assets/images/postnhost/icons/arrow-right-end-on-rectangle.svg +3 -0
- data/app/assets/images/postnhost/icons/arrow-right-long.svg +3 -0
- data/app/assets/images/postnhost/icons/arrow-right.svg +3 -0
- data/app/assets/images/postnhost/icons/bars.svg +3 -0
- data/app/assets/images/postnhost/icons/bluesky.svg +3 -0
- data/app/assets/images/postnhost/icons/check-circle.svg +3 -0
- data/app/assets/images/postnhost/icons/chevron-down-small.svg +3 -0
- data/app/assets/images/postnhost/icons/chevron-down.svg +3 -0
- data/app/assets/images/postnhost/icons/chevron-left.svg +3 -0
- data/app/assets/images/postnhost/icons/chevron-right.svg +3 -0
- data/app/assets/images/postnhost/icons/clock.svg +3 -0
- data/app/assets/images/postnhost/icons/close.svg +3 -0
- data/app/assets/images/postnhost/icons/code-bracket.svg +3 -0
- data/app/assets/images/postnhost/icons/document-text.svg +3 -0
- data/app/assets/images/postnhost/icons/drag-handle.svg +8 -0
- data/app/assets/images/postnhost/icons/edit.svg +3 -0
- data/app/assets/images/postnhost/icons/external-link.svg +3 -0
- data/app/assets/images/postnhost/icons/eye.svg +4 -0
- data/app/assets/images/postnhost/icons/facebook.svg +3 -0
- data/app/assets/images/postnhost/icons/folder.svg +3 -0
- data/app/assets/images/postnhost/icons/image.svg +3 -0
- data/app/assets/images/postnhost/icons/info-circle.svg +3 -0
- data/app/assets/images/postnhost/icons/instagram.svg +3 -0
- data/app/assets/images/postnhost/icons/language.svg +3 -0
- data/app/assets/images/postnhost/icons/layers.svg +3 -0
- data/app/assets/images/postnhost/icons/lightning.svg +3 -0
- data/app/assets/images/postnhost/icons/linkedin.svg +3 -0
- data/app/assets/images/postnhost/icons/logout.svg +3 -0
- data/app/assets/images/postnhost/icons/magnifying-glass.svg +3 -0
- data/app/assets/images/postnhost/icons/mastodon.svg +3 -0
- data/app/assets/images/postnhost/icons/menu.svg +3 -0
- data/app/assets/images/postnhost/icons/plus.svg +3 -0
- data/app/assets/images/postnhost/icons/schedule.svg +3 -0
- data/app/assets/images/postnhost/icons/settings.svg +4 -0
- data/app/assets/images/postnhost/icons/sparkles.svg +3 -0
- data/app/assets/images/postnhost/icons/spinner.svg +4 -0
- data/app/assets/images/postnhost/icons/threads.svg +3 -0
- data/app/assets/images/postnhost/icons/tiktok.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/align-center.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/align-left.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/align-right.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/apply-link.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/blockquote.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/bold.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/bullet-list.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/code-block.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/code.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/heading-2.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/heading-3.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/image-add.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/italic.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/link.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/ordered-list.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/redo.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/remove-link.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/strike.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/table.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/underline.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/undo.svg +3 -0
- data/app/assets/images/postnhost/icons/tiptap/youtube.svg +4 -0
- data/app/assets/images/postnhost/icons/translate.svg +3 -0
- data/app/assets/images/postnhost/icons/trash.svg +3 -0
- data/app/assets/images/postnhost/icons/user.svg +4 -0
- data/app/assets/images/postnhost/icons/users.svg +3 -0
- data/app/assets/images/postnhost/icons/warning.svg +3 -0
- data/app/assets/images/postnhost/icons/x.svg +3 -0
- data/app/assets/images/postnhost/icons/youtube.svg +3 -0
- data/app/assets/images/postnhost/logo.webp +0 -0
- data/app/assets/images/postnhost/og-image.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/08-how-to-control-suggested-articles-and-top-picks-01-discovery-controls.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/09-all-about-authors-in-postnhost-01-author-profile.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/09-all-about-authors-in-postnhost-02-multiple-authors.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/11-how-to-schedule-an-article-for-publication-01-timezone.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/11-how-to-schedule-an-article-for-publication-02-scheduled-article.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/12-how-article-version-history-and-restores-work-01-version-history.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/13-how-to-add-and-manage-languages-01-language-management.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/14-how-to-translate-articles-pages-and-categories-01-translation-options.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/14-how-to-translate-articles-pages-and-categories-02-ai-language-selection.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/16-how-to-add-navigation-links-01-navigation-builder.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/16-how-to-add-navigation-links-02-external-link-settings.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/17-how-to-add-a-logo-and-default-og-image-01-assets-settings.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/19-how-to-customize-public-text-for-each-language-01-i18n-overrides.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/20-how-to-configure-structured-data-and-sitemap-seo-01-site-schema.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/20-how-to-configure-structured-data-and-sitemap-seo-02-author-schema-defaults.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/20-how-to-configure-structured-data-and-sitemap-seo-03-author-schema-advanced-fields.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/08-suggested-articles-and-top-picks.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/09-authors.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/11-scheduling.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/12-version-history.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/13-languages.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/14-translations.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/16-navigation-links.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/17-logo-and-default-og-image.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/19-public-text-for-each-language.webp +0 -0
- data/app/assets/images/postnhost/sample-docs/covers/20-structured-data-and-sitemap-seo.webp +0 -0
- data/app/assets/stylesheets/application.tailwind.css +347 -0
- data/app/assets/stylesheets/postnhost/application.css +15 -0
- data/app/assets/xsl/sitemap.xsl +64 -0
- data/app/controllers/concerns/postnhost/authentication.rb +59 -0
- data/app/controllers/concerns/postnhost/canonical_first_page_redirect.rb +14 -0
- data/app/controllers/concerns/postnhost/language_switcher.rb +42 -0
- data/app/controllers/concerns/postnhost/onboarding/access_control.rb +57 -0
- data/app/controllers/concerns/postnhost/onboarding/step_assignment.rb +55 -0
- data/app/controllers/concerns/postnhost/public_footer_data.rb +103 -0
- data/app/controllers/concerns/postnhost/public_http_caching.rb +35 -0
- data/app/controllers/concerns/postnhost/public_page_size.rb +17 -0
- data/app/controllers/concerns/postnhost/public_template_resolvable.rb +44 -0
- data/app/controllers/concerns/postnhost/settings/i18n_manageable.rb +61 -0
- data/app/controllers/concerns/postnhost/settings/navigation_manageable.rb +118 -0
- data/app/controllers/concerns/postnhost/settings/schema_manageable.rb +140 -0
- data/app/controllers/concerns/postnhost/users/schema_manageable.rb +119 -0
- data/app/controllers/postnhost/application_controller.rb +37 -0
- data/app/controllers/postnhost/article_variants_controller.rb +138 -0
- data/app/controllers/postnhost/articles/cover_images_controller.rb +35 -0
- data/app/controllers/postnhost/articles/images_controller.rb +28 -0
- data/app/controllers/postnhost/articles/translations_controller.rb +26 -0
- data/app/controllers/postnhost/articles_controller.rb +130 -0
- data/app/controllers/postnhost/categories/translations_controller.rb +24 -0
- data/app/controllers/postnhost/categories_controller.rb +59 -0
- data/app/controllers/postnhost/category_variants_controller.rb +69 -0
- data/app/controllers/postnhost/languages_controller.rb +66 -0
- data/app/controllers/postnhost/onboarding_controller.rb +70 -0
- data/app/controllers/postnhost/page_variants_controller.rb +136 -0
- data/app/controllers/postnhost/pages/images_controller.rb +28 -0
- data/app/controllers/postnhost/pages/translations_controller.rb +26 -0
- data/app/controllers/postnhost/pages_controller.rb +95 -0
- data/app/controllers/postnhost/public/articles_controller.rb +135 -0
- data/app/controllers/postnhost/public/authors_controller.rb +57 -0
- data/app/controllers/postnhost/public/categories_controller.rb +61 -0
- data/app/controllers/postnhost/public/static_pages_controller.rb +77 -0
- data/app/controllers/postnhost/public_controller.rb +32 -0
- data/app/controllers/postnhost/sessions_controller.rb +37 -0
- data/app/controllers/postnhost/settings/site_scripts_controller.rb +61 -0
- data/app/controllers/postnhost/settings_controller.rb +63 -0
- data/app/controllers/postnhost/sitemap_controller.rb +17 -0
- data/app/controllers/postnhost/templates_controller.rb +26 -0
- data/app/controllers/postnhost/users_controller.rb +112 -0
- data/app/helpers/postnhost/application_helper.rb +236 -0
- data/app/helpers/postnhost/article_helper.rb +41 -0
- data/app/helpers/postnhost/category_helper.rb +52 -0
- data/app/helpers/postnhost/common_css_helper.rb +97 -0
- data/app/helpers/postnhost/navigation_helper.rb +148 -0
- data/app/helpers/postnhost/pagy_helper.rb +103 -0
- data/app/helpers/postnhost/public_pages_helper.rb +287 -0
- data/app/helpers/postnhost/schema_helper.rb +102 -0
- data/app/helpers/postnhost/seo_helper.rb +428 -0
- data/app/helpers/postnhost/settings_helper.rb +79 -0
- data/app/javascript/application.js +3 -0
- data/app/javascript/controllers/ai_translation_controller.js +42 -0
- data/app/javascript/controllers/application.js +9 -0
- data/app/javascript/controllers/author_manager_controller.js +96 -0
- data/app/javascript/controllers/auto_save_controller.js +244 -0
- data/app/javascript/controllers/bulk_selection_controller.js +74 -0
- data/app/javascript/controllers/burger_controller.js +20 -0
- data/app/javascript/controllers/category_manager_controller.js +99 -0
- data/app/javascript/controllers/collapsible_sidebar_controller.js +87 -0
- data/app/javascript/controllers/cover_image_upload_controller.js +164 -0
- data/app/javascript/controllers/dropdown_controller.js +38 -0
- data/app/javascript/controllers/editor_mobile_sidebars_controller.js +36 -0
- data/app/javascript/controllers/file_auto_submit_controller.js +23 -0
- data/app/javascript/controllers/flash_message_controller.js +40 -0
- data/app/javascript/controllers/index.js +71 -0
- data/app/javascript/controllers/navigation_builder_controller.js +463 -0
- data/app/javascript/controllers/public_mobile_nav_controller.js +26 -0
- data/app/javascript/controllers/publish_guard_controller.js +47 -0
- data/app/javascript/controllers/reading_progress_controller.js +38 -0
- data/app/javascript/controllers/schedule_manager_controller.js +87 -0
- data/app/javascript/controllers/suggestion_manager_controller.js +99 -0
- data/app/javascript/controllers/template_preview_controller.js +34 -0
- data/app/javascript/controllers/tiptap_editor_controller.js +812 -0
- data/app/javascript/controllers/title_field_controller.js +17 -0
- data/app/javascript/helpers/auto_save_state.js +47 -0
- data/app/javascript/helpers/code_highlighting.js +48 -0
- data/app/javascript/helpers/dom_helpers.js +109 -0
- data/app/javascript/helpers/style_helpers.js +168 -0
- data/app/jobs/postnhost/application_job.rb +9 -0
- data/app/jobs/postnhost/scheduled_article_job.rb +13 -0
- data/app/jobs/postnhost/translation/article_variant_job.rb +17 -0
- data/app/jobs/postnhost/translation/category_variant_job.rb +17 -0
- data/app/jobs/postnhost/translation/page_variant_job.rb +17 -0
- data/app/models/concerns/postnhost/article/image_uploadable.rb +11 -0
- data/app/models/concerns/postnhost/excerpt_optimizable.rb +57 -0
- data/app/models/concerns/postnhost/inline_image_uploadable.rb +40 -0
- data/app/models/concerns/postnhost/page/image_uploadable.rb +11 -0
- data/app/models/concerns/postnhost/primary_language_guard.rb +18 -0
- data/app/models/concerns/postnhost/public_revision_touch.rb +15 -0
- data/app/models/concerns/postnhost/schema_localizable.rb +28 -0
- data/app/models/postnhost/application_record.rb +5 -0
- data/app/models/postnhost/article.rb +142 -0
- data/app/models/postnhost/article_author.rb +20 -0
- data/app/models/postnhost/article_category.rb +8 -0
- data/app/models/postnhost/article_suggestion.rb +19 -0
- data/app/models/postnhost/article_variant.rb +28 -0
- data/app/models/postnhost/category.rb +34 -0
- data/app/models/postnhost/category_variant.rb +24 -0
- data/app/models/postnhost/language.rb +38 -0
- data/app/models/postnhost/navigation.rb +76 -0
- data/app/models/postnhost/navigation_item.rb +100 -0
- data/app/models/postnhost/page.rb +63 -0
- data/app/models/postnhost/page_variant.rb +26 -0
- data/app/models/postnhost/public_site_revision.rb +24 -0
- data/app/models/postnhost/published_cover_image.rb +28 -0
- data/app/models/postnhost/setting.rb +116 -0
- data/app/models/postnhost/site_script.rb +11 -0
- data/app/models/postnhost/snapshot/article.rb +142 -0
- data/app/models/postnhost/snapshot/article_author.rb +11 -0
- data/app/models/postnhost/snapshot/article_category.rb +10 -0
- data/app/models/postnhost/snapshot/article_suggestion.rb +11 -0
- data/app/models/postnhost/snapshot/article_variant.rb +60 -0
- data/app/models/postnhost/snapshot/page.rb +33 -0
- data/app/models/postnhost/snapshot/page_variant.rb +41 -0
- data/app/models/postnhost/template.rb +20 -0
- data/app/models/postnhost/user.rb +63 -0
- data/app/models/postnhost/version.rb +7 -0
- data/app/services/postnhost/base_service.rb +17 -0
- data/app/services/postnhost/constraints/public_locale_constraint.rb +9 -0
- data/app/services/postnhost/constraints/public_route_constraint.rb +19 -0
- data/app/services/postnhost/onboarding/step_processor.rb +27 -0
- data/app/services/postnhost/onboarding/steps/base.rb +52 -0
- data/app/services/postnhost/onboarding/steps/choose_languages.rb +66 -0
- data/app/services/postnhost/onboarding/steps/complete_post_install_checklist.rb +12 -0
- data/app/services/postnhost/onboarding/steps/create_admin_account.rb +28 -0
- data/app/services/postnhost/onboarding/steps/finish_setup.rb +27 -0
- data/app/services/postnhost/onboarding/steps/set_site_metadata.rb +70 -0
- data/app/services/postnhost/public_navigation_targets.rb +67 -0
- data/app/services/postnhost/public_request_context.rb +101 -0
- data/app/services/postnhost/publishing/article_variants/publish.rb +26 -0
- data/app/services/postnhost/publishing/article_variants/publish_many.rb +23 -0
- data/app/services/postnhost/publishing/article_variants/snapshot_writer.rb +44 -0
- data/app/services/postnhost/publishing/article_variants/unpublish.rb +27 -0
- data/app/services/postnhost/publishing/article_variants/unpublish_many.rb +23 -0
- data/app/services/postnhost/publishing/articles/publish.rb +25 -0
- data/app/services/postnhost/publishing/articles/publish_scheduled.rb +42 -0
- data/app/services/postnhost/publishing/articles/snapshot_writer.rb +84 -0
- data/app/services/postnhost/publishing/articles/unpublish.rb +26 -0
- data/app/services/postnhost/publishing/bulk_transition.rb +63 -0
- data/app/services/postnhost/publishing/error.rb +12 -0
- data/app/services/postnhost/publishing/page_variants/publish.rb +26 -0
- data/app/services/postnhost/publishing/page_variants/publish_many.rb +23 -0
- data/app/services/postnhost/publishing/page_variants/snapshot_writer.rb +41 -0
- data/app/services/postnhost/publishing/page_variants/unpublish.rb +27 -0
- data/app/services/postnhost/publishing/page_variants/unpublish_many.rb +23 -0
- data/app/services/postnhost/publishing/pages/publish.rb +25 -0
- data/app/services/postnhost/publishing/pages/snapshot_writer.rb +38 -0
- data/app/services/postnhost/publishing/pages/unpublish.rb +26 -0
- data/app/services/postnhost/publishing/revision.rb +37 -0
- data/app/services/postnhost/publishing/route_validator.rb +41 -0
- data/app/services/postnhost/publishing/versions/restore_draft.rb +64 -0
- data/app/services/postnhost/service_result.rb +7 -0
- data/app/services/postnhost/sitemap_builder.rb +395 -0
- data/app/services/postnhost/translation/article_variant_translator.rb +102 -0
- data/app/services/postnhost/translation/category_variant_translator.rb +92 -0
- data/app/services/postnhost/translation/content_translator.rb +119 -0
- data/app/services/postnhost/translation/openai_llm_client.rb +30 -0
- data/app/services/postnhost/translation/page_variant_translator.rb +55 -0
- data/app/uploaders/base_uploader.rb +26 -0
- data/app/uploaders/cover_image_uploader.rb +31 -0
- data/app/uploaders/postnhost/avatar_uploader.rb +17 -0
- data/app/uploaders/postnhost/inline_article_image_uploader.rb +38 -0
- data/app/uploaders/postnhost/inline_page_image_uploader.rb +38 -0
- data/app/uploaders/postnhost/setting_asset_uploader.rb +18 -0
- data/app/views/layouts/postnhost/_favicon.html.erb +6 -0
- data/app/views/layouts/postnhost/_footer.html.erb +67 -0
- data/app/views/layouts/postnhost/_header.html.erb +89 -0
- data/app/views/layouts/postnhost/_sidebar.html.erb +72 -0
- data/app/views/layouts/postnhost/application.html.erb +23 -0
- data/app/views/layouts/postnhost/articles.html.erb +34 -0
- data/app/views/layouts/postnhost/product.html.erb +36 -0
- data/app/views/layouts/postnhost/public/templates/default.html.erb +110 -0
- data/app/views/layouts/postnhost/public/templates/swiss-editorial.html.erb +213 -0
- data/app/views/layouts/postnhost/public/templates/workspace-journal.html.erb +231 -0
- data/app/views/layouts/postnhost/public_header/_dashboard_sign_in.html.erb +14 -0
- data/app/views/layouts/postnhost/public_header/_language_switcher.html.erb +43 -0
- data/app/views/layouts/postnhost/public_header/_logo.html.erb +9 -0
- data/app/views/postnhost/article_variants/_variants_list.html.erb +82 -0
- data/app/views/postnhost/article_variants/edit.html.erb +48 -0
- data/app/views/postnhost/article_variants/index.html.erb +128 -0
- data/app/views/postnhost/article_variants/publish.turbo_stream.erb +3 -0
- data/app/views/postnhost/article_variants/unpublish.turbo_stream.erb +3 -0
- data/app/views/postnhost/article_variants/update.turbo_stream.erb +3 -0
- data/app/views/postnhost/articles/_author_manager.html.erb +38 -0
- data/app/views/postnhost/articles/_category_manager.html.erb +42 -0
- data/app/views/postnhost/articles/_cover_image_upload.html.erb +82 -0
- data/app/views/postnhost/articles/_suggestion_manager.html.erb +43 -0
- data/app/views/postnhost/articles/_version_snapshot.html.erb +10 -0
- data/app/views/postnhost/articles/edit.html.erb +51 -0
- data/app/views/postnhost/articles/index.html.erb +132 -0
- data/app/views/postnhost/articles/publish.turbo_stream.erb +3 -0
- data/app/views/postnhost/articles/unpublish.turbo_stream.erb +3 -0
- data/app/views/postnhost/articles/update.turbo_stream.erb +3 -0
- data/app/views/postnhost/articles/version_preview.html.erb +17 -0
- data/app/views/postnhost/articles/versions.html.erb +68 -0
- data/app/views/postnhost/categories/edit.html.erb +77 -0
- data/app/views/postnhost/categories/index.html.erb +80 -0
- data/app/views/postnhost/categories/new.html.erb +50 -0
- data/app/views/postnhost/categories/show.html.erb +99 -0
- data/app/views/postnhost/category_variants/_category_variants_list.html.erb +67 -0
- data/app/views/postnhost/category_variants/_form.html.erb +29 -0
- data/app/views/postnhost/category_variants/edit.html.erb +21 -0
- data/app/views/postnhost/category_variants/index.html.erb +82 -0
- data/app/views/postnhost/category_variants/new.html.erb +21 -0
- data/app/views/postnhost/languages/edit.html.erb +45 -0
- data/app/views/postnhost/languages/index.html.erb +86 -0
- data/app/views/postnhost/languages/new.html.erb +45 -0
- data/app/views/postnhost/languages/show.html.erb +156 -0
- data/app/views/postnhost/onboarding/_post_install_checklist.html.erb +40 -0
- data/app/views/postnhost/onboarding/_step_1.html.erb +42 -0
- data/app/views/postnhost/onboarding/_step_2.html.erb +38 -0
- data/app/views/postnhost/onboarding/_step_3.html.erb +62 -0
- data/app/views/postnhost/onboarding/_step_4.html.erb +26 -0
- data/app/views/postnhost/onboarding/show.html.erb +51 -0
- data/app/views/postnhost/page_variants/_variants_list.html.erb +82 -0
- data/app/views/postnhost/page_variants/edit.html.erb +50 -0
- data/app/views/postnhost/page_variants/index.html.erb +128 -0
- data/app/views/postnhost/page_variants/publish.turbo_stream.erb +3 -0
- data/app/views/postnhost/page_variants/unpublish.turbo_stream.erb +3 -0
- data/app/views/postnhost/page_variants/update.turbo_stream.erb +3 -0
- data/app/views/postnhost/pages/edit.html.erb +50 -0
- data/app/views/postnhost/pages/index.html.erb +110 -0
- data/app/views/postnhost/pages/publish.turbo_stream.erb +3 -0
- data/app/views/postnhost/pages/unpublish.turbo_stream.erb +3 -0
- data/app/views/postnhost/public/articles/content_for/_index.html.erb +30 -0
- data/app/views/postnhost/public/articles/content_for/_preview.html.erb +9 -0
- data/app/views/postnhost/public/articles/content_for/_show.html.erb +24 -0
- data/app/views/postnhost/public/authors/content_for/_show.html.erb +24 -0
- data/app/views/postnhost/public/categories/content_for/_index.html.erb +29 -0
- data/app/views/postnhost/public/static_pages/content_for/_show.html.erb +19 -0
- data/app/views/postnhost/public/templates/default/articles/_article_card.html.erb +37 -0
- data/app/views/postnhost/public/templates/default/articles/_search_form.html.erb +12 -0
- data/app/views/postnhost/public/templates/default/articles/_suggestions.html.erb +44 -0
- data/app/views/postnhost/public/templates/default/articles/_top_picks.html.erb +42 -0
- data/app/views/postnhost/public/templates/default/articles/index.html.erb +53 -0
- data/app/views/postnhost/public/templates/default/articles/preview.html.erb +102 -0
- data/app/views/postnhost/public/templates/default/articles/show.html.erb +111 -0
- data/app/views/postnhost/public/templates/default/authors/_article_card.html.erb +28 -0
- data/app/views/postnhost/public/templates/default/authors/_profile_block.html.erb +29 -0
- data/app/views/postnhost/public/templates/default/authors/show.html.erb +36 -0
- data/app/views/postnhost/public/templates/default/categories/_article_card.html.erb +34 -0
- data/app/views/postnhost/public/templates/default/categories/index.html.erb +48 -0
- data/app/views/postnhost/public/templates/default/shared/_article_authors.html.erb +24 -0
- data/app/views/postnhost/public/templates/default/shared/_author_avatar.html.erb +9 -0
- data/app/views/postnhost/public/templates/default/shared/_hero_cover_image.html.erb +11 -0
- data/app/views/postnhost/public/templates/default/shared/_pagination.html.erb +35 -0
- data/app/views/postnhost/public/templates/default/shared/_thumbnail_cover_image.html.erb +9 -0
- data/app/views/postnhost/public/templates/default/static_pages/show.html.erb +22 -0
- data/app/views/postnhost/public/templates/swiss-editorial/articles/_article_card.html.erb +28 -0
- data/app/views/postnhost/public/templates/swiss-editorial/articles/_search_form.html.erb +19 -0
- data/app/views/postnhost/public/templates/swiss-editorial/articles/_suggestions.html.erb +42 -0
- data/app/views/postnhost/public/templates/swiss-editorial/articles/_top_picks.html.erb +38 -0
- data/app/views/postnhost/public/templates/swiss-editorial/articles/index.html.erb +133 -0
- data/app/views/postnhost/public/templates/swiss-editorial/articles/preview.html.erb +42 -0
- data/app/views/postnhost/public/templates/swiss-editorial/articles/show.html.erb +100 -0
- data/app/views/postnhost/public/templates/swiss-editorial/authors/_article_card.html.erb +27 -0
- data/app/views/postnhost/public/templates/swiss-editorial/authors/_profile_block.html.erb +32 -0
- data/app/views/postnhost/public/templates/swiss-editorial/authors/show.html.erb +31 -0
- data/app/views/postnhost/public/templates/swiss-editorial/categories/_article_card.html.erb +28 -0
- data/app/views/postnhost/public/templates/swiss-editorial/categories/index.html.erb +88 -0
- data/app/views/postnhost/public/templates/swiss-editorial/shared/_article_authors.html.erb +26 -0
- data/app/views/postnhost/public/templates/swiss-editorial/shared/_author_avatar.html.erb +9 -0
- data/app/views/postnhost/public/templates/swiss-editorial/shared/_hero_cover_image.html.erb +11 -0
- data/app/views/postnhost/public/templates/swiss-editorial/shared/_pagination.html.erb +35 -0
- data/app/views/postnhost/public/templates/swiss-editorial/shared/_thumbnail_cover_image.html.erb +9 -0
- data/app/views/postnhost/public/templates/swiss-editorial/static_pages/show.html.erb +17 -0
- data/app/views/postnhost/public/templates/workspace-journal/articles/_article_card.html.erb +44 -0
- data/app/views/postnhost/public/templates/workspace-journal/articles/_search_form.html.erb +19 -0
- data/app/views/postnhost/public/templates/workspace-journal/articles/_suggestions.html.erb +49 -0
- data/app/views/postnhost/public/templates/workspace-journal/articles/_top_picks.html.erb +34 -0
- data/app/views/postnhost/public/templates/workspace-journal/articles/index.html.erb +69 -0
- data/app/views/postnhost/public/templates/workspace-journal/articles/preview.html.erb +113 -0
- data/app/views/postnhost/public/templates/workspace-journal/articles/show.html.erb +120 -0
- data/app/views/postnhost/public/templates/workspace-journal/authors/_article_card.html.erb +1 -0
- data/app/views/postnhost/public/templates/workspace-journal/authors/_profile_block.html.erb +32 -0
- data/app/views/postnhost/public/templates/workspace-journal/authors/show.html.erb +33 -0
- data/app/views/postnhost/public/templates/workspace-journal/categories/_article_card.html.erb +1 -0
- data/app/views/postnhost/public/templates/workspace-journal/categories/index.html.erb +58 -0
- data/app/views/postnhost/public/templates/workspace-journal/shared/_article_authors.html.erb +27 -0
- data/app/views/postnhost/public/templates/workspace-journal/shared/_article_card.html.erb +44 -0
- data/app/views/postnhost/public/templates/workspace-journal/shared/_author_avatar.html.erb +9 -0
- data/app/views/postnhost/public/templates/workspace-journal/shared/_category_navigation.html.erb +10 -0
- data/app/views/postnhost/public/templates/workspace-journal/shared/_hero_cover_image.html.erb +11 -0
- data/app/views/postnhost/public/templates/workspace-journal/shared/_pagination.html.erb +35 -0
- data/app/views/postnhost/public/templates/workspace-journal/shared/_thumbnail_cover_image.html.erb +9 -0
- data/app/views/postnhost/public/templates/workspace-journal/static_pages/show.html.erb +17 -0
- data/app/views/postnhost/sessions/new.html.erb +59 -0
- data/app/views/postnhost/settings/edit.html.erb +68 -0
- data/app/views/postnhost/settings/sections/_assets.html.erb +40 -0
- data/app/views/postnhost/settings/sections/_feature_flags.html.erb +43 -0
- data/app/views/postnhost/settings/sections/_i18n.html.erb +57 -0
- data/app/views/postnhost/settings/sections/_navigation.html.erb +98 -0
- data/app/views/postnhost/settings/sections/_schema.html.erb +253 -0
- data/app/views/postnhost/settings/sections/_scripts.html.erb +79 -0
- data/app/views/postnhost/settings/sections/_site.html.erb +41 -0
- data/app/views/postnhost/settings/sections/_timezone.html.erb +19 -0
- data/app/views/postnhost/shared/_ai_translation_modal.html.erb +85 -0
- data/app/views/postnhost/shared/_flash_messages.html.erb +27 -0
- data/app/views/postnhost/shared/_form_errors.html.erb +22 -0
- data/app/views/postnhost/shared/_seo_meta_tags.html.erb +70 -0
- data/app/views/postnhost/shared/_structured_data.html.erb +5 -0
- data/app/views/postnhost/shared/articles/_action_buttons.html.erb +87 -0
- data/app/views/postnhost/shared/articles/_cover_image_preview.html.erb +30 -0
- data/app/views/postnhost/shared/articles/_editor_column.html.erb +15 -0
- data/app/views/postnhost/shared/articles/_editor_column_preview.html.erb +33 -0
- data/app/views/postnhost/shared/articles/_error_messages.html.erb +23 -0
- data/app/views/postnhost/shared/articles/_meta_sidebar.html.erb +322 -0
- data/app/views/postnhost/shared/articles/_meta_sidebar_preview.html.erb +29 -0
- data/app/views/postnhost/shared/articles/_post_actions.html.erb +105 -0
- data/app/views/postnhost/shared/articles/_schedule_actions.html.erb +51 -0
- data/app/views/postnhost/shared/articles/_tiptap_editor.html.erb +225 -0
- data/app/views/postnhost/shared/articles/_title_field.html.erb +9 -0
- data/app/views/postnhost/shared/articles/_version_action_buttons.html.erb +35 -0
- data/app/views/postnhost/shared/elements/_button.html.erb +20 -0
- data/app/views/postnhost/shared/elements/_button_link.html.erb +24 -0
- data/app/views/postnhost/shared/elements/_empty_state.html.erb +22 -0
- data/app/views/postnhost/shared/elements/_error_messages.html.erb +28 -0
- data/app/views/postnhost/shared/elements/_form_card.html.erb +10 -0
- data/app/views/postnhost/shared/elements/_form_page_header.html.erb +21 -0
- data/app/views/postnhost/shared/elements/_icon_button.html.erb +17 -0
- data/app/views/postnhost/shared/elements/_page_header.html.erb +40 -0
- data/app/views/postnhost/shared/elements/_table_container.html.erb +23 -0
- data/app/views/postnhost/shared/pages/_action_buttons.html.erb +84 -0
- data/app/views/postnhost/shared/pages/_meta_sidebar.html.erb +132 -0
- data/app/views/postnhost/shared/pages/_post_actions.html.erb +69 -0
- data/app/views/postnhost/templates/edit.html.erb +83 -0
- data/app/views/postnhost/users/_avatar.html.erb +9 -0
- data/app/views/postnhost/users/_form.html.erb +160 -0
- data/app/views/postnhost/users/edit.html.erb +26 -0
- data/app/views/postnhost/users/index.html.erb +91 -0
- data/app/views/postnhost/users/new.html.erb +9 -0
- data/app/views/postnhost/users/schema_edit.html.erb +175 -0
- data/config/locales/de.yml +55 -0
- data/config/locales/en.yml +88 -0
- data/config/locales/es.yml +58 -0
- data/config/locales/fr.yml +55 -0
- data/config/locales/ja.yml +55 -0
- data/config/locales/ko.yml +55 -0
- data/config/locales/pl.yml +55 -0
- data/config/locales/pt.yml +55 -0
- data/config/locales/ru.yml +55 -0
- data/config/routes.rb +112 -0
- data/db/migrate/20250822213820_create_users.rb +29 -0
- data/db/migrate/20250822214046_create_categories.rb +15 -0
- data/db/migrate/20250822214106_create_languages.rb +16 -0
- data/db/migrate/20250822214148_create_articles.rb +34 -0
- data/db/migrate/20250822214217_create_article_variants.rb +24 -0
- data/db/migrate/20250929091137_create_article_categories.rb +12 -0
- data/db/migrate/20251013204200_create_versions.rb +40 -0
- data/db/migrate/20260106074532_create_article_suggestions.rb +13 -0
- data/db/migrate/20260108110506_create_category_variants.rb +15 -0
- data/db/migrate/20260308130000_create_settings.rb +23 -0
- data/db/migrate/20260323113000_create_pages.rb +19 -0
- data/db/migrate/20260414100000_create_article_authors.rb +14 -0
- data/db/migrate/20260512100000_create_templates.rb +9 -0
- data/db/migrate/20260520110001_create_navigations.rb +9 -0
- data/db/migrate/20260520110002_create_navigation_items.rb +22 -0
- data/db/migrate/20260528000002_create_page_variants.rb +20 -0
- data/db/migrate/20260709090000_create_snapshots.rb +154 -0
- data/db/migrate/20260726130000_create_site_scripts.rb +11 -0
- data/lib/generators/postnhost/install/install_generator.rb +55 -0
- data/lib/generators/postnhost/install/templates/carrierwave.rb +17 -0
- data/lib/generators/postnhost/install/templates/postnhost.rb +36 -0
- data/lib/generators/postnhost/locale/locale_generator.rb +36 -0
- data/lib/generators/postnhost/static_pages/static_pages_generator.rb +47 -0
- data/lib/generators/postnhost/tailwindcss/install_generator.rb +100 -0
- data/lib/generators/postnhost/tailwindcss/templates/host.tailwind.css +4 -0
- data/lib/generators/postnhost/user/user_generator.rb +36 -0
- data/lib/generators/postnhost/views/views_generator.rb +140 -0
- data/lib/postnhost/configuration.rb +64 -0
- data/lib/postnhost/css_build.rb +68 -0
- data/lib/postnhost/css_scope.rb +77 -0
- data/lib/postnhost/engine.rb +57 -0
- data/lib/postnhost/sample_data.rb +865 -0
- data/lib/postnhost/settings/i18n_overrides.rb +137 -0
- data/lib/postnhost/settings/i18n_patch.rb +18 -0
- data/lib/postnhost/tailwind_compiler.rb +75 -0
- data/lib/postnhost/tailwind_input.rb +32 -0
- data/lib/postnhost/version.rb +1 -3
- data/lib/postnhost.rb +26 -3
- data/lib/tasks/postnhost_snapshots.rake +77 -0
- data/lib/tasks/postnhost_tasks.rake +71 -0
- metadata +679 -21
- data/.github/workflows/main.yml +0 -27
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/.rubocop.yml +0 -8
- data/Gemfile +0 -13
- data/bin/console +0 -11
- data/bin/setup +0 -8
- data/postnhost.gemspec +0 -31
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<% content_for :title, "Translations - #{@category.name}" %>
|
|
2
|
+
|
|
3
|
+
<%= turbo_stream_from "category_variants_#{@category.id}" %>
|
|
4
|
+
<div class="space-y-8" data-controller="ai-translation dialog" data-action="click->dialog#backdropClose">
|
|
5
|
+
<%= render 'postnhost/shared/elements/page_header',
|
|
6
|
+
title: 'Category Translations',
|
|
7
|
+
description: "Manage translations for \"#{@category.name}\"",
|
|
8
|
+
stats: [
|
|
9
|
+
{ text: "#{@variants.count} translations", class: '' },
|
|
10
|
+
{ text: "#{@available_languages.count} available languages", class: '' }
|
|
11
|
+
] do %>
|
|
12
|
+
<%= render 'postnhost/shared/elements/button_link',
|
|
13
|
+
text: 'Back to Category',
|
|
14
|
+
url: category_path(@category),
|
|
15
|
+
variant: :secondary,
|
|
16
|
+
icon: 'chevron-left',
|
|
17
|
+
extra_class: 'w-full md:w-auto' %>
|
|
18
|
+
|
|
19
|
+
<% if @available_languages.any? %>
|
|
20
|
+
<button
|
|
21
|
+
data-action="dialog#open"
|
|
22
|
+
class="<%= button_classes %> w-full md:w-auto">
|
|
23
|
+
<%= icon("sparkles", css_class: "w-4 h-4 mr-2") %>
|
|
24
|
+
Translate with AI
|
|
25
|
+
</button>
|
|
26
|
+
|
|
27
|
+
<div class="relative w-full md:w-auto" data-controller="dropdown">
|
|
28
|
+
<button
|
|
29
|
+
data-action="click->dropdown#toggle"
|
|
30
|
+
class="<%= button_classes %> w-full md:w-auto">
|
|
31
|
+
<%= icon("language", css_class: "w-4 h-4 mr-2") %>
|
|
32
|
+
Manual Translation
|
|
33
|
+
<%= icon("chevron-down", css_class: "w-4 h-4 ml-2") %>
|
|
34
|
+
</button>
|
|
35
|
+
|
|
36
|
+
<div data-dropdown-target="menu" class="absolute right-0 mt-2 w-48 bg-white rounded-lg shadow-lg border border-gray-200 overflow-hidden z-20 hidden">
|
|
37
|
+
<div class="py-1">
|
|
38
|
+
<% @available_languages.each do |language| %>
|
|
39
|
+
<%= link_to new_category_variant_path(@category, language_id: language.id), data: { turbo_prefetch: false }, class: "flex items-center px-4 py-3 text-sm text-gray-700 hover:bg-gray-50 transition-colors duration-150 cursor-pointer" do %>
|
|
40
|
+
<div class="flex-1">
|
|
41
|
+
<div class="font-medium"><%= language.name %></div>
|
|
42
|
+
<div class="text-xs text-gray-500"><%= language.html_lang %></div>
|
|
43
|
+
</div>
|
|
44
|
+
<% end %>
|
|
45
|
+
<% end %>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
<% else %>
|
|
50
|
+
<span class="<%= button_classes(variant: :secondary, disabled: true) %> w-full md:w-auto">
|
|
51
|
+
All languages translated
|
|
52
|
+
</span>
|
|
53
|
+
<% end %>
|
|
54
|
+
<% end %>
|
|
55
|
+
|
|
56
|
+
<% if @variants.any? %>
|
|
57
|
+
<div class="bg-white rounded-lg border border-gray-200 overflow-hidden">
|
|
58
|
+
<div class="px-6 py-4 border-b border-gray-200 bg-gray-50">
|
|
59
|
+
<div class="flex items-center gap-2 md:gap-4 text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
60
|
+
<div class="flex-1">Translation</div>
|
|
61
|
+
<div class="hidden md:block md:w-32">Language</div>
|
|
62
|
+
<div class="hidden md:block md:w-28">Status</div>
|
|
63
|
+
<div class="w-24 text-right">Actions</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div id="category_variants_list" class="divide-y divide-gray-200">
|
|
68
|
+
<%= render partial: "category_variants_list", locals: { variants: @variants, category: @category } %>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
<% else %>
|
|
72
|
+
<%= render 'postnhost/shared/elements/empty_state',
|
|
73
|
+
icon: 'translate',
|
|
74
|
+
title: 'No translations',
|
|
75
|
+
description: 'Use "Translate with AI" to automatically create translations, or "Manual Translation" to create them manually.' %>
|
|
76
|
+
<% end %>
|
|
77
|
+
|
|
78
|
+
<%= render "postnhost/shared/ai_translation_modal",
|
|
79
|
+
subject_title: @category.name,
|
|
80
|
+
form_url: category_translations_path(@category),
|
|
81
|
+
available_languages: @available_languages %>
|
|
82
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<% content_for :title, "New Translation - #{@category.name}" %>
|
|
2
|
+
|
|
3
|
+
<div class="max-w-2xl">
|
|
4
|
+
<%= render 'postnhost/shared/elements/form_page_header',
|
|
5
|
+
title: 'New Translation',
|
|
6
|
+
description: "Create a #{@category_variant.language&.name || 'new'} translation for \"#{@category.name}\"" %>
|
|
7
|
+
|
|
8
|
+
<%= form_with model: @category_variant, url: category_variants_path(@category), local: true, class: "space-y-6" do |form| %>
|
|
9
|
+
<%= render 'postnhost/shared/elements/error_messages', resource: @category_variant %>
|
|
10
|
+
|
|
11
|
+
<%= render 'postnhost/category_variants/form', form: form, category_variant: @category_variant %>
|
|
12
|
+
|
|
13
|
+
<div class="flex items-center space-x-4">
|
|
14
|
+
<%= form.submit "Create Translation", class: button_classes %>
|
|
15
|
+
<%= render 'postnhost/shared/elements/button_link',
|
|
16
|
+
text: 'Cancel',
|
|
17
|
+
url: category_variants_path(@category),
|
|
18
|
+
variant: :secondary %>
|
|
19
|
+
</div>
|
|
20
|
+
<% end %>
|
|
21
|
+
</div>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<% content_for :title, "Editing #{@language.name}" %>
|
|
2
|
+
|
|
3
|
+
<div class="max-w-2xl">
|
|
4
|
+
<%= render 'postnhost/shared/elements/form_page_header',
|
|
5
|
+
title: 'Edit Language',
|
|
6
|
+
description: 'Update language information' %>
|
|
7
|
+
|
|
8
|
+
<%= form_with model: @language, local: true, class: "space-y-6" do |form| %>
|
|
9
|
+
<%= render 'postnhost/shared/elements/error_messages', resource: @language %>
|
|
10
|
+
|
|
11
|
+
<%= render 'postnhost/shared/elements/form_card' do %>
|
|
12
|
+
<div>
|
|
13
|
+
<%= form.label :name, class: form_label_classes %>
|
|
14
|
+
<%= form.text_field :name,
|
|
15
|
+
class: form_input_classes,
|
|
16
|
+
placeholder: "Enter language name (e.g., English, Spanish)" %>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div>
|
|
20
|
+
<%= form.label :html_lang, "Language Code", class: form_label_classes %>
|
|
21
|
+
<%= form.text_field :html_lang,
|
|
22
|
+
class: form_input_classes,
|
|
23
|
+
placeholder: "Enter HTML language code (e.g., en, es, fr)" %>
|
|
24
|
+
<p class="mt-1 text-sm text-gray-500">ISO 639-1 language code for HTML lang attribute</p>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div>
|
|
28
|
+
<div class="flex items-center">
|
|
29
|
+
<%= form.check_box :default,
|
|
30
|
+
class: "h-4 w-4 text-gray-600 focus:ring-gray-500 border-gray-300 rounded" %>
|
|
31
|
+
<%= form.label :default, "Default Language", class: "ml-2 block text-sm font-medium text-gray-700" %>
|
|
32
|
+
</div>
|
|
33
|
+
<p class="mt-1 text-sm text-gray-500">Set as the default language for new content</p>
|
|
34
|
+
</div>
|
|
35
|
+
<% end %>
|
|
36
|
+
|
|
37
|
+
<div class="flex items-center space-x-4">
|
|
38
|
+
<%= form.submit "Update Language", class: button_classes %>
|
|
39
|
+
<%= render 'postnhost/shared/elements/button_link',
|
|
40
|
+
text: 'Cancel',
|
|
41
|
+
url: language_path(@language),
|
|
42
|
+
variant: :secondary %>
|
|
43
|
+
</div>
|
|
44
|
+
<% end %>
|
|
45
|
+
</div>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<% content_for :title, "Languages" %>
|
|
2
|
+
|
|
3
|
+
<div class="space-y-8">
|
|
4
|
+
<%= render 'postnhost/shared/elements/page_header',
|
|
5
|
+
title: 'Languages',
|
|
6
|
+
description: 'Manage your supported languages for articles and categories' do %>
|
|
7
|
+
<%= render 'postnhost/shared/elements/button_link',
|
|
8
|
+
text: 'New Language',
|
|
9
|
+
url: new_language_path,
|
|
10
|
+
icon: 'plus',
|
|
11
|
+
extra_class: 'w-full md:w-auto' %>
|
|
12
|
+
<% end %>
|
|
13
|
+
|
|
14
|
+
<% if @languages.any? %>
|
|
15
|
+
<%= render 'postnhost/shared/elements/table_container',
|
|
16
|
+
headers: [
|
|
17
|
+
{ text: 'Language', class: 'col-span-5' },
|
|
18
|
+
{ text: 'Articles', class: 'col-span-3' },
|
|
19
|
+
{ text: 'Actions', class: 'col-span-4 text-right' }
|
|
20
|
+
] do %>
|
|
21
|
+
<% @languages.each do |language| %>
|
|
22
|
+
<div class="<%= table_row_classes %>">
|
|
23
|
+
<div class="grid grid-cols-12 gap-4 items-center">
|
|
24
|
+
<div class="col-span-5">
|
|
25
|
+
<%= link_to language_path(language), class: "block group" do %>
|
|
26
|
+
<div class="flex items-center space-x-3">
|
|
27
|
+
<div class="font-medium text-gray-900 group-hover:text-gray-600 transition-colors">
|
|
28
|
+
<%= language.name %>
|
|
29
|
+
</div>
|
|
30
|
+
<% if language.default? %>
|
|
31
|
+
<span class="<%= stats_badge_classes(variant: :blue) %> px-2 py-1">
|
|
32
|
+
Default
|
|
33
|
+
</span>
|
|
34
|
+
<% end %>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="text-sm text-gray-500 mt-1">
|
|
37
|
+
Code: <%= language.html_lang %>
|
|
38
|
+
</div>
|
|
39
|
+
<% end %>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="col-span-3">
|
|
43
|
+
<div class="flex items-center space-x-3">
|
|
44
|
+
<span class="<%= stats_badge_classes(variant: :blue) %>">
|
|
45
|
+
<%= language.articles_count %>
|
|
46
|
+
</span>
|
|
47
|
+
<span class="<%= stats_badge_classes(variant: :purple) %>">
|
|
48
|
+
<%= language.article_variants_count %>
|
|
49
|
+
</span>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="col-span-4 flex items-center justify-end space-x-2">
|
|
54
|
+
<%= render 'postnhost/shared/elements/icon_button',
|
|
55
|
+
icon: 'eye',
|
|
56
|
+
url: language_path(language) %>
|
|
57
|
+
|
|
58
|
+
<%= render 'postnhost/shared/elements/icon_button',
|
|
59
|
+
icon: 'edit',
|
|
60
|
+
url: edit_language_path(language) %>
|
|
61
|
+
|
|
62
|
+
<%= render 'postnhost/shared/elements/icon_button',
|
|
63
|
+
icon: 'trash',
|
|
64
|
+
url: language_path(language),
|
|
65
|
+
variant: :danger,
|
|
66
|
+
data: {
|
|
67
|
+
turbo_method: :delete,
|
|
68
|
+
turbo_confirm: "Are you sure you want to delete this language? This action cannot be undone."
|
|
69
|
+
} %>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
<% end %>
|
|
74
|
+
<% end %>
|
|
75
|
+
<% else %>
|
|
76
|
+
<%= render 'postnhost/shared/elements/empty_state',
|
|
77
|
+
icon: 'translate',
|
|
78
|
+
title: 'No languages',
|
|
79
|
+
description: 'Get started by creating your first language.' do %>
|
|
80
|
+
<%= render 'postnhost/shared/elements/button_link',
|
|
81
|
+
text: 'New Language',
|
|
82
|
+
url: new_language_path,
|
|
83
|
+
icon: 'plus' %>
|
|
84
|
+
<% end %>
|
|
85
|
+
<% end %>
|
|
86
|
+
</div>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<% content_for :title, "New Language" %>
|
|
2
|
+
|
|
3
|
+
<div class="max-w-2xl">
|
|
4
|
+
<%= render 'postnhost/shared/elements/form_page_header',
|
|
5
|
+
title: 'New Language',
|
|
6
|
+
description: 'Add a new language for your articles and categories' %>
|
|
7
|
+
|
|
8
|
+
<%= form_with model: @language, local: true, class: "space-y-6" do |form| %>
|
|
9
|
+
<%= render 'postnhost/shared/elements/error_messages', resource: @language %>
|
|
10
|
+
|
|
11
|
+
<%= render 'postnhost/shared/elements/form_card' do %>
|
|
12
|
+
<div>
|
|
13
|
+
<%= form.label :name, class: form_label_classes %>
|
|
14
|
+
<%= form.text_field :name,
|
|
15
|
+
class: form_input_classes,
|
|
16
|
+
placeholder: "Enter language name (e.g., English, Spanish)" %>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div>
|
|
20
|
+
<%= form.label :html_lang, "Language Code", class: form_label_classes %>
|
|
21
|
+
<%= form.text_field :html_lang,
|
|
22
|
+
class: form_input_classes,
|
|
23
|
+
placeholder: "Enter HTML language code (e.g., en, es, fr)" %>
|
|
24
|
+
<p class="mt-1 text-sm text-gray-500">ISO 639-1 language code for HTML lang attribute</p>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<div>
|
|
28
|
+
<div class="flex items-center">
|
|
29
|
+
<%= form.check_box :default,
|
|
30
|
+
class: "h-4 w-4 text-gray-600 focus:ring-gray-500 border-gray-300 rounded" %>
|
|
31
|
+
<%= form.label :default, "Default Language", class: "ml-2 block text-sm font-medium text-gray-700" %>
|
|
32
|
+
</div>
|
|
33
|
+
<p class="mt-1 text-sm text-gray-500">Set as the default language for new content</p>
|
|
34
|
+
</div>
|
|
35
|
+
<% end %>
|
|
36
|
+
|
|
37
|
+
<div class="flex items-center space-x-4">
|
|
38
|
+
<%= form.submit "Create Language", class: button_classes %>
|
|
39
|
+
<%= render 'postnhost/shared/elements/button_link',
|
|
40
|
+
text: 'Cancel',
|
|
41
|
+
url: languages_path,
|
|
42
|
+
variant: :secondary %>
|
|
43
|
+
</div>
|
|
44
|
+
<% end %>
|
|
45
|
+
</div>
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<% content_for :title, @language.name %>
|
|
2
|
+
|
|
3
|
+
<div class="space-y-8">
|
|
4
|
+
<%= render 'postnhost/shared/elements/page_header',
|
|
5
|
+
title: @language.name,
|
|
6
|
+
stats: [
|
|
7
|
+
{ text: "Code: #{@language.html_lang}", class: '' },
|
|
8
|
+
{ text: "#{@articles_pagy.count} articles", class: '' },
|
|
9
|
+
{ text: "#{@article_variants_pagy.count} article variants", class: '' },
|
|
10
|
+
(@language.default? ? { text: "Default Language", class: stats_badge_classes(variant: :blue) } : nil)
|
|
11
|
+
].compact do %>
|
|
12
|
+
<%= render 'postnhost/shared/elements/button_link',
|
|
13
|
+
text: 'Back to Languages',
|
|
14
|
+
url: languages_path(@article),
|
|
15
|
+
variant: :secondary,
|
|
16
|
+
icon: 'chevron-left',
|
|
17
|
+
extra_class: 'w-full md:w-auto' %>
|
|
18
|
+
<%= render 'postnhost/shared/elements/button_link',
|
|
19
|
+
text: 'Edit',
|
|
20
|
+
url: edit_language_path(@language),
|
|
21
|
+
icon: 'edit',
|
|
22
|
+
extra_class: 'w-full md:w-auto' %>
|
|
23
|
+
<%= render 'postnhost/shared/elements/button_link',
|
|
24
|
+
text: 'Delete',
|
|
25
|
+
url: language_path(@language),
|
|
26
|
+
variant: :danger,
|
|
27
|
+
icon: 'trash',
|
|
28
|
+
method: :delete,
|
|
29
|
+
extra_class: 'w-full md:w-auto',
|
|
30
|
+
data: {
|
|
31
|
+
turbo_method: :delete,
|
|
32
|
+
turbo_confirm: "Are you sure you want to delete this language? This action cannot be undone."
|
|
33
|
+
} %>
|
|
34
|
+
<% end %>
|
|
35
|
+
|
|
36
|
+
<% unless postnhost_public_locale_file_present_for?(@language.html_lang) %>
|
|
37
|
+
<div class="rounded-xl border border-yellow-200 bg-yellow-50 px-4 py-3 text-sm text-yellow-900 space-y-2">
|
|
38
|
+
<p class="font-medium">No locale file for this language code</p>
|
|
39
|
+
<p class="text-yellow-950">
|
|
40
|
+
There is no <code class="rounded bg-yellow-100 px-1.5 py-0.5 text-xs font-mono text-yellow-950">config/locales/<%= @language.html_lang %>.yml</code>
|
|
41
|
+
in your app and Postnhost does not ship one for <code class="rounded bg-yellow-100 px-1.5 py-0.5 text-xs font-mono text-yellow-950"><%= @language.html_lang %></code>.
|
|
42
|
+
Public pages may fall back to English for <code class="rounded bg-yellow-100 px-1.5 py-0.5 text-xs font-mono text-yellow-950">postnhost.public</code> strings.
|
|
43
|
+
</p>
|
|
44
|
+
<p class="text-yellow-950">
|
|
45
|
+
Generate a starter file from English:
|
|
46
|
+
<code class="rounded bg-yellow-100 px-1.5 py-0.5 text-xs font-mono text-yellow-950">bin/rails g postnhost:locale <%= @language.html_lang %></code>
|
|
47
|
+
</p>
|
|
48
|
+
</div>
|
|
49
|
+
<% end %>
|
|
50
|
+
|
|
51
|
+
<!-- Articles Section -->
|
|
52
|
+
<div class="bg-white rounded-lg border border-gray-200 overflow-hidden">
|
|
53
|
+
<div class="px-6 py-4 border-b border-gray-200 bg-gray-50">
|
|
54
|
+
<div class="flex items-center justify-between">
|
|
55
|
+
<div>
|
|
56
|
+
<h2 class="text-lg font-medium text-gray-900">Articles</h2>
|
|
57
|
+
<p class="mt-1 text-sm text-gray-600">Articles written in this language</p>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<span class="<%= stats_badge_classes(variant: :gray) %>">
|
|
61
|
+
<%= @articles_pagy.count %> articles
|
|
62
|
+
</span>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<% if @articles.any? %>
|
|
67
|
+
<div class="divide-y divide-gray-200">
|
|
68
|
+
<% @articles.each do |article| %>
|
|
69
|
+
<div class="<%= table_row_classes %>">
|
|
70
|
+
<div class="flex items-center justify-between">
|
|
71
|
+
<div class="flex-1">
|
|
72
|
+
<%= link_to edit_article_path(article), class: "block group" do %>
|
|
73
|
+
<div class="font-medium text-gray-900 group-hover:text-gray-600 transition-colors">
|
|
74
|
+
<%= article.title.present? ? article.title : 'Untitled' %>
|
|
75
|
+
</div>
|
|
76
|
+
<div class="text-sm text-gray-500 mt-1 flex items-center space-x-4">
|
|
77
|
+
<% if article.categories.any? %>
|
|
78
|
+
<span><%= article.categories.first.name %></span>
|
|
79
|
+
<% end %>
|
|
80
|
+
<span><%= article.created_at.strftime('%b %d, %Y') %></span>
|
|
81
|
+
</div>
|
|
82
|
+
<% end %>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
<div class="flex items-center space-x-2">
|
|
86
|
+
<span class="<%= stats_badge_classes(variant: article.published? ? :green : :gray) %>">
|
|
87
|
+
<%= article.published? ? 'Published' : 'Draft' %>
|
|
88
|
+
</span>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
<% end %>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<% if @articles_pagy.pages > 1 %>
|
|
96
|
+
<div class="border-t border-gray-200 px-6 py-4">
|
|
97
|
+
<%== pagination_nav(@articles_pagy) %>
|
|
98
|
+
</div>
|
|
99
|
+
<% end %>
|
|
100
|
+
<% else %>
|
|
101
|
+
<%= render 'postnhost/shared/elements/empty_state',
|
|
102
|
+
icon: 'document-text',
|
|
103
|
+
title: 'No articles',
|
|
104
|
+
description: 'No articles have been created in this language yet.' %>
|
|
105
|
+
<% end %>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<!-- Article Variants Section -->
|
|
109
|
+
<% if @article_variants.any? %>
|
|
110
|
+
<div class="bg-white rounded-lg border border-gray-200 overflow-hidden">
|
|
111
|
+
<div class="px-6 py-4 border-b border-gray-200 bg-gray-50">
|
|
112
|
+
<div class="flex items-center justify-between">
|
|
113
|
+
<div>
|
|
114
|
+
<h2 class="text-lg font-medium text-gray-900">Article Variants</h2>
|
|
115
|
+
<p class="mt-1 text-sm text-gray-600">Article translations in this language</p>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<span class="<%= stats_badge_classes(variant: :gray) %>">
|
|
119
|
+
<%= @article_variants_pagy.count %> variants
|
|
120
|
+
</span>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<div class="divide-y divide-gray-200">
|
|
125
|
+
<% @article_variants.each do |variant| %>
|
|
126
|
+
<div class="<%= table_row_classes %>">
|
|
127
|
+
<div class="flex items-center justify-between">
|
|
128
|
+
<div class="flex-1">
|
|
129
|
+
<%= link_to edit_article_path(variant.article), class: "block group" do %>
|
|
130
|
+
<div class="font-medium text-gray-900 group-hover:text-gray-600 transition-colors">
|
|
131
|
+
<%= variant.title.present? ? variant.title : 'Untitled Variant' %>
|
|
132
|
+
</div>
|
|
133
|
+
<div class="text-sm text-gray-500 mt-1">
|
|
134
|
+
<span>Original: <%= variant.article.title.present? ? variant.article.title : 'Untitled' %></span>
|
|
135
|
+
</div>
|
|
136
|
+
<% end %>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<div class="flex items-center space-x-2">
|
|
140
|
+
<span class="<%= stats_badge_classes(variant: :purple) %>">
|
|
141
|
+
Variant
|
|
142
|
+
</span>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
<% end %>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<% if @article_variants_pagy.pages > 1 %>
|
|
150
|
+
<div class="border-t border-gray-200 px-6 py-4">
|
|
151
|
+
<%== pagination_nav(@article_variants_pagy) %>
|
|
152
|
+
</div>
|
|
153
|
+
<% end %>
|
|
154
|
+
</div>
|
|
155
|
+
<% end %>
|
|
156
|
+
</div>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<div class="space-y-5">
|
|
2
|
+
<p class="text-sm text-gray-600">
|
|
3
|
+
Review these host-app settings before deployment. Details are available in the Production checklist section of the README.
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
<div class="rounded-xl border border-gray-200 bg-gray-50 p-4">
|
|
7
|
+
<ul class="space-y-3 text-sm text-gray-700">
|
|
8
|
+
<li>
|
|
9
|
+
<span class="font-medium text-gray-900">1. Favicon</span><br>
|
|
10
|
+
Replace the favicon and related icon files in the host app if needed.
|
|
11
|
+
</li>
|
|
12
|
+
<li>
|
|
13
|
+
<span class="font-medium text-gray-900">2. 404 and 500 pages</span><br>
|
|
14
|
+
Review the host app’s static error pages at <code>public/404.html</code> and <code>public/500.html</code>.
|
|
15
|
+
</li>
|
|
16
|
+
<li>
|
|
17
|
+
<span class="font-medium text-gray-900">3. robots.txt</span><br>
|
|
18
|
+
Update the host app’s <code>public/robots.txt</code> and confirm that the sitemap URL matches your mount path.
|
|
19
|
+
</li>
|
|
20
|
+
<li>
|
|
21
|
+
<span class="font-medium text-gray-900">4. Public template styling</span><br>
|
|
22
|
+
To customize the public site, run <code>bin/rails g postnhost:views --views-scope=minimal</code> or use <code>--views-scope=full</code>, then edit the copied templates.
|
|
23
|
+
</li>
|
|
24
|
+
<li>
|
|
25
|
+
<span class="font-medium text-gray-900">5. Production uploads</span><br>
|
|
26
|
+
The generated CarrierWave initializer uses S3-compatible storage in production. Configure it through Rails credentials or <code>config/initializers/postnhost.rb</code>, or replace that storage configuration.
|
|
27
|
+
</li>
|
|
28
|
+
</ul>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<%= form_with url: postnhost.onboarding_path, method: :patch do %>
|
|
32
|
+
<%= hidden_field_tag :step, "post_install_done" %>
|
|
33
|
+
<button type="submit" class="group relative w-full cursor-pointer overflow-hidden rounded-xl bg-gray-900 px-4 py-3 font-medium text-white transition-all duration-300 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-2">
|
|
34
|
+
<span class="relative flex items-center justify-center">
|
|
35
|
+
Go to Dashboard
|
|
36
|
+
<%= icon("arrow-right", css_class: "ml-2 h-4 w-4 transition-transform group-hover:translate-x-1") %>
|
|
37
|
+
</span>
|
|
38
|
+
</button>
|
|
39
|
+
<% end %>
|
|
40
|
+
</div>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<%= form_with model: @user, url: postnhost.onboarding_path, method: :patch, class: "space-y-5" do |f| %>
|
|
2
|
+
<%= hidden_field_tag :step, 1 %>
|
|
3
|
+
<%= render "postnhost/shared/form_errors", resource: @user %>
|
|
4
|
+
|
|
5
|
+
<div class="space-y-4">
|
|
6
|
+
<div>
|
|
7
|
+
<%= f.label :name, "Your name", class: "mb-1 block text-sm font-medium text-gray-700" %>
|
|
8
|
+
<%= f.text_field :name,
|
|
9
|
+
autofocus: true,
|
|
10
|
+
autocomplete: "name",
|
|
11
|
+
placeholder: "Enter your name",
|
|
12
|
+
required: true,
|
|
13
|
+
class: "block w-full rounded-xl border-gray-200 bg-gray-50 px-4 py-3 text-sm font-medium text-gray-900 placeholder-gray-500 transition-all duration-200 focus:border-gray-900 focus:bg-white focus:ring-0" %>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<div>
|
|
17
|
+
<%= f.label :email, "Email", class: "mb-1 block text-sm font-medium text-gray-700" %>
|
|
18
|
+
<%= f.email_field :email,
|
|
19
|
+
autocomplete: "email",
|
|
20
|
+
placeholder: "Enter your email address",
|
|
21
|
+
required: true,
|
|
22
|
+
class: "block w-full rounded-xl border-gray-200 bg-gray-50 px-4 py-3 text-sm font-medium text-gray-900 placeholder-gray-500 transition-all duration-200 focus:border-gray-900 focus:bg-white focus:ring-0" %>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div>
|
|
26
|
+
<%= f.label :password, "Password", class: "mb-1 block text-sm font-medium text-gray-700" %>
|
|
27
|
+
<%= f.password_field :password,
|
|
28
|
+
autocomplete: "new-password",
|
|
29
|
+
placeholder: "Create a password (min 6 characters)",
|
|
30
|
+
required: true,
|
|
31
|
+
minlength: 6,
|
|
32
|
+
class: "block w-full rounded-xl border-gray-200 bg-gray-50 px-4 py-3 text-sm font-medium text-gray-900 placeholder-gray-500 transition-all duration-200 focus:border-gray-900 focus:bg-white focus:ring-0" %>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<button type="submit" class="group relative w-full cursor-pointer overflow-hidden rounded-xl bg-gray-900 px-4 py-3 font-medium text-white transition-all duration-300 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-2">
|
|
37
|
+
<span class="relative flex items-center justify-center">
|
|
38
|
+
Continue
|
|
39
|
+
<%= icon("arrow-right", css_class: "ml-2 h-4 w-4 transition-transform group-hover:translate-x-1") %>
|
|
40
|
+
</span>
|
|
41
|
+
</button>
|
|
42
|
+
<% end %>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<%= form_with url: postnhost.onboarding_path, method: :patch, class: "space-y-5" do %>
|
|
2
|
+
<%= hidden_field_tag :step, 2 %>
|
|
3
|
+
|
|
4
|
+
<p class="text-xs text-gray-500">
|
|
5
|
+
Select one or more languages now. You can add more languages later.
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<div class="space-y-2">
|
|
9
|
+
<%= hidden_field_tag "language_locales[]", "" %>
|
|
10
|
+
<% @language_options.each do |option| %>
|
|
11
|
+
<label class="flex cursor-pointer items-center justify-between rounded-xl border border-gray-200 bg-gray-50 px-3 py-2">
|
|
12
|
+
<div class="flex items-center gap-2">
|
|
13
|
+
<%= check_box_tag "language_locales[]",
|
|
14
|
+
option[:html_lang],
|
|
15
|
+
@selected_language_locales.include?(option[:html_lang]),
|
|
16
|
+
id: "language_locale_#{option[:html_lang]}",
|
|
17
|
+
class: "cursor-pointer rounded border-gray-300 text-gray-900 focus:ring-gray-900" %>
|
|
18
|
+
<span class="text-sm text-gray-900"><%= option[:name] %> (<%= option[:html_lang] %>)</span>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="flex items-center gap-2">
|
|
21
|
+
<%= radio_button_tag :default_locale,
|
|
22
|
+
option[:html_lang],
|
|
23
|
+
@selected_default_locale == option[:html_lang],
|
|
24
|
+
id: "default_locale_#{option[:html_lang]}",
|
|
25
|
+
class: "cursor-pointer border-gray-300 text-gray-900 focus:ring-gray-900" %>
|
|
26
|
+
<span class="text-xs font-medium uppercase tracking-wide text-gray-500">Default</span>
|
|
27
|
+
</div>
|
|
28
|
+
</label>
|
|
29
|
+
<% end %>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<button type="submit" class="group relative w-full cursor-pointer overflow-hidden rounded-xl bg-gray-900 px-4 py-3 font-medium text-white transition-all duration-300 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-2">
|
|
33
|
+
<span class="relative flex items-center justify-center">
|
|
34
|
+
Continue
|
|
35
|
+
<%= icon("arrow-right", css_class: "ml-2 h-4 w-4 transition-transform group-hover:translate-x-1") %>
|
|
36
|
+
</span>
|
|
37
|
+
</button>
|
|
38
|
+
<% end %>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<%= form_with url: postnhost.onboarding_path, method: :patch, class: "space-y-5" do %>
|
|
2
|
+
<%= hidden_field_tag :step, 3 %>
|
|
3
|
+
|
|
4
|
+
<p class="text-sm text-gray-600">
|
|
5
|
+
Configure where your public site lives and how it appears to visitors and search engines.
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<% if @locale.to_s != "en" %>
|
|
9
|
+
<div class="space-y-3 rounded-xl border border-yellow-200 bg-yellow-50 px-4 py-3 text-sm text-yellow-900">
|
|
10
|
+
<p class="font-medium">Non-English default locale selected</p>
|
|
11
|
+
<p class="text-yellow-950">
|
|
12
|
+
Add <code class="rounded bg-yellow-100 px-1.5 py-0.5 text-xs font-mono text-yellow-950">config.i18n.fallbacks = [:en]</code>
|
|
13
|
+
to <code class="rounded bg-yellow-100 px-1.5 py-0.5 text-xs font-mono text-yellow-950">config/application.rb</code>
|
|
14
|
+
to keep missing translations safe.
|
|
15
|
+
</p>
|
|
16
|
+
</div>
|
|
17
|
+
<% end %>
|
|
18
|
+
|
|
19
|
+
<div class="space-y-3">
|
|
20
|
+
<div class="grid gap-x-4 gap-y-3 sm:grid-cols-2">
|
|
21
|
+
<div class="space-y-1">
|
|
22
|
+
<%= label_tag :site_url, "Site URL", class: "block cursor-pointer text-sm font-medium text-gray-700" %>
|
|
23
|
+
<%= url_field_tag :site_url,
|
|
24
|
+
@site_url,
|
|
25
|
+
placeholder: "https://example.com",
|
|
26
|
+
autocomplete: "url",
|
|
27
|
+
spellcheck: false,
|
|
28
|
+
aria: { describedby: "site_url_help" },
|
|
29
|
+
class: "block w-full rounded-xl border-gray-200 bg-gray-50 px-4 py-3 text-sm font-medium text-gray-900 placeholder-gray-500 transition-all duration-200 focus:border-gray-900 focus:bg-white focus:ring-0" %>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<% @site_copy.each do |key, value| %>
|
|
33
|
+
<div class="space-y-1">
|
|
34
|
+
<label for="translation_<%= key.parameterize %>" class="block cursor-pointer text-sm font-medium text-gray-700"><%= site_copy_label(key) %></label>
|
|
35
|
+
<%= text_field_tag "translations[#{key}]",
|
|
36
|
+
value,
|
|
37
|
+
id: "translation_#{key.parameterize}",
|
|
38
|
+
class: "block w-full rounded-xl border-gray-200 bg-gray-50 px-4 py-3 text-sm font-medium text-gray-900 placeholder-gray-500 transition-all duration-200 focus:border-gray-900 focus:bg-white focus:ring-0" %>
|
|
39
|
+
</div>
|
|
40
|
+
<% end %>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<%= hidden_field_tag :site_indexing, "noindex", id: nil %>
|
|
44
|
+
<label class="flex cursor-pointer items-start gap-3 rounded-xl border border-gray-200 bg-gray-50 px-4 py-3">
|
|
45
|
+
<%= check_box_tag :site_indexing,
|
|
46
|
+
"index",
|
|
47
|
+
@site_indexing == "index",
|
|
48
|
+
class: "mt-0.5 h-4 w-4 cursor-pointer rounded border-gray-300 text-gray-900 focus:ring-gray-900" %>
|
|
49
|
+
<span class="space-y-0.5">
|
|
50
|
+
<span class="block text-sm font-medium text-gray-900">Allow search engines to index this site</span>
|
|
51
|
+
<span class="block text-xs text-gray-500">Turn this off to output noindex, nofollow on every public page.</span>
|
|
52
|
+
</span>
|
|
53
|
+
</label>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<button type="submit" class="group relative w-full cursor-pointer overflow-hidden rounded-xl bg-gray-900 px-4 py-3 font-medium text-white transition-all duration-300 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-2">
|
|
57
|
+
<span class="relative flex items-center justify-center">
|
|
58
|
+
Continue
|
|
59
|
+
<%= icon("arrow-right", css_class: "ml-2 h-4 w-4 transition-transform group-hover:translate-x-1") %>
|
|
60
|
+
</span>
|
|
61
|
+
</button>
|
|
62
|
+
<% end %>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<%= form_with url: postnhost.onboarding_path, method: :patch, class: "space-y-5" do %>
|
|
2
|
+
<%= hidden_field_tag :step, 4 %>
|
|
3
|
+
|
|
4
|
+
<div class="space-y-3">
|
|
5
|
+
<p class="text-sm text-gray-600">
|
|
6
|
+
Generate demo categories and articles similar to the development seeds, or skip and start with an empty blog.
|
|
7
|
+
</p>
|
|
8
|
+
<div class="space-y-2">
|
|
9
|
+
<label class="flex cursor-pointer items-center gap-2 text-sm text-gray-700">
|
|
10
|
+
<%= radio_button_tag :generate_sample, "1", true, class: "cursor-pointer" %>
|
|
11
|
+
Yes, add sample categories and articles
|
|
12
|
+
</label>
|
|
13
|
+
<label class="flex cursor-pointer items-center gap-2 text-sm text-gray-700">
|
|
14
|
+
<%= radio_button_tag :generate_sample, "0", false, class: "cursor-pointer" %>
|
|
15
|
+
No, start empty
|
|
16
|
+
</label>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<button type="submit" class="group relative w-full cursor-pointer overflow-hidden rounded-xl bg-gray-900 px-4 py-3 font-medium text-white transition-all duration-300 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-gray-900 focus:ring-offset-2">
|
|
21
|
+
<span class="relative flex items-center justify-center">
|
|
22
|
+
Finish setup
|
|
23
|
+
<%= icon("arrow-right", css_class: "ml-2 h-4 w-4 transition-transform group-hover:translate-x-1") %>
|
|
24
|
+
</span>
|
|
25
|
+
</button>
|
|
26
|
+
<% end %>
|