Przeglądaj źródła

Progress on styled RSS and replacement emoji picker.

George Baugh 2 lat temu
rodzic
commit
5815e93fb6

+ 1 - 2
.gitignore

@@ -11,8 +11,7 @@ nytprof*
 www/nytprof
 pm_to_blib
 pod2htmd.tmp
-fgEmojiPicker.js
-full-emoji-list.json
+list.min.json
 highlight.min.js
 obsidian.min.css
 www/.well_known

+ 1 - 2
Makefile

@@ -51,8 +51,7 @@ prereq-node:
 .PHONY: prereq-frontend
 prereq-frontend:
 	mkdir -p www/scripts; pushd www/scripts && curl -L --remote-name-all                                 \
-		"https://raw.githubusercontent.com/woody180/vanilla-javascript-emoji-picker/e357923d49fcc23f17cf1727045e802f765969cd/fgEmojiPicker.js"     \
-		"https://github.com/woody180/vanilla-javascript-emoji-picker/blob/e357923d49fcc23f17cf1727045e802f765969cd/full-emoji-list.json" \
+		"https://raw.githubusercontent.com/chalda-pnuzig/emojis.json/master/dist/list.min.json"     \
 		"https://raw.githubusercontent.com/highlightjs/cdn-release/main/build/highlight.min.js"; popd
 	mkdir -p www/styles; cd www/styles && curl -L --remote-name-all \
 		"https://raw.githubusercontent.com/highlightjs/cdn-release/main/build/styles/obsidian.min.css"

+ 1 - 0
Makefile.PL

@@ -59,6 +59,7 @@ WriteMakefile(
     'Digest::SHA'               => '0',
     'MIME::Base32::XS'          => '0',
     'URI'                       => '0',
+    'FindBin::libs'             => '0',
   },
   test => {TESTS => 't/*.t'}
 );

+ 2 - 2
lib/TCMS.pm

@@ -25,7 +25,7 @@ use UUID::Tiny();
 use URI();
 
 #Grab our custom routes
-use lib 'lib';
+use FindBin::libs;
 use Trog::Routes::HTML;
 use Trog::Routes::JSON;
 
@@ -40,7 +40,6 @@ use Trog::FileHandler;
 # Troglodyne philosophy - simple as possible
 
 # Import the routes
-
 my $conf  = Trog::Config::get();
 my $data  = Trog::Data->new($conf);
 my %roots = $data->routes();
@@ -227,6 +226,7 @@ sub app {
     $query->{social_meta}  = 1;
     $query->{primary_post} = {};
     $query->{has_query}    = $has_query;
+    $query->{port}         = $env->{HTTP_X_FORWARDED_PORT} // $env->{HTTP_PORT};
     # Redirecting somewhere naughty not allow
     $query->{to}           = URI->new($query->{to} // '')->path() || $query->{to} if $query->{to};
 

+ 39 - 12
lib/Trog/Routes/HTML.pm

@@ -190,7 +190,12 @@ our %routes = (
         method   => 'GET',
         callback => \&Trog::Routes::HTML::posts,
         data     => { format => 'rss' },
-    }
+    },
+    '/emoji' => {
+        method => 'GET',
+        callback => \&Trog::Routes::HTML::emojis,
+        auth => 1,
+    },
 );
 
 # Grab theme routes
@@ -944,7 +949,10 @@ sub posts ( $query, $direct = 0 ) {
     # Set the eTag so that we don't get a re-fetch
     $query->{etag} = "$posts[0]{id}-$posts[0]{version}" if @posts;
 
-    return _rss( $query, \@posts ) if $fmt eq 'rss';
+    #Correct page headers
+    my $ph = $themed ? _themed_title( $query->{route} ) : $query->{route};
+
+    return _rss( $query, $ph, \@posts ) if $fmt eq 'rss';
 
     #XXX Is used by the sitemap, maybe just fix there?
     my @post_aliases = map { $_->{local_href} } _get_series();
@@ -959,9 +967,6 @@ sub posts ( $query, $direct = 0 ) {
 
     my $styles = _build_themed_styles('posts.css');
 
-    #Correct page headers
-    my $ph = $themed ? _themed_title( $query->{route} ) : $query->{route};
-
     # Build page title if it wasn't set by a wrapping sub
     $query->{title} = "$query->{domain} : $query->{title}" if $query->{title} && $query->{domain};
     $query->{title} ||= @$tags && $query->{domain} ? "$query->{domain} : @$tags" : undef;
@@ -1258,12 +1263,13 @@ sub sitemap ($query) {
     return Trog::Routes::HTML::index( $query, $content, $styles );
 }
 
-sub _rss ( $query, $posts ) {
+sub _rss ( $query, $subtitle, $posts ) {
     require XML::RSS;
     my $rss = XML::RSS->new( version => '2.0', stylesheet => '/styles/rss-style.xsl' );
     my $now = DateTime->from_epoch( epoch => time() );
     $rss->channel(
         title         => "$query->{domain}",
+        subtitle      => $subtitle,
         link          => "http://$query->{domain}/$query->{route}.rss.xml",
         language      => 'en',                                                   #TODO localization
         description   => "$query->{domain} : $query->{route}",
@@ -1294,9 +1300,9 @@ sub _rss ( $query, $posts ) {
         undef,
         {
             etag => $query->{etag},
-            contenttype => "application/rss+xml",
+            contenttype => "application/xml",
             body => encode_utf8( $rss->as_string ),
-            scheme => $query->{scheme}
+            scheme => $query->{scheme},
         },
         'Content-Disposition' => 'inline; filename="rss.xml"',
     );
@@ -1426,12 +1432,16 @@ sub themed_render ( $template, $data ) {
 }
 
 sub _pick_processor ( $file, $normal, $themed ) {
-    return _dir_for_resource($file) eq $template_dir ? $normal : $themed;
+    return _template_dir($file) eq $template_dir ? $normal : $themed;
+}
+
+sub _template_dir ($template) {
+    return $theme_dir && -f "www/$theme_dir/$template" ? $theme_dir : $template_dir;
 }
 
 # Pick appropriate dir based on whether theme override exists
 sub _dir_for_resource ($resource) {
-    return $theme_dir && -f "www/$theme_dir/$resource" ? $theme_dir : $template_dir;
+    return $theme_dir && -f "www/$theme_dir/$resource" ? $theme_dir : '';
 }
 
 sub _themed_style ($resource) {
@@ -1487,9 +1497,9 @@ sub finish_render ( $template, $vars, %headers ) {
     $headers{'Referrer-Policy'} = 'no-referrer-when-downgrade';
 
     #CSP. Yet another layer of 'no mixed content' plus whitelisted execution of remote resources.
-    my $scheme = $vars->{scheme} ? $vars->{scheme} : '';
+    my $scheme = $vars->{scheme} ? "$vars->{scheme}:" : '';
     my $sites = $conf->param('security.allow_embeds_from') // '';
-    $headers{'Content-Security-Policy'} .= ";default-src '$scheme' 'self' 'unsafe-eval' 'unsafe-inline' $sites";
+    $headers{'Content-Security-Policy'} .= ";default-src $scheme 'self' 'unsafe-eval' 'unsafe-inline' $sites";
     $headers{'Content-Security-Policy'} .= ";object-src 'none'";
 
     # Force https if we are https
@@ -1542,6 +1552,8 @@ sub icon ($query) {
 
 # TODO make statics, abstract gzipped outputting & header handling
 sub rss_style ($query) {
+    $query->{port} = ":$query->{port}" if $query->{port};
+    $query->{rss_css} = _themed_style("rss.css");
     my $body = encode_utf8(themed_render('rss-style.tx', $query));
     my %headers = (
         'Content-Type'   => 'text/xsl',
@@ -1561,4 +1573,19 @@ sub rss_style ($query) {
     return [ 200, [%headers], [$dfh] ];
 }
 
+sub emojis ($query) {
+    my $file = 'www/scripts/list.min.json';
+    die "Run make prereq-frontend first" unless -f $file;
+
+    my $raw = File::Slurper::read_binary($file);
+    my $emojis = Cpanel::JSON::XS::decode_json($raw);
+    my %categorized;
+    foreach my $emoji (@{$emojis->{emojis}}) {
+        $categorized{$emoji->{category}} //= [];
+        push(@{$categorized{$emoji->{category}}}, $emoji->{emoji});
+    }
+
+    return finish_render('emojis.tx', { %$query, categories => \%categorized, scripts => _build_themed_scripts('emoji.js') });
+}
+
 1;

+ 21 - 0
www/scripts/emoji.js

@@ -0,0 +1,21 @@
+function switchEmojiDropDown (e) {
+    var panes = document.querySelectorAll('.mojipane');
+    for (pane of panes) {
+        pane.style.display="none";
+    }
+
+    var theId = e.target.value;
+    var el = document.getElementById(theId);
+    if ( el === null ) {
+        console.log('no such element '+el);
+        return;
+    }
+    el.style.display = 'inline-block';
+}
+
+window.onload = function () {
+    var cat = document.getElementById('emoji-category');
+    cat.addEventListener("change", switchEmojiDropDown);
+    const ev = new Event("change");
+    cat.dispatchEvent(ev);
+}

+ 1 - 0
www/scripts/main.js

@@ -0,0 +1 @@
+

+ 5 - 1
www/scripts/post.js

@@ -1,9 +1,13 @@
 function switchMenu(obj) {
     var el = document.getElementById(obj);
+    if ( el === null ) {
+        console.log('no such element '+el);
+        return;
+    }
     if ( el.style.display != 'none' ) {
         el.style.display = 'none';
     } else {
-        el.style.display = '';
+        el.style.display = 'inline-block';
     }
 }
 

+ 122 - 0
www/styles/rss.css

@@ -0,0 +1,122 @@
+@charset "UTF-8";
+
+:root,[data-theme=default]{
+    --color-accent:#783cb9;
+    --color-text-default:#1f303e;
+    --color-text-offset:#686c71;
+    --color-text-accent:var(--color-accent);
+    --color-text-interaction:#005aff;
+    --color-text-success:#4d7500;
+    --color-text-danger:#d22006;
+    --color-background-default:#fff;
+    --color-background-offset:#f1f3f6;
+    --color-background-success:#ddf9c7;
+    --color-background-warning:#fef2e4;
+    --color-background-danger:#fff3f2;
+    --color-background-info:#edf5ff;
+    --color-background-disabled:#e6e6e2;
+    --color-border-default:#dfe1e2;
+    --color-border-success:#7d9b4e;
+    --color-border-warning:#dd7533;
+    --color-border-danger:#e9695f;
+    --color-border-info:#4f97d1;
+    --color-focus-ring:hsla(219, 100%, 50%, 0.5);
+    --color-box-shadow:rgba(0, 0, 0, 0.1);
+    --color-backdrop:rgba(255, 255, 255, 0.6);
+}
+
+
+[data-theme=dark]{
+    color-scheme:dark;
+    --color-accent:#aacdec;
+    --color-text-default:#fff;
+    --color-text-offset:#c9c9c9;
+    --color-text-accent:var(--color-accent);
+    --color-text-interaction:#ffbe2e;
+    --color-text-success:#a3b72c;
+    --color-text-danger:#ff8d7b;
+    --color-background-default:#2d2e2f;
+    --color-background-offset:#1c1d1f;
+    --color-background-success:#3c4a29;
+    --color-background-warning:#614527;
+    --color-background-danger:#6f3331;
+    --color-background-info:#2f4668;
+    --color-background-disabled:#454540;
+    --color-border-default:#5d5d52;
+    --color-border-success:#7d9b4e;
+    --color-border-warning:#dd7533;
+    --color-border-danger:#e9695f;
+    --color-border-info:#4f97d1;
+    --color-focus-ring:#c2850c;
+    --color-box-shadow:rgba(0, 0, 0, 0.5);
+    --color-backdrop:rgba(0, 0, 0, 0.6);
+}
+html{
+    word-wrap:break-word
+}
+h1{
+    font-size:3.8rem;
+    line-height:1;
+    font-weight:800;
+    margin-bottom:4rem
+}
+h2{
+    font-size:3rem;
+    line-height:1.2;
+    font-weight:700;
+    margin-bottom:3rem
+}
+h2:not(:first-child){
+    margin-top:5.8rem
+}
+hr+h2:not(:first-child){
+    margin-top:4rem
+}
+h3{
+    font-size:2.4rem;
+    line-height:1.25;
+    font-weight:500;
+    margin-top:4.2rem;
+    margin-bottom:1.8rem
+}
+h4{
+    font-size:2rem;
+    line-height:1.35;
+    font-weight:500;
+    margin-top:3.2rem;
+    margin-bottom:1.8rem
+}
+.layout-content{
+max-width:var(--content-max-width);
+padding-inline:var(--content-horizontal-padding-xs)
+}
+@media (min-width:768px){
+.layout-content{
+padding-inline:var(--content-horizontal-padding-md)
+}
+
+dk-alert-box{
+display:block;
+margin:3rem 0;
+padding:2rem 3rem;
+border:1px solid var(--alert-border);
+border-left-width:.5rem;
+border-radius:.4rem;
+background-color:var(--alert-background)
+}
+dk-alert-box[type=info]{
+--alert-border:var(--color-border-info);
+--alert-background:var(--color-background-info)
+}
+dk-alert-box[type=warning]{
+--alert-border:var(--color-border-warning);
+--alert-background:var(--color-background-warning)
+}
+dk-alert-box[type=danger]{
+--alert-border:var(--color-border-danger);
+--alert-background:var(--color-background-danger)
+}
+dk-alert-box[type=success]{
+--alert-border:var(--color-border-success);
+--alert-background:var(--color-background-success)
+}

+ 32 - 0
www/styles/screen.css

@@ -199,6 +199,16 @@ span#clickme:hover {
  background-color: #333;
  width: 100%;
 }
+.cooltab {
+    box-shadow: 0 0 .5em black;
+    background-color: #333;
+    cursor:pointer;
+    border-color: gray;
+    box-sizing: border-box;
+    border-radius: .5em;
+    border: .25em solid black;
+    color: white;
+}
 .coolcb {
     height: 1.5rem !important;
     width: 1.5rem !important;
@@ -303,6 +313,9 @@ p.posteditortitle {
 #newpostlink {
  color: #990000;
 }
+.hidon {
+    display:none;
+}
 /*Responsive design stuff that used to be in JS, modify as needed*/
 @media (max-width: 1024px) {
   div#midtitle {
@@ -456,3 +469,22 @@ a.tag {
 .postData {
     margin-top: .5rem;
 }
+
+#emojis {
+    width: 30vw;
+    height: 30vh;
+    overflow: scroll;
+}
+#emoji-container {
+    border-radius: 1rem;
+    background: #e4e4e4;
+    border-width: 1px;
+    border-style: solid;
+    border-color: grey;
+    text-decoration: none;
+    text-shadow 0 0 2px grey;
+    font-size: 1rem;
+    width: 30vw;
+    text-align: center;
+    padding: .25rem;
+}

+ 7 - 0
www/styles/structure.css

@@ -57,6 +57,13 @@ body {
  width: 100%;
  padding-bottom: 2.5em;
 }
+.kontable {
+    display "table";
+    width: 100%;
+}
+.kontrow {
+    display: table-row;
+}
 .kontained {
  display: table-cell;
 }

+ 18 - 0
www/templates/emojis.tx

@@ -0,0 +1,18 @@
+<div id="emoji-container">
+    <select id="emoji-category" class="mojitab" >
+    : for $categories.keys() -> $category {
+        <option value="<: $category :>"><: $category :></option>
+    : }
+    </select>
+    <div id="emojis">
+    : for $categories.keys() -> $category {
+        <span id="<: $category :>" class="mojipane" style="display:none">
+    :   for $categories[$category] -> $emoji {
+            <span>
+            <: $emoji :>
+            </span>
+    :   }
+        </span>
+    : }
+    </div>
+</div>

+ 1 - 1
www/templates/form_common.tx

@@ -8,7 +8,7 @@ Add Post Alias:<br />
 <input class="cooltext" type="text" id="<: $post.id :>-customalias" placeholder="/tickle" />
 <button style="float:right;" onclick="add2aliases('<: $post.id :>'); return false;" class="coolbutton" >Add</button>
 
-Content <button class="coolbutton emojiPicker">😎</button>:
+Content <button type="button" class="coolbutton emojiPicker">😎</button>:
 <br /><textarea class="cooltext" name="data" placeholder="Potzrebie"><: $post.data :></textarea>
 <input type="hidden" name="app" value="<: $app :>" />
 <input type="hidden" name="to"  value="<: $route :>" />

+ 1 - 0
www/templates/posts.tx

@@ -10,6 +10,7 @@
             trigger: ['button.emojiPicker'],
             position: ['bottom'],
             dir: `/scripts/`,
+            preFetch: true,
             emit(obj, triggerElement) {
                 const emoji = obj.emoji;
                 document.querySelector('textarea').value += emoji;

+ 2 - 2
www/templates/rss-style.tx

@@ -7,12 +7,12 @@
       <head>
         <title>
           RSS Feed |
-          <xsl:value-of select="/atom:feed/atom:title"/>
+          <xsl:value-of select="/channel:feed/channel:title"/>
         </title>
         <meta charset="utf-8"/>
         <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
         <meta name="viewport" content="width=device-width, initial-scale=1"/>
-        <link rel="stylesheet" href="/assets/styles.css"/>
+        <link rel="stylesheet" href="<: $rss_css :>"/>
       </head>
       <body>
         <main class="layout-content">