diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css index bc471f7..107281b 100644 --- a/app/assets/stylesheets/application.tailwind.css +++ b/app/assets/stylesheets/application.tailwind.css @@ -4,3 +4,41 @@ @tailwind components; @tailwind utilities; +.loading { + position: relative; +} + +.loading::after { + content: ""; + position: absolute; + top: 50%; + right: 1rem; + transform: translateY(-50%); + width: 1rem; + height: 1rem; + border: 2px solid transparent; + border-top-color: currentColor; + border-right-color: currentColor; + border-radius: 50%; + animation: spin 0.6s linear infinite; +} + +@keyframes spin { + to { + transform: translateY(-50%) rotate(360deg); + } +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +.animate-spin { + animation: spin 1s linear infinite; + transform-origin: center center; +} \ No newline at end of file diff --git a/app/controllers/cities_controller.rb b/app/controllers/cities_controller.rb index a89ab26..4949bac 100644 --- a/app/controllers/cities_controller.rb +++ b/app/controllers/cities_controller.rb @@ -15,18 +15,17 @@ class CitiesController < ApplicationController @cities = @cities.by_region(@current_region.id) if @current_region end - if params[:country] - @current_country = Country.friendly.find(params[:country]) - @cities = @cities.by_country(@current_country.id) - end - @cities = @cities.page(params[:page]).per(12) - set_meta_tags( - title: @current_region ? "Cities in #{@current_region.name}" : "Explore Cities", - description: "Discover weather art for cities #{@current_region ? "in #{@current_region.name}" : 'worldwide'}. Real-time AI-generated weather visualization.", - keywords: "#{@current_region&.name}, cities, weather art, AI visualization" - ) + respond_to do |format| + format.html + format.turbo_stream { + render turbo_stream: turbo_stream.update("cities_results", + partial: "cities/results", + locals: { cities: @cities } + ) + } + end end def show diff --git a/app/javascript/controllers/search_controller.js b/app/javascript/controllers/search_controller.js index bcfed0e..2454f0a 100644 --- a/app/javascript/controllers/search_controller.js +++ b/app/javascript/controllers/search_controller.js @@ -2,12 +2,71 @@ import { Controller } from "@hotwired/stimulus" export default class extends Controller { - static targets = ["input"] + static targets = ["input", "clearButton", "spinner", "statusIcon"] + + connect() { + this.pendingRequest = null + } submit() { clearTimeout(this.timeout) this.timeout = setTimeout(() => { - this.element.requestSubmit() + // 如果有待处理的请求,则中止它 + if (this.pendingRequest) { + this.pendingRequest.abort() + } + + const form = this.element + const searchInput = this.inputTarget + const encodedValue = encodeURIComponent(searchInput.value) + + // 更新 URL + const url = new URL(window.location) + url.searchParams.set('query', encodedValue) + window.history.pushState({}, '', url) + + // 显示加载状态 + this.showLoadingState() + + // 发送请求 + this.pendingRequest = new AbortController() + fetch(form.action + '?' + new URLSearchParams(new FormData(form)), { + headers: { + 'Accept': 'text/vnd.turbo-stream.html', + 'Turbo-Frame': 'cities_results' + }, + signal: this.pendingRequest.signal + }) + .then(response => response.text()) + .then(html => { + Turbo.renderStreamMessage(html) + }) + .catch(error => { + if (error.name === 'AbortError') return + console.error('Search error:', error) + }) + .finally(() => { + this.hideLoadingState() + this.pendingRequest = null + }) }, 300) } + + showLoadingState() { + if (this.hasClearButtonTarget) { + this.clearButtonTarget.classList.add('hidden') + } + if (this.hasSpinnerTarget) { + this.spinnerTarget.classList.remove('hidden') + } + } + + hideLoadingState() { + if (this.hasClearButtonTarget) { + this.clearButtonTarget.classList.remove('hidden') + } + if (this.hasSpinnerTarget) { + this.spinnerTarget.classList.add('hidden') + } + } } \ No newline at end of file diff --git a/app/views/cities/_results.html.erb b/app/views/cities/_results.html.erb new file mode 100644 index 0000000..897237b --- /dev/null +++ b/app/views/cities/_results.html.erb @@ -0,0 +1,24 @@ + +
+ <%= t('.no_results_message') %> +
+- Try adjusting your search or filters to find what you're looking for. -
-