docs: #303 support for @theodore-s-beers Theo Beers' pretty-print format for poems:

This commit is contained in:
Hamid Reza Mohammadi 2022-03-28 15:14:58 +04:30
parent e0f5927c81
commit c03c232e7d
28 changed files with 345 additions and 24 deletions

View File

@ -15,7 +15,7 @@
گنجور » نمایش خوانش
</title>
<link href="~/dist/skin/pink.flag/css/jplayer.pink.flag.min.css" rel="stylesheet" type="text/css" />
<link href="~/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="~/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />
<script>

View File

@ -11,7 +11,7 @@
<title>انتخاب قطعهٔ موسیقی مرتبط با شعر از بیپتونز</title>
<meta name="robots" content="noindex, nofollow" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/spotify.css" rel="stylesheet" type="text/css" />
<script src="/lib/jquery/dist/jquery.min.js"></script>

View File

@ -14,7 +14,7 @@
@ViewData["Title"]
</title>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />

View File

@ -12,7 +12,7 @@
@ViewData["Title"]
</title>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/fab.css" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />

View File

@ -10,7 +10,7 @@
<title>انتخاب قطعه‌ای از برنامهٔ گلها مرتبط با این شعر</title>
<meta name="robots" content="noindex, nofollow" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/spotify.css" rel="stylesheet" type="text/css" />
<script src="/lib/jquery/dist/jquery.min.js"></script>
<script src="~/js/golha.js"></script>

View File

@ -12,7 +12,7 @@
<title>
@Html.Raw(ViewData["Title"])
</title>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/fab.css" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />

View File

@ -13,7 +13,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex, nofollow" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="hdr">

View File

@ -12,7 +12,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="شاعران و نویسندگان گنجور روی نقشهٔ جغرافیایی" />
<meta charset="utf-8" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="/css/leaflet.css" />
<style>
.leaflet-container {

View File

@ -11,7 +11,7 @@
<title>
@Html.Raw(ViewData["Title"])
</title>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/fab.css" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />

View File

@ -11,7 +11,7 @@
<title>پیشنهاد شعر مرتبط با تصویر</title>
<meta name="robots" content="noindex, nofollow" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/spotify.css" rel="stylesheet" type="text/css" />
<script src="/lib/jquery/dist//jquery.min.js"></script>

View File

@ -12,7 +12,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex, nofollow" />
<title>اطلاعات رتبه‌بندی خوانش‌های شعر</title>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
</head>
<body>

View File

@ -11,7 +11,7 @@
<meta name="robots" content="noindex, nofollow" />
<title>درخواست حذف حاشیه</title>
<script src="/lib/jquery/dist/jquery.min.js"></script>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<style>
label {
width: 100px;

View File

@ -13,7 +13,7 @@
<meta name="robots" content="noindex, nofollow" />
<title>گزارش خطا در خوانش</title>
<script src="/lib/jquery/dist/jquery.min.js"></script>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<style>
label {
width: 100px;

View File

@ -12,7 +12,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex, nofollow" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="hdr">

View File

@ -15,7 +15,7 @@
@ViewData["Title"]
</title>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/fab.css" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />

View File

@ -10,7 +10,7 @@
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
<link href="/dist/skin/blue.monday/css/jplayer.blue.monday.min.css" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/fab.css" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />

View File

@ -9,7 +9,7 @@
</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/fab.css" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />

View File

@ -12,7 +12,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="noindex, nofollow" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="hdr">

View File

@ -11,7 +11,7 @@
<title>انتخاب قطعهٔ موسیقی مرتبط با شعر از اسپاتیفای</title>
<meta name="robots" content="noindex, nofollow" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link href="/css/spotify.css" rel="stylesheet" type="text/css" />
<script src="/lib/jquery/dist/jquery.min.js"></script>

View File

@ -14,7 +14,7 @@
گنجور » برگردان‌ها و نویس‌های شعر
</title>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<link href="~/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="~/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />
</head>

View File

@ -393,6 +393,11 @@
}
}
<span id="t6e" class="w3tooltip">
<a role="button" id="t6e-button" target="_blank" class="pagebutton"href="/t6e?p=@Model.GanjoorPage.Id"><i class="info-buttons menu-book"></i></a>
<span class="w3tooltiptext" id="t6e-tooltip">نمای چاپی</span>
</span>
@if (Model.LoggedIn)
{
<a role="button" class="pagebutton comments-link" href="@Html.Raw($"/trans?p={Model.GanjoorPage.Id}")" onclick="wpopen(this.href); return false" title="برگردان‌ها و نویسش‌ها"><i class="info-buttons translate-button"></i></a>

View File

@ -14,7 +14,7 @@
@ViewData["Title"]
</title>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />

View File

@ -15,7 +15,7 @@
@ViewData["Title"]
</title>
<link href="/css/p8.css?version=38" rel="stylesheet" type="text/css" />
<link href="/css/p8.css?version=39" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="search" type="application/opensearchdescription+xml" title="گنجور" href="https://ganjoor.net/search.xml" />

View File

@ -0,0 +1,166 @@
@page
@model GanjooRazor.Pages.t6eModel
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="fa-IR" dir="rtl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<meta name="robots" content="noindex, nofollow" />
@if (Model.Poem != null)
{
<title>@Model.Poem.FullTitle</title>
}
<style>
code {
white-space: pre-wrap;
}
span.smallcaps {
font-variant: small-caps;
}
span.underline {
text-decoration: underline;
}
div.column {
display: inline-block;
vertical-align: top;
width: 50%;
}
</style>
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link href="https://fonts.googleapis.com/css2?family=Scheherazade&display=swap" rel="stylesheet" />
<link href="~/css/t6e.css" rel="stylesheet" type="text/css" />
</head>
<body>
@if (!string.IsNullOrEmpty(Model.LastError))
{
@Html.Raw(Model.LastError)
}
else
{
<header id="title-block-header">
<h1 class="title"><a href="@Model.Poem.FullUrl">@Model.Poem.FullTitle</a></h1>
</header>
@Html.Raw(Model.Poem.HtmlText)
<script>
function fixup() {
//
// LINE NUMBER & SEPARATOR DIVS
//
// Select all first hemistichs
const firstHems = document.querySelectorAll("div.m1");
for (let i = 0; i < firstHems.length; i++) {
// Add a div for line number before each first hemistich
firstHems[i].insertAdjacentHTML(
"beforebegin",
'<div class="line-number"></div>'
);
// Add a div for separator after each first hemistich
firstHems[i].insertAdjacentHTML(
"afterend",
'<div class="separator"></div>'
);
}
//
// FINAL LINE
//
// Select all whole lines
const lines = document.querySelectorAll("div.b");
// Select final line
const finalLine = lines[lines.length - 1];
// Apply special class to final line
finalLine.classList.remove("b");
finalLine.classList.add("final-line");
//
// ADD LINE NUMBERS
//
// Select all line number divs
const lineNumbers = document.querySelectorAll("div.line-number");
// Final line should never be numbered, so we stop iteration early
for (let i = 0; i < lineNumbers.length - 1; i++) {
// The actual line number, 1-indexed
const count = i + 1;
// If divisible by three, insert number
if (count % 3 === 0) {
// Number is also localized for Persian
lineNumbers[i].innerHTML = `<p>${count.toLocaleString("fa-IR")}</p>`;
}
}
//
// HEMISTICH WIDTH
//
// I picked up this function from SO. It's supposed to use a canvas to
// calculate the width of some text. We provide a string of text and the
// desired font properties.
function getTextWidth(text, font) {
const canvas =
getTextWidth.canvas ||
(getTextWidth.canvas = document.createElement("canvas"));
const context = canvas.getContext("2d");
context.font = font;
const metrics = context.measureText(text);
return metrics.width;
}
// Select all p tags. This is an easy way of getting all hemistichs.
const allHems = document.querySelectorAll("p");
// Set up variable to hold max computed text width
let maxWidth = 0;
// Iterate over hemistichs, calculating width of each
for (let i = 0; i < allHems.length; i++) {
const testText = allHems[i].innerText;
const hemWidth = getTextWidth(testText, "x-large Scheherazade");
// If this hemistich's width is a new maximum, update
if (hemWidth > maxWidth) {
maxWidth = hemWidth;
}
}
// Make sure we got an actual max width before doing anything else
if (maxWidth !== 0) {
// Round up maxWidth, and make it into a string with a px value for CSS
const pixelWidth = Math.ceil(maxWidth) + "px";
// Finally, update CSS custom property
document.documentElement.style.setProperty(
"--hemistich-width",
pixelWidth
);
}
}
window.onload = (event) => {
fixup();
};
</script>
<div id="t6e-footer">
به همت <a href="https://www.theobeers.com/about">Theo Beers</a> | <a href="@Model.Poem.FullUrl">برگشت به @Model.Poem.FullTitle</a>
</div>
}
</body>
</html>

View File

@ -0,0 +1,57 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using RMuseum.Models.Ganjoor.ViewModels;
using RMuseum.Models.GanjoorAudio.ViewModels;
namespace GanjooRazor.Pages
{
public class t6eModel : PageModel
{
/// <summary>
/// poem
/// </summary>
public GanjoorPoemCompleteViewModel Poem { get; set; }
/// <summary>
/// last error
/// </summary>
public string LastError { get; set; }
public async Task<IActionResult> OnGetAsync()
{
var responsePoem = await _httpClient.GetAsync($"{APIRoot.Url}/api/ganjoor/poem/{Request.Query["p"]}?verseDetails=true&catInfo=false&rhymes=false&recitations=false&images=false&songs=false&comments=false&navigation=false");
if (!responsePoem.IsSuccessStatusCode)
{
LastError = JsonConvert.DeserializeObject<string>(await responsePoem.Content.ReadAsStringAsync());
return Page();
}
Poem = JsonConvert.DeserializeObject<GanjoorPoemCompleteViewModel>(await responsePoem.Content.ReadAsStringAsync());
return Page();
}
/// <summary>
/// HttpClient instance
/// </summary>
private readonly HttpClient _httpClient;
/// <summary>
/// constructor
/// </summary>
/// <param name="httpClient"></param>
/// <param name="configuration"></param>
public t6eModel(HttpClient httpClient)
{
_httpClient = httpClient;
}
}
}

View File

@ -8,8 +8,8 @@
},
"AllowedHosts": "*",
"GoogleAnalyticsCode": "",
"APIRoot": "http://localhost:3439",
"GlobalAPIRoot": "http://localhost:3439",
"APIRoot": "https://api.ganjoor.net",
"GlobalAPIRoot": "https://api.ganjoor.net",
"SiteUrl": "http://localhost:33081",
"MockSpotify": "False",
"Spotify": {

View File

@ -1603,6 +1603,10 @@ audio {
content: 'delete'
}
.menu-book::after {
content: 'menu_book'
}
.visible-notification-badge {
position: absolute;

View File

@ -0,0 +1,89 @@
:root {
--hemistich-width: auto;
}
body {
margin: auto;
max-width: calc((var(--hemistich-width) * 2) + 10ch);
padding: 2ch 1ch;
}
p {
font-family: "Scheherazade", serif;
font-size: x-large;
margin: 0;
text-align-last: justify;
}
.b {
display: flex;
flex-flow: row wrap;
}
.final-line {
align-items: center;
display: flex;
flex-flow: column nowrap;
margin-right: 5.5ch;
margin-top: 0.4rem;
}
.line-number {
width: 5.5ch;
}
.m1,
.m2 {
width: var(--hemistich-width);
}
.separator {
width: 4.5ch;
}
#title-block-header {
display: none;
}
@media screen and (max-width: 767px) {
p {
text-align-last: auto;
}
.b,
.final-line {
display: block;
}
.final-line {
margin: 0;
}
.line-number {
display: none;
}
.m1,
.m2 {
width: auto;
}
.m2 {
background-color: #e8e8e8;
border-radius: 4px;
padding-right: 2ch;
}
.separator {
display: none;
}
}
#t6e-footer {
margin-left: auto;
margin-right: auto;
margin-bottom: 5px;
margin-top: 50px;
border-top: 1px dotted #000;
font-size: small;
}