There be a website

This commit is contained in:
Roscoe 2025-09-21 03:09:52 +01:00
commit af0907c7c3
Signed by: RoscoeDaWah
SSH key fingerprint: SHA256:Hqn452XQ1ETzUt/FthJu6+OFkS4NBxCv5VQSEvuk7CE
65 changed files with 708 additions and 14 deletions

18
.editorconfig Normal file
View file

@ -0,0 +1,18 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4

View file

@ -12,6 +12,8 @@ gem "puma", ">= 5.0"
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ] gem "tzinfo-data", platforms: %i[ windows jruby ]
gem "view_component"
group :development, :test do group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"

View file

@ -205,6 +205,9 @@ GEM
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
uri (1.0.3) uri (1.0.3)
useragent (0.16.11) useragent (0.16.11)
view_component (4.0.2)
activesupport (>= 7.1.0, < 8.1)
concurrent-ruby (~> 1)
websocket-driver (0.8.0) websocket-driver (0.8.0)
base64 base64
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
@ -230,6 +233,7 @@ DEPENDENCIES
rails (~> 8.0.2, >= 8.0.2.1) rails (~> 8.0.2, >= 8.0.2.1)
sqlite3 (>= 2.1) sqlite3 (>= 2.1)
tzinfo-data tzinfo-data
view_component
BUNDLED WITH BUNDLED WITH
2.7.1 2.7.1

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 786 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 996 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 899 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
app/assets/images/logo-v2.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 746 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

BIN
app/assets/images/peek.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -0,0 +1,31 @@
<!--
pride flag - copyright (c) 2024 ari melody
this code is provided AS-IS, WITHOUT ANY WARRANTY, to be
freely redistributed and/or modified as you please, however
retaining this license in any redistribution.
please use this flag to link to an LGBTQI+-supporting page
of your choosing!
web: https://arimelody.me
source: https://git.arimelody.me/ari/prideflag
-->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="120" height="120">
<path id="red" d="M120,80 L100,100 L120,120 Z" style="fill:#d20605"/>
<path id="orange" d="M120,80 V40 L80,80 L100,100 Z" style="fill:#ef9c00"/>
<path id="yellow" d="M120,40 V0 L60,60 L80,80 Z" style="fill:#e5fe02"/>
<path id="green" d="M120,0 H80 L40,40 L60,60 Z" style="fill:#09be01"/>
<path id="blue" d="M80,0 H40 L20,20 L40,40 Z" style="fill:#081a9a"/>
<path id="purple" d="M40,0 H0 L20,20 Z" style="fill:#76008a"/>
<rect id="black" x="60" width="60" height="60" style="fill:#010101"/>
<rect id="brown" x="70" width="50" height="50" style="fill:#603814"/>
<rect id="lightblue" x="80" width="40" height="40" style="fill:#73d6ed"/>
<rect id="pink" x="90" width="30" height="30" style="fill:#ffafc8"/>
<rect id="white" x="100" width="20" height="20" style="fill:#fff"/>
<rect id="intyellow" x="110" width="10" height="10" style="fill:#fed800"/>
<circle id="intpurple" cx="120" cy="0" r="5" stroke="#7601ad" stroke-width="2" fill="none"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/assets/images/roscoe_tile.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View file

@ -8,3 +8,363 @@
* *
* Consider organizing styles into separate files for maintainability. * Consider organizing styles into separate files for maintainability.
*/ */
:root {
--background: hsl(214, 67%, 85%);
--foreground: hsl(214, 20%, 14%);
--border-color: hsl(214, 96%, 48%);
--border: var(--border-color) 2px solid;
--shadow-color: hsla(214, 96%, 43%, 0.4);
--shadow: drop-shadow(8px 8px var(--shadow-color));
--shadow-small: drop-shadow(3px 3px var(--shadow-color));
--links: hsl(214, 27%, 22%);
--links-hover: hsl(214, 27%, 15%);
--table-header: hsla(214, 96%, 43%, 0.2);
}
/* ───────────────────────────────────── Fonts ────────────────────────────────────── */
@font-face {
font-family: "PT Sans";
src: url("PTSans-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "PT Sans";
src: url("PTSans-Italic.ttf") format("truetype");
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: "PT Sans";
src: url("PTSans-Bold.ttf") format("truetype");
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: "PT Sans";
src: url("PTSans-BoldItalic.ttf") format("truetype");
font-weight: bold;
font-style: italic;
}
@font-face {
font-family: "PT Serif";
src: url("PTSerif-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "PT Serif";
src: url("PTSerif-Italic.ttf") format("truetype");
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: "PT Serif";
src: url("PTSerif-Bold.ttf") format("truetype");
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: "PT Serif";
src: url("PTSerif-BoldItalic.ttf") format("truetype");
font-weight: bold;
font-style: italic;
}
/* ───────────────────────────────────── Pride ────────────────────────────────────── */
#prideflag {
position: fixed;
top: 0;
right: 0;
width: 120px;
transform-origin: 100% 0;
transition: transform .5s cubic-bezier(.32,1.63,.41,1.01);
z-index: 8008135;
}
#prideflag:hover {
transform: scale(110%);
}
#prideflag:active {
transform: scale(110%);
}
#prideflag * {
pointer-events: all;
}
/* ───────────────────────────────────── Global ───────────────────────────────────── */
html {
height: 100%;
color-scheme: light;
scrollbar-color: var(--border-color) var(--background);
}
body {
color: var(--foreground);
min-height: 100%;
background: url('roscoe_tile.jpg');
padding: 5px;
font-family: "PT Serif", serif;
}
img.logo_paw {
filter: grayscale(100%) sepia(100%) hue-rotate(180deg) saturate(300%);
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 20px 0 0 0;
}
p,
ul,
ol,
dl,
menu,
dir {
margin: 0;
}
hr {
border: none;
border-top: var(--border);
}
a {
color: var(--links);
text-decoration: underline dotted;
}
a:hover {
color: var(--links-hover);
text-decoration: underline solid;
}
div.page-container {
width: 800px;
margin: 5px auto;
}
div.page-container > div {
background-color: var(--background);
filter: var(--shadow);
padding: 10px;
border: var(--border);
margin-bottom: 20px;
}
div.page-container > div:last-child {
margin-bottom: 0;
}
header {
display: grid;
grid-template-columns: 64px 1fr;
grid-template-rows: 1fr;
grid-column-gap: 15px;
grid-row-gap: 0;
align-items: center;
}
header img {
image-rendering: pixelated;
}
header h1 {
margin: 0;
font-style: italic;
}
header h1,
header p {
display: inline;
}
main>div {
position: relative;
}
main>div::after {
display: block;
content: "";
clear: both;
}
div#footer {
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: 1fr;
grid-column-gap: 0;
grid-row-gap: 0;
align-items: center;
}
div#footer div:last-child {
text-align: right;
}
div#footer div:last-child img {
image-rendering: pixelated;
margin: 0;
padding: 0;
width: 88px;
height: 31px;
}
/** Wah! **/
div.wah {
float: right;
border: var(--border);
padding: 5px;
filter: var(--shadow-small);
background-color: var(--background);
}
div.wah img {
display: block;
}
div.wah h3,
div.wah p {
text-align: center;
margin: 5px 0;
font-style: italic;
}
div.wah p {
margin-bottom: 0;
}
div.wah img {
width: 250px;
}
/** Guestbook **/
table.form input,
table.form textarea,
table.form button {
background-color: var(--background);
border: var(--border);
filter: var(--shadow-small);
}
table.form input,
table.form textarea {
width: 250px;
}
table.form textarea {
resize: none;
}
table.form button:hover {
background-color: var(--border-color);
color: var(--background);
filter: none;
}
table.form tr td,
table.gb-entry-form-container td:last-child {
vertical-align: top;
}
div.gb-entry {
border: var(--border);
filter: var(--shadow-small);
background-color: var(--background);
width: 75%;
padding: 10px;
}
/** Music **/
table.music-top10 {
border: var(--border);
filter: var(--shadow-small);
background-color: var(--background);
border-collapse: collapse;
}
table.music-top10 th,
table.music-top10 td {
padding: 2px 5px;
}
table.music-top10 th:first-child {
text-align: left;
}
table.music-top10 tr:first-child th {
border-right: var(--border);
border-bottom: var(--border);
}
table.music-top10 tr:first-child th:last-child {
border-right: none;
}
table.music-top10 tr td {
border-right: var(--border);
}
table.music-top10 tr td:last-child {
border-right: none;
}
table.music-top10 tr:first-child th,
table.music-top10 tr td:first-child {
background-color: var(--table-header);
}
div.current-track {
display: grid;
grid-template-columns: 180px auto;
grid-template-rows: 1fr;
grid-column-gap: 10px;
align-items: center;
}
div.current-track img {
float: left;
filter: var(--shadow-small);
border: var(--border);
width: 174px;
height: 174px;
}
/** Bookmarks **/
div.bookmark-category:first-child h2 {
margin: 0;
}
/* ────────────────────────────────── Rosco & Leko ────────────────────────────────── */
div.rosco-leko-gallery {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
div.rosco-leko-gallery > div {
border: var(--border);
padding: 5px;
filter: var(--shadow-small);
background-color: var(--background);
margin: 10px;
height: auto;
}
div.rosco-leko-gallery > div,
div.rosco-leko-gallery > div img {
max-width: 220px;
}

View file

@ -0,0 +1,5 @@
<div class="wah">
<h3>Random Wah!</h3>
<%= image_tag @wah_url, alt: "Random image featuring a red panda" %>
<p>Image "stolen" from <a href="https://tinyfox.dev/">tinyfox.dev</a></p>
</div>

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
require "net/http"
require "json"
class WahComponent < ViewComponent::Base
def initialize(legacy:)
if legacy then
else
uri = URI.parse('https://api.tinyfox.dev/img.json?animal=wah')
req = Net::HTTP::Get.new(uri.to_s)
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) {|http|
http.request(req)
}
data = JSON.parse(res.body)
url = "https://tinyfox.dev" + data["loc"]
@wah_url = url
end
end
end

View file

@ -0,0 +1,9 @@
class HomeController < ApplicationController
def years_between_dates(date_from, date_to)
return (date_to - date_from).to_i / 365
end
def index
@age = years_between_dates(DateTime.civil_from_format(:local, 2005, 6, 7), DateTime.now)
end
end

View file

@ -0,0 +1,78 @@
require 'uri'
require 'net/http'
class MusicController < ApplicationController
def get_current_track
if Rails.cache.exist?("current_track")
return Rails.cache.read("current_track")
end
uri = URI.parse('https://ws.audioscrobbler.com/2.0/')
params = {
:method => 'user.getrecenttracks',
:user => Rails.application.credentials.lastfm.username,
:format => 'json',
:nowplaying => 'true',
:api_key => Rails.application.credentials.lastfm.api_key
}
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri.to_s)
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) {|http|
http.request(req)
}
data = JSON.parse(res.body)
track_data = data["recenttracks"]["track"][0]
image = defined?(track_data["image"][-1]) ? track_data["image"][-1] : false
now_playing = false
if track_data["@attr"] != nil
now_playing = track_data["@attr"]["nowplaying"] == "true"
end
current_track = {
:title => track_data["name"],
:artist => track_data["artist"]["#text"],
:url => track_data["url"],
:image => image["#text"],
:header => if now_playing then "Now Playing" else "Last Track" end
}
return current_track
end
def get_top_tracks
if Rails.cache.exist?("top_tracks")
return Rails.cache.read("top_tracks")
end
uri = URI.parse('https://ws.audioscrobbler.com/2.0/')
params = {
:method => 'user.gettoptracks',
:user => Rails.application.credentials.lastfm.username,
:format => 'json',
:period => '1month',
:limit => 10,
:api_key => Rails.application.credentials.lastfm.api_key
}
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri.to_s)
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) {|http|
http.request(req)
}
data = JSON.parse(res.body)
top_tracks = []
data["toptracks"]["track"].each do |track|
top_tracks.push({
:title => track["name"],
:artist => track["artist"]["name"],
:url => track["url"],
:plays => track["playcount"]
})
end
return top_tracks
end
def index
@current_track = get_current_track
@top_tracks = get_top_tracks
end
end

View file

@ -1,2 +1,9 @@
module ApplicationHelper module ApplicationHelper
def is_legacy
return (
request.host === "legacy.wah.moe" or
request.host.start_with? ("192.168") or
request.headers["Host"] === nil
)
end
end end

View file

@ -0,0 +1,2 @@
module HomeHelper
end

View file

@ -0,0 +1,2 @@
module MusicHelper
end

View file

@ -0,0 +1,30 @@
<%= unless is_legacy then render(WahComponent.new(legacy: is_legacy)) end %>
<p>Hi! This is my personal homepage on the <strong>W</strong>orld <strong>W</strong>ide
<strong>W</strong>eb.
</p>
<% unless is_legacy then%>
<br>
<% end %>
<p>Some quick facts about me:</p>
<ul>
<li><%= @age %> y/o, he/him, British</li>
<li>Theatre Technician and &quot;Web Developer&quot;</li>
<li>Loves ETC desks, prefers Generics to LEDs for some reason</li>
<li>Spends way too much time on his computer</li>
<li>Favorite games: <a href="https://steamcommunity.com/id/RoscoeDaWah/recommended/420530/"><font color="#000000">OneShot</font></a>,
Minecraft, Stardew Valley, N++ and Starbound</li>
<li><a href="http://wxqa.com/"><font color="#000000">CWOP</font></a> member</li>
</ul>
<% unless is_legacy then%>
<br>
<% end %>
<p>Interests:</p>
<ul>
<li><strong>Tech Theatre</strong> - Lighting, Stage Management, etc.</li>
<li><strong>Programming</strong> - HTML, CSS, JavaScript, C#, Java, PHP, Ruby, Python (<a
href="https://github.com/RoscoeDaWah"><font color="#000000">GitHub</font></a>)</li>
<li><strong>Photography</strong> - <a href="https://www.flickr.com/photos/roscoedawah/"><font color="#000000">Flickr</font></a></li>
<li><strong>Gaming</strong> - <a href="https://steamcommunity.com/id/RoscoeDaWah/"><font color="#000000">Steam Profile</font></a>
</li>
</ul>

View file

@ -1,10 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<title><%= content_for(:title) || "Wah Moe" %></title> <!-- Global -->
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta charset="utf-8">
<meta name="apple-mobile-web-app-capable" content="yes"> <meta property="og:type" content="website">
<meta name="mobile-web-app-capable" content="yes"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#f27405">
<meta name="twitter:card" content="summary_large_image">
<title>wah! (dot moe)</title>
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
<%= csp_meta_tag %> <%= csp_meta_tag %>
@ -13,15 +16,75 @@
<%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %> <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %>
<%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %> <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %>
<link rel="icon" href="/icon.png" type="image/png"> <%= favicon_link_tag %>
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/icon.png">
<%# Includes all stylesheet files in app/assets/stylesheets %> <%# Includes all stylesheet files in app/assets/stylesheets %>
<%= stylesheet_link_tag :app %> <%= stylesheet_link_tag :app %>
</head> </head>
<body> <body>
<%= link_to (image_tag "progress.svg", width: 120, height: 120, alt: "progressive pride flag"), "https://git.arimelody.me/ari/prideflag", id: "prideflag", target: "_blank" %>
<div class="page-container">
<div id="header">
<header>
<div>
<%= image_tag "logo-v2.png", class: "logo_paw", width: 65, alt: "A pixel art depiction of a paw, in three alternating shades of blue."%>
</div>
<div>
<h1>wah!</h1>
<p>
(dot moe)
</p>
<nav>
<strong>Pages:</strong>
<a href="/">home</a> |
<% unless is_legacy then%>
<a href="//wiki.wah.moe">wah-ki</a> |
<% end %>
<a href="//git.wah.moe">git</a> |
<a href="/pub">files</a> |
<a href="gopher://wah.moe">gopher</a> |
<a href="/bookmarks">bookmarks</a> |
<a href="/guestbook">guestbook</a> |
<a href="/music">music</a> |
<a href="/pandamonium">pandamonium</a>
</nav>
</div>
</header>
</div>
<div id="content">
<main>
<%= yield %> <%= yield %>
</body> <div class="clear"></div>
</main>
</div>
<div>
<footer>
<div id="footer">
<div>
<span>
&copy; RoscoeDaWah 2021-<%= Time.now.year %><br>
vVERSION, <a href="https://git.frzn.dev/RoscoeDaWah/wah.moe/releases/latest">Source</a><br>
<a href="https://webring.julimiro.eu/api/previous/wah.moe">&lt;</a> <a href="https://webring.julimiro.eu/">the basename ring</a> <a href="https://webring.julimiro.eu/api/next/wah.moe">&gt;</a>
</span>
</div>
<div>
<%= image_tag "buttons/wah.png", alt: "wah! (dot moe)" %>
<%= link_to (image_tag "buttons/cnfunknown.gif", alt: "ConfusionUnknown"), "https://aliceisvery.gay" %>
<%= link_to (image_tag "buttons/juli.gif", alt: "Julimiro.eu"), "https://julimiro.eu" %>
<%= link_to (image_tag "buttons/x86.gif", alt: "x86Overflow"), "https://x86.isafox.gay" %>
<%= link_to (image_tag "buttons/thnlqd.png", alt: "thinliquid"), "https://thinliquid.dev" %>
<%= link_to (image_tag "https://dimden.dev/services/images/88x31.gif", alt: "Dimden's website"), "https://dimden.dev" %><br>
<%= image_tag "buttons/servfail.png", alt: "Servfail DNS" %>
<%= link_to (image_tag "buttons/linuxnow.gif", alt: "Linux NOW!"), "https://linux.org" %>
<%= image_tag "buttons/paws-aliased.png", alt: "Made with my own two paws" %>
<%= image_tag "buttons/transrights.gif", alt: "Trans Rights NOW!" %>
<%= link_to (image_tag "buttons/vim.gif", alt: "Vim"), "https://www.vim.org" %>
<%= image_tag "buttons/aliasing.png", alt: "I Heart Aliasing" %>
</div>
</div>
</footer>
</div>
</div>
</body>
</html> </html>

View file

@ -0,0 +1,32 @@
<div class="current-track">
<% if @current_track["image"] != "" %>
<div>
<%= image_tag @current_track[:image], alt: "Album cover for " + @current_track[:title] + " by " + @current_track[:artist] %>
</div>
<% end %>
<div>
<h2><%= @current_track[:header]%>:</h2>
<font color="#000000"><%== link_to @current_track[:title] %></font><br>
by <%= @current_track[:artist] %><br>
</div>
</div>
<table class="music-top10">
<caption>
<h2 style="margin-bottom: 5px">Top 10 Tracks (Last 30 days):</h2>
</caption>
<tr>
<th><b>#</b></th>
<th><b>Track</b></th>
<th><b>Artist</b></th>
<th><b>Plays</b></th>
</tr>
<% @top_tracks.each.with_index do |track, index| %>
<tr>
<td><%= index %></td>
<td><font color="#000000"><%= link_to track[:title], track[:url] %></font></td>
<td><%= track[:artist] %></td>
<td><%= track[:plays] %></td>
</tr>
<% end %>
</table>

View file

@ -14,6 +14,8 @@ require "action_view/railtie"
# require "action_cable/engine" # require "action_cable/engine"
require "rails/test_unit/railtie" require "rails/test_unit/railtie"
require 'view_component'
# Require the gems listed in Gemfile, including any gems # Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production. # you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups) Bundler.require(*Rails.groups)

View file

@ -10,5 +10,7 @@ Rails.application.routes.draw do
# get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker # get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker
# Defines the root path route ("/") # Defines the root path route ("/")
# root "posts#index" root "home#index"
get "music" => "music#index"
end end

View file

@ -0,0 +1,12 @@
# frozen_string_literal: true
require "test_helper"
class WahComponentTest < ViewComponent::TestCase
def test_component_renders_something_useful
# assert_equal(
# %(<span>Hello, components!</span>),
# render_inline(WahComponent.new(message: "Hello, components!")).css("span").to_html
# )
end
end

View file

@ -0,0 +1,7 @@
require "test_helper"
class HomeControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end

View file

@ -0,0 +1,7 @@
require "test_helper"
class MusicControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end