├── .DS_Store ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── examples ├── .DS_Store └── index.html ├── screenshot.png └── src ├── default.css └── script.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakhar897/hn-comments-drawer/8963dfc8f15157792e1dee0f635ba4be025f29fb/.DS_Store -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 4, 3 | "editor.detectIndentation": true, 4 | "editor.wordWrap": "on", 5 | "editor.formatOnSave": true, 6 | "editor.defaultFormatter": "esbenp.prettier-vscode", 7 | "editor.codeActionsOnSave": { 8 | "source.fixAll": true 9 | }, 10 | "html.format.enable": true, 11 | "html.format.indentInnerHtml": true, 12 | "html.format.indentHandlebars": true, 13 | "html.format.extraLiners": "head, body, /html", 14 | "html.format.unformatted": "code, pre, tt", 15 | "html.format.wrapAttributes": "force-aligned", 16 | "emmet.includeLanguages": { 17 | "html": "html", 18 | "javascript": "javascriptreact" 19 | }, 20 | "emmet.triggerExpansionOnTab": true, 21 | "files.exclude": { 22 | "**/.git": true, 23 | "**/.DS_Store": true, 24 | "**/*.js.map": true 25 | }, 26 | "[javascript]": { 27 | "editor.tabSize": 4, 28 | "editor.insertSpaces": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Prakhar Gupta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hacker News Comments Drawer (hn-comments-drawer) 2 | 3 | Integrate Hacker News comments and display them beautifully within your websites. 4 | 5 | [See Discussion on this](https://news.ycombinator.com/item?id=38597301) 6 | 7 | ## Demo 8 | 9 | [Live Demo 1](https://softwaredesign.ing/misc/hn-comments-drawer-demo) 10 | 11 | [Live Demo 2](https://softwaredesign.ing/blog/moving-away-from-substack) 12 | 13 | ![Screenshot of the product](https://raw.githubusercontent.com/prakhar897/hn-comments-drawer/main/screenshot.png) 14 | 15 | ## Features 16 | 17 | - Display HN comments using a single line of code. 18 | - Customizable styling for comments. 19 | - Options to vary stuff. 20 | 21 | ## Usage 22 | 23 | 1. Include this snippet in your HTML document: 24 | 25 | `` 26 | 27 | 2. Create an HTML element where you want to display the comments. Use the following format for the ID: 28 | 29 |
32 |
33 | 34 | Replace `38300167` with the actual ID of the Hacker News story for which you want to display comments. 35 | 36 | ## Docs 37 | 38 | - Add maxDepth of comments: 39 | 40 |
44 |
45 | 46 | - Add default styling: 47 | 48 | 49 | 50 | ## Styling 51 | 52 | Customize the styling of the comments by modifying the provided CSS classes in your own stylesheet: 53 | 54 | /* Example of provided CSS classes for comments */ 55 | 56 | .hn-comments-drawer { 57 | list-style-type: none; 58 | margin-left: 0; 59 | padding-left: 20px; 60 | border: 2px solid red; 61 | margin-top: 50px; 62 | margin-bottom: 50px; 63 | 64 | } 65 | 66 | .hn-comments-drawer-heading{ 67 | border: 2px solid red; 68 | } 69 | 70 | .comments-list { 71 | list-style-type: none; /* Remove default list-style dots */ 72 | padding-left: 0; /* Remove default padding */ 73 | } 74 | 75 | .comments-list li { 76 | border-left: 2px solid #ccc; /* Adjust thickness and color as needed */ 77 | padding-left: 10px; /* Adjust left padding for spacing */ 78 | margin-left: 5px; /* Adjust margin for spacing */ 79 | margin-top: 20px; 80 | } 81 | 82 | .comment-text { 83 | color: red; 84 | } 85 | 86 | .comment-header { 87 | color:blue; 88 | } 89 | 90 | .comments-loading { 91 | text-align: center; 92 | padding: 2rem; 93 | } 94 | 95 | ## Examples 96 | 97 | You can find examples in the `examples` folder. 98 | 99 | ## Contributing 100 | 101 | Contributions are welcome! Feel free to open issues or submit pull requests for enhancements or bug fixes. 102 | 103 | ## License 104 | 105 | This project is licensed under the MIT License - see the [LICENSE](https://github.com/prakhar897/hn-comments-drawer/LICENSE) file for details. 106 | -------------------------------------------------------------------------------- /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakhar897/hn-comments-drawer/8963dfc8f15157792e1dee0f635ba4be025f29fb/examples/.DS_Store -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hacker News Comments 6 | 7 | 8 | 9 |

Hacker News Comments

10 | 11 | 12 |

Story 1 Comments

13 |
18 | 19 |

Story 2 Comments

20 |
25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prakhar897/hn-comments-drawer/8963dfc8f15157792e1dee0f635ba4be025f29fb/screenshot.png -------------------------------------------------------------------------------- /src/default.css: -------------------------------------------------------------------------------- 1 | .hn-comments-drawer { 2 | list-style-type: none; 3 | margin-left: 0; 4 | padding-left: 20px; 5 | border: 2px solid red; 6 | margin-top: 50px; 7 | margin-bottom: 50px; 8 | 9 | } 10 | 11 | .hn-comments-drawer-heading{ 12 | color: red; 13 | } 14 | 15 | .comments-list { 16 | list-style-type: none; /* Remove default list-style dots */ 17 | padding-left: 0; /* Remove default padding */ 18 | } 19 | 20 | .comments-list li { 21 | border-left: 2px solid #ccc; /* Adjust thickness and color as needed */ 22 | padding-left: 10px; /* Adjust left padding for spacing */ 23 | margin-left: 5px; /* Adjust margin for spacing */ 24 | margin-top: 20px; 25 | } 26 | 27 | .comment-text { 28 | color: red; 29 | } 30 | 31 | .comment-header { 32 | color:blue; 33 | } 34 | 35 | .comment-text p { 36 | color:blue; 37 | } 38 | 39 | .hn-comments-drawer-footer{ 40 | color: gray; 41 | } 42 | 43 | .comments-loading { 44 | text-align: center; 45 | padding: 2rem; 46 | } 47 | -------------------------------------------------------------------------------- /src/script.js: -------------------------------------------------------------------------------- 1 | // Create a function that fetches comments and displays them 2 | async function displayHNComments( 3 | storyId, 4 | rootElement, 5 | options 6 | ) { 7 | try { 8 | rootElement.innerHTML = "" 9 | 10 | const story = await fetchItemFromHN(storyId) 11 | if (!story.kids || story.kids.length === 0) { 12 | rootElement.innerHTML = "No comments found."; 13 | return; 14 | } 15 | 16 | rootElement.innerHTML += renderCommentsHeader(story.id, story.title) 17 | const commentsWrapper = rootElement.appendChild(document.createElement("ul")); 18 | commentsWrapper.classList.add("comments-list") 19 | commentsWrapper.style.marginRight = 0 * 20; 20 | 21 | const commentIds = story.kids 22 | await createCommentListElement(commentIds,rootElement,0,options.maxDepth) 23 | 24 | rootElement.innerHTML += renderCommentsFooter() 25 | 26 | } catch (error) { 27 | console.error("Error fetching comments:", error); 28 | commentsDrawer.innerHTML = "Error fetching comments."; 29 | } 30 | } 31 | 32 | 33 | async function fetchItemFromHN(itemId){ 34 | const res = await fetch( 35 | `https://hacker-news.firebaseio.com/v0/item/${itemId}.json` 36 | ); 37 | const item = await res.json(); 38 | return item; 39 | } 40 | 41 | function renderCommentsHeader(storyId, title){ 42 | return ` 43 |
44 | Comments On this post : 45 | 46 | ${title} 47 | 48 |
49 | `; 50 | } 51 | function renderCommentsFooter(){ 52 | return ``; 55 | } 56 | 57 | async function createCommentListElement(commentIds,parentElement, depth, maxDepth = 10){ 58 | const commentsWrapper = parentElement.appendChild(document.createElement("ul")); 59 | commentsWrapper.classList.add("comments-list") 60 | commentsWrapper.style.marginRight = depth * 20; 61 | 62 | console.log({maxDepth,depth}) 63 | if(depth >= maxDepth) return; 64 | 65 | for(const commentId of commentIds){ 66 | await createCommentElement(commentId,commentsWrapper,depth+1,maxDepth); 67 | } 68 | } 69 | 70 | async function createCommentElement(commentId, parentElement, depth, maxDepth){ 71 | 72 | const comment = await fetchItemFromHN(commentId) 73 | 74 | if(comment == null || comment.deleted) return false; 75 | 76 | const commentElement = document.createElement("li"); 77 | commentElement.innerHTML = ` 78 |
${comment.by}
79 |
${comment.text}
80 | ` 81 | parentElement.appendChild(commentElement) 82 | 83 | if(comment.kids && comment.kids.length > 0){ 84 | createCommentListElement(comment.kids,commentElement,depth+1,maxDepth) 85 | } 86 | 87 | } 88 | 89 | 90 | function renderGithubLogo(){ 91 | return `` 92 | } 93 | 94 | 95 | document.addEventListener("DOMContentLoaded", function (event) { 96 | const hnCommentsDrawers = document.querySelectorAll( 97 | '[hn-story-id]' 98 | ); 99 | 100 | hnCommentsDrawers.forEach(async (drawer) => { 101 | 102 | const attr = (attrName)=>drawer.getAttribute(attrName) 103 | const storyId = attr("hn-story-id") 104 | 105 | 106 | console.log( typeof attr("hn-max-depth")) 107 | const maxDepth = typeof attr("hn-max-depth") === "string" ? parseInt( attr("hn-max-depth")) : 10; 108 | 109 | displayHNComments(storyId, drawer, { 110 | maxDepth 111 | 112 | }); 113 | }); 114 | }); 115 | --------------------------------------------------------------------------------