Compare commits

...

23 Commits

Author SHA1 Message Date
httpjamesm 6f86cbce6e feat: update version num to 1.3 2022-12-28 22:55:42 -05:00
httpjamesm 1d2e98e4c1 style: add margin between comments and divider 2022-12-28 22:55:30 -05:00
httpjamesm 599d23544b feat: unify comments finder, show post comments
style: show post notices in a clean layout
2022-12-28 22:54:13 -05:00
httpjamesm 84ba0886cd feat: show answer comments under collapsible 2022-12-28 22:48:02 -05:00
httpjamesm 5bd9ce484f fix: escape code blocks to prevent HTML injection 2022-12-28 22:18:18 -05:00
httpjamesm 8f9091fb2a docs: add chroma to attribution 2022-12-28 19:20:58 -05:00
httpjamesm 1b1120d924 docs: attribution with licenses 2022-12-28 19:19:53 -05:00
httpjamesm a327366400 feat: version 1.2 2022-12-28 19:15:18 -05:00
httpjamesm 97e2e50015 fix: remove debug statements 2022-12-28 19:10:27 -05:00
httpjamesm 96d4f768d9 feat: syntax highlighting for question codeblocks 2022-12-28 19:10:14 -05:00
httpjamesm 14b11b7f14 style: fix syntax highlighting in light mode 2022-12-28 18:52:38 -05:00
httpjamesm 631a700c9f feat: highlight code blocks within answers 2022-12-28 18:51:14 -05:00
httpjamesm da57f98fec docs: bookmark tool 2022-12-28 17:47:55 -05:00
httpjamesm b68786a50f Merge pull request #4 from privacytime101/main
docs: Create bug_report.md
2022-12-28 17:01:34 -05:00
Whatever Social 819a8fe39f Create bug_report.md 2022-12-28 14:00:46 -08:00
httpjamesm 0d5f0a04f1 docs: add about text 2022-12-28 16:47:18 -05:00
httpjamesm 46545385e1 docs: rename new_instance template to md 2022-12-28 16:46:40 -05:00
httpjamesm ef723a0c21 Merge branch 'main' of https://github.com/privacytime101/AnonymousOverflow into privacytime101-main 2022-12-28 16:42:55 -05:00
Whatever Social 0e2e8b26f6 Create new_instance.yml 2022-12-28 13:39:37 -08:00
Whatever Social 5a1e1ca652 Add vern.cc 2022-12-28 13:32:05 -08:00
httpjamesm 5373b9d979 docs: add vern instance 2022-12-28 16:26:01 -05:00
httpjamesm a3b69f37a2 docs: jae 777.tf instance 2022-12-28 15:51:23 -05:00
httpjamesm f9025ff9cc fix: no cache middleware to prevent visual bugs 2022-12-28 14:14:30 -05:00
15 changed files with 399 additions and 20 deletions
+35
View File
@@ -0,0 +1,35 @@
---
name: Bug report
about: 'Create a report to help us improve'
title: ''
labels: ''
assignees: ''
---
Please make sure you're on the latest version before submitting.
# What's Happening?
<!-- Describe here -->
## How to reproduce:
<!-- Describe here -->
## Affected Platforms:
- [ ] macOS
- [ ] Windows
- [ ] Linux (Specify)
- [ ] iOS
- [ ] Android
Version:
## Browser:
- [ ] Chromium-based (ex: Brave or Chrome)
- [ ] Webkit-based (ex: Safari)
- [ ] Gecko-based (ex: Firefox)
+12
View File
@@ -0,0 +1,12 @@
---
name: New Instance
about: 'Add my public instance to the list'
title: "[INSTANCE] New public instance"
labels: ''
assignees: ''
---
Instance URL:
Region (Written Out - ex United States):
Operated by (Link to your site):
+34 -3
View File
@@ -12,11 +12,20 @@ This project is super lightweight by design. The UI is simple and the frontend i
![Answer](https://cdn.horizon.pics/0RwQtrxH3COTC9sfo0FsQ56I3Opl0m.png)
## Instances
## Clearnet Instances
| Instance URL | Region | Notes |
|------------------------------------------------------|-------------------------|--------------------------------------------------------------------------------------------------|
| ---------------------------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------ |
| [code.whatever.social](https://code.whatever.social) | United States & Germany | Operated by [Whatever Social](https://whatever.social) and [http.james](https://httpjames.space) |
| [overflow.777.tf](https://overflow.777.tf/) | The Netherlands | Operated by [Jae](https://777.tf) |
| [ao.vern.cc](https://ao.vern.cc) | United States | Operated by [vern.cc](https://vern.cc) |
## Other Instances
| Instance URL | Region | Notes |
| --------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -------------------------------------- |
| [ao.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion](http://ao.vernccvbvyi5qhfzyqengccj7lkove6bjot2xhh5kajhwvidqafczrad.onion) | United States | Operated by [vern.cc](https://vern.cc) |
| [vernmzgraj6aaoafmehupvtkkynpaa67rxcdj2kinwiy6konn6rq.b32.i2p](http://vernmzgraj6aaoafmehupvtkkynpaa67rxcdj2kinwiy6konn6rq.b32.i2p) | United States | Operated by [vern.cc](https://vern.cc) |
## How it works
@@ -34,6 +43,24 @@ becomes
${instanceURL}/questions/43743250/using-libsodium-xchacha20-poly1305-for-large-files
```
### Bookmark Conversion Tool
You can easily convert StackOverflow URLs to AnonymousOverflow ones by adding the following code as a bookmark in your web browser:
```js
javascript: (function () {
window.location = window.location
.toString()
.replace(/stackoverflow\.com/, "code.whatever.social");
})();
```
Replace `code.whatever.social` with the domain name of the instance you're using if needed.
You can run this bookmarklet on any StackOverflow page to view it anonymously.
Thanks to [Manav from ente.io](https://ente.io/about) for the handy tool.
## How to deploy
AnonymousOverflow uses Docker for deployment.
@@ -46,4 +73,8 @@ Run `docker compose up -d` to build and start the container.
## Attribution
- Icons provided by [heroicons](https://heroicons.com) under the [MIT License](https://choosealicense.com/licenses/mit/)
- Icons provided by [heroicons](https://heroicons.com) under the [MIT License](https://choosealicense.com/licenses/mit/)
- [Gin](https://github.com/gin-gonic/gin) under the [MIT License](https://github.com/gin-gonic/gin/blob/master/LICENSE)
- [goquery](https://github.com/PuerkitoBio/goquery) under the [BSD 3-Clause License](https://github.com/PuerkitoBio/goquery/blob/master/LICENSE)
- [resty](https://github.com/go-resty/resty) under the [MIT License](https://github.com/go-resty/resty/blob/master/LICENSE)
- [Chroma](https://github.com/alecthomas/chroma) under the [MIT License](https://github.com/alecthomas/chroma/blob/master/COPYING)
+1 -1
View File
@@ -1,3 +1,3 @@
package config
var Version = "1.1"
var Version = "1.3"
+8 -3
View File
@@ -3,14 +3,19 @@ module anonymousoverflow
go 1.19
require (
github.com/PuerkitoBio/goquery v1.8.0 // indirect
github.com/PuerkitoBio/goquery v1.8.0
github.com/alecthomas/chroma v0.10.0
github.com/gin-gonic/gin v1.8.2
github.com/go-resty/resty/v2 v2.7.0
)
require (
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.8.2 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/go-resty/resty/v2 v2.7.0 // indirect
github.com/goccy/go-json v0.10.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
+16 -1
View File
@@ -1,14 +1,21 @@
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.8.2 h1:UzKToD9/PoFj/V4rvlKqTRKnQYyz8Sc1MJlv4JHPtvY=
github.com/gin-gonic/gin v1.8.2/go.mod h1:qw5AYuDrzRTnhvusDsrov+fDIxp9Dleuu12h8nfB398=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
@@ -21,15 +28,18 @@ github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSM
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
@@ -43,8 +53,10 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -54,6 +66,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/ugorji/go/codec v1.2.8 h1:sgBJS6COt0b/P40VouWKdseidkDgHxYGm0SAglUHfP0=
github.com/ugorji/go/codec v1.2.8/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
@@ -61,7 +74,6 @@ golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb h1:pirldcYWx7rx7kE5r+9WsOXPXK0+WH5+uZ7uPmJ44uM=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
@@ -79,16 +91,19 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+1
View File
@@ -35,6 +35,7 @@ func main() {
r.Static("/static", "./public")
r.Use(gin.Recovery())
r.Use(middleware.NoCacheMiddleware())
r.Use(middleware.OptionsMiddleware())
r.Use(middleware.Ratelimit())
+5 -1
View File
@@ -14,7 +14,7 @@
--main-bg: rgb(219, 219, 219);
--text-color: #000;
--muted-text-color: #636363;
--code-bg: #b5b5b5;
--code-bg: #36383d;
--input-bg: rgb(188, 188, 188);
--input-bg-hover: rgb(168, 168, 168);
--meta-bg: rgb(170, 168, 168);
@@ -47,3 +47,7 @@ html {
border-radius: 50%;
padding: .25rem;
}
details {
cursor: pointer;
}
+38 -8
View File
@@ -8,7 +8,7 @@ body {
background-color: var(--main-bg);
color: var(--text-color);
font-family: sans-serif;
display: flex;
justify-content: center;
@@ -31,9 +31,9 @@ body {
code {
background-color: var(--code-bg);
padding: .15rem;
padding: 0.15rem;
border-radius: 5px;
color: var(--text-color);
color: white;
}
pre {
@@ -45,15 +45,17 @@ pre {
line-height: 1.35;
}
.timestamp {
color: var(--muted-text-color);
font-size: 0.8rem;
}
.answer-divider {
.post-divider, .answer-divider {
margin-top: 3rem;
margin-bottom: 3rem;
}
.answer-divider {
border: 0;
height: 1px;
background-color: var(--divider-color);
@@ -85,10 +87,10 @@ img {
.answer-author {
width: fit-content;
background-color: var(--meta-bg);
padding: .5rem;
padding: 0.5rem;
border-radius: 5px;
text-align: right;
font-size: .8rem;
font-size: 0.8rem;
}
.logo-link {
@@ -100,9 +102,37 @@ img {
height: 2rem;
}
.comments-parent {
display: flex;
flex-direction: column;
gap: 1rem;
margin-top: 1rem;
}
.comment-parent {
cursor: text;
}
.comment-body {
font-size: 0.95rem;
}
.comment-author {
color: var(--muted-text-color);
font-size: 0.8rem;
}
.s-notice {
background-color: var(--meta-bg);
padding: 1rem;
border-radius: 5px;
color: var(--text-color);
margin-bottom: 1rem;
}
@media only screen and (max-width: 800px) {
body {
padding-left: 1rem;
padding-right: 1rem;
}
}
}
+60
View File
@@ -0,0 +1,60 @@
/* Background */ .bg { color: #f8f8f2; background-color: #272822; }
/* Error */ .err { color: #960050; background-color: #1e0010 }
/* LineTableTD */ .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; }
/* LineHighlight */ .hl { background-color: #3c3d38 }
/* LineNumbersTable */ .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Line */ .line { display: flex; }
/* Keyword */ .k { color: #66d9ef }
/* KeywordConstant */ .kc { color: #66d9ef }
/* KeywordDeclaration */ .kd { color: #66d9ef }
/* KeywordNamespace */ .kn { color: #f92672 }
/* KeywordPseudo */ .kp { color: #66d9ef }
/* KeywordReserved */ .kr { color: #66d9ef }
/* KeywordType */ .kt { color: #66d9ef }
/* NameAttribute */ .na { color: #a6e22e }
/* NameClass */ .nc { color: #a6e22e }
/* NameConstant */ .no { color: #66d9ef }
/* NameDecorator */ .nd { color: #a6e22e }
/* NameException */ .ne { color: #a6e22e }
/* NameFunction */ .nf { color: #a6e22e }
/* NameOther */ .nx { color: #a6e22e }
/* NameTag */ .nt { color: #f92672 }
/* Literal */ .l { color: #ae81ff }
/* LiteralDate */ .ld { color: #e6db74 }
/* LiteralString */ .s { color: #e6db74 }
/* LiteralStringAffix */ .sa { color: #e6db74 }
/* LiteralStringBacktick */ .sb { color: #e6db74 }
/* LiteralStringChar */ .sc { color: #e6db74 }
/* LiteralStringDelimiter */ .dl { color: #e6db74 }
/* LiteralStringDoc */ .sd { color: #e6db74 }
/* LiteralStringDouble */ .s2 { color: #e6db74 }
/* LiteralStringEscape */ .se { color: #ae81ff }
/* LiteralStringHeredoc */ .sh { color: #e6db74 }
/* LiteralStringInterpol */ .si { color: #e6db74 }
/* LiteralStringOther */ .sx { color: #e6db74 }
/* LiteralStringRegex */ .sr { color: #e6db74 }
/* LiteralStringSingle */ .s1 { color: #e6db74 }
/* LiteralStringSymbol */ .ss { color: #e6db74 }
/* LiteralNumber */ .m { color: #ae81ff }
/* LiteralNumberBin */ .mb { color: #ae81ff }
/* LiteralNumberFloat */ .mf { color: #ae81ff }
/* LiteralNumberHex */ .mh { color: #ae81ff }
/* LiteralNumberInteger */ .mi { color: #ae81ff }
/* LiteralNumberIntegerLong */ .il { color: #ae81ff }
/* LiteralNumberOct */ .mo { color: #ae81ff }
/* Operator */ .o { color: #f92672 }
/* OperatorWord */ .ow { color: #f92672 }
/* Comment */ .c { color: #75715e }
/* CommentHashbang */ .ch { color: #75715e }
/* CommentMultiline */ .cm { color: #75715e }
/* CommentSingle */ .c1 { color: #75715e }
/* CommentSpecial */ .cs { color: #75715e }
/* CommentPreproc */ .cp { color: #75715e }
/* CommentPreprocFile */ .cpf { color: #75715e }
/* GenericDeleted */ .gd { color: #f92672 }
/* GenericEmph */ .ge { font-style: italic }
/* GenericInserted */ .gi { color: #a6e22e }
/* GenericStrong */ .gs { font-weight: bold }
/* GenericSubheading */ .gu { color: #75715e }
+12
View File
@@ -0,0 +1,12 @@
package middleware
import "github.com/gin-gonic/gin"
func NoCacheMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("Cache-Control", "no-cache, no-store, must-revalidate")
c.Header("Pragma", "no-cache")
c.Header("Expires", "0")
c.Next()
}
}
+35 -2
View File
@@ -1,9 +1,11 @@
package routes
import (
"anonymousoverflow/src/utils"
"fmt"
"html/template"
"os"
"regexp"
"strings"
"github.com/PuerkitoBio/goquery"
@@ -11,6 +13,9 @@ import (
"github.com/go-resty/resty/v2"
)
var codeBlockRegex = regexp.MustCompile(`(?s)<pre><code>(.+?)<\/code><\/pre>`)
var questionCodeBlockRegex = regexp.MustCompile(`(?s)<pre class=".+"><code( class=".+")?>(.+?)</code></pre>`)
func ViewQuestion(c *gin.Context) {
client := resty.New()
@@ -37,6 +42,8 @@ func ViewQuestion(c *gin.Context) {
questionText := questionTextParent.Children().First().Text()
questionPostLayout := doc.Find("div.post-layout").First()
questionBodyParent := doc.Find("div.s-prose")
questionBodyParentHTML, err := questionBodyParent.Html()
@@ -44,6 +51,20 @@ func ViewQuestion(c *gin.Context) {
panic(err)
}
questionBodyParentHTML = utils.FindAndReturnComments(questionBodyParentHTML, questionPostLayout)
// parse any code blocks and highlight them
answerCodeBlocks := questionCodeBlockRegex.FindAllString(questionBodyParentHTML, -1)
for _, codeBlock := range answerCodeBlocks {
codeBlock = utils.StripBlockTags(codeBlock)
// syntax highlight
highlightedCodeBlock := utils.HighlightSyntaxViaContent(codeBlock)
// replace the code block with the highlighted code block
questionBodyParentHTML = strings.Replace(questionBodyParentHTML, codeBlock, highlightedCodeBlock, 1)
}
questionCard := doc.Find("div.postcell")
questionMetadata := questionCard.Find("div.user-info")
@@ -135,9 +156,21 @@ func ViewQuestion(c *gin.Context) {
})
// append <div class="answer-author">Answered %s by %s</div> to the bottom of the answer
answerBodyHTML += fmt.Sprintf(`<div class="answer-author-parent"><div class="answer-author">Answered at %s by <a href="https://stackoverflow.com/%s" target="_blank" rel="noopener noreferrer">%s</a></div></div>`, answerTimestamp, answerAuthorURL, answerAuthorName)
answerBodyHTML += fmt.Sprintf(`<div class="answer-author-parent"><div class="answer-author">Answered %s by <a href="https://stackoverflow.com/%s" target="_blank" rel="noopener noreferrer">%s</a></div></div>`, answerTimestamp, answerAuthorURL, answerAuthorName)
// get the timestamp and author
// parse any code blocks and highlight them
answerCodeBlocks := codeBlockRegex.FindAllString(answerBodyHTML, -1)
for _, codeBlock := range answerCodeBlocks {
codeBlock = utils.StripBlockTags(codeBlock)
// syntax highlight
highlightedCodeBlock := utils.HighlightSyntaxViaContent(codeBlock)
// replace the code block with the highlighted code block
answerBodyHTML = strings.Replace(answerBodyHTML, codeBlock, highlightedCodeBlock, 1)
}
answerBodyHTML = utils.FindAndReturnComments(answerBodyHTML, postLayout)
answers = append(answers, template.HTML(answerBodyHTML))
})
+58
View File
@@ -0,0 +1,58 @@
package utils
import (
"fmt"
"strings"
"github.com/PuerkitoBio/goquery"
)
func FindAndReturnComments(inHtml string, postLayout *goquery.Selection) (outHtml string) {
outHtml = inHtml
comments := []string{}
commentsComponent := postLayout.Find("div.js-post-comments-component")
commentsList := commentsComponent.Find("div.comments")
commentsList2 := commentsList.Find("ul.comments-list")
allComments := commentsList2.Find("li.comment")
allComments.Each(func(i int, s *goquery.Selection) {
commentText := s.Find("div.comment-text")
commentBody := commentText.Find("div.comment-body")
commentCopy, err := commentBody.Find("span.comment-copy").Html()
if err != nil {
return
}
commentAuthorURL := ""
commentAuthor := commentBody.Find("span.comment-user")
if commentAuthor.Length() == 0 {
commentAuthor = commentBody.Find("a.comment-user")
if commentAuthor.Length() == 0 {
return
}
commentAuthorURL = commentAuthor.AttrOr("href", "")
}
commentTimestamp := commentBody.Find("span.relativetime-clean").Text()
comment := fmt.Sprintf(`<div class="comment-parent"><div class="comment"><div class="comment-body">%s</div><div class="comment-author">Commented %s by <a href="https://stackoverflow.com%s" target="_blank" rel="noopener noreferrer">%s</a>.</div></div></div>`, commentCopy, commentTimestamp, commentAuthorURL, commentAuthor.Text())
comments = append(comments, comment)
})
if len(comments) > 0 {
outHtml = inHtml + fmt.Sprintf(`<details class="comments"><summary>Show <b>%d comments</b></summary><div class="comments-parent">%s</div></details>`, len(comments), strings.Join(comments, ""))
}
return
}
+82
View File
@@ -0,0 +1,82 @@
package utils
import (
"bytes"
"html"
"io"
"regexp"
"strings"
"github.com/alecthomas/chroma/formatters"
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
)
var plainFormattedCodeRegex = regexp.MustCompile(`(?s)<pre tabindex="0" class="chroma"><code>(.+?)</code></pre>`)
func HighlightSyntaxViaContent(content string) (htmlOut string) {
content = html.UnescapeString(content)
fallbackOut := html.EscapeString(content)
// identify the language
lexer := lexers.Analyse(content)
if lexer == nil {
// unable to identify, so just return the wrapped content
htmlOut = fallbackOut
return
}
style := styles.Get("xcode")
if style == nil {
style = styles.Fallback
}
formatter := formatters.Get("html")
if formatter == nil {
formatter = formatters.Fallback
}
iterator, err := lexer.Tokenise(nil, content)
if err != nil {
htmlOut = fallbackOut
return
}
b := bytes.NewBufferString("")
w := io.Writer(b)
err = formatter.Format(w, style, iterator)
if err != nil {
htmlOut = fallbackOut
return
}
// parse only the <pre><code>...</code></pre> part
htmlOut = b.String()
htmlOut = plainFormattedCodeRegex.FindString(htmlOut)
htmlOut = StripBlockTags(htmlOut)
// remove <pre tabindex="0" class="chroma">
htmlOut = strings.Replace(htmlOut, "<pre tabindex=\"0\" class=\"chroma\">", "", -1)
return
}
var preClassRegex = regexp.MustCompile(`(?s)<pre class=".+">`)
func StripBlockTags(content string) (result string) {
// strip all "<code>" tags
content = strings.Replace(content, "<code>", "", -1)
content = strings.Replace(content, "</code>", "", -1)
// and the <pre>
content = strings.Replace(content, "<pre>", "", -1)
content = strings.Replace(content, "</pre>", "", -1)
content = preClassRegex.ReplaceAllString(content, "")
result = content
return
}
+2 -1
View File
@@ -4,6 +4,7 @@
<title>{{ .title }}</title>
<link rel="stylesheet" href="/static/question.css" />
<link rel="stylesheet" href="/static/globals.css" />
<link rel="stylesheet" href="/static/syntax.css" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta
http-equiv="Content-Security-Policy"
@@ -46,7 +47,7 @@
</div>
<div class="card-body">{{ .body }}</div>
</div>
<hr />
<hr class="post-divider" />
<h2>Answers</h2>
{{ range $answer := .answers }}
<div class="answer">{{ $answer }}</div>