Compare commits

..

No commits in common. "42ccd7c0499d00bca79811f22453d35e79b0a6ca" and "51e2c8782897f2b837730ae783c6997b942a29cc" have entirely different histories.

38 changed files with 114 additions and 7268 deletions

View File

@ -1 +0,0 @@
.DS_Store

View File

@ -1,18 +0,0 @@
kind: pipeline
type: docker
name: Build and Push to Local Registry
steps:
- name: Build and Push Docker Image
image: plugins/docker
settings:
# Custom registry address
registry: localhost:32000
# Repository name (include registry address in repo path)
repo: localhost:32000/log101-dot-dev
# Tags for the image
tags:
- latest
- ${DRONE_COMMIT_SHA:0:7}
# Allow insecure connections (for HTTP registries)
insecure: true

View File

@ -1,45 +1,18 @@
name: Build and Push Docker Image
run-name: Build triggered by ${{ gitea.actor }}
run-name: ${{ gitea.actor }}, deploy to docker registry
on:
push:
branches:
- main
- "main"
jobs:
build:
runs-on: ubuntu-22.04 # Using specific Ubuntu version instead of latest
runs-on: ubuntu-latest
steps:
- name: Checkout repository
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to private registry
uses: docker/login-action@v3
with:
registry: registry.acayip.dev
username: ${{ secrets.REGISTRY_USERNAME }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Generate image tag
id: meta
run: |
VERSION=$(date +%Y%m%d)-$(git rev-parse --short HEAD)
echo "TAG=registry.acayip.dev/log101-dot-dev:${VERSION}" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: ${{ gitea.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.TAG }}
# Add build caching for faster builds
cache-from: type=gha
cache-to: type=gha,mode=max
# Add labels for better tracking
labels: |
org.opencontainers.image.source=${{ gitea.repository }}
org.opencontainers.image.revision=${{ gitea.sha }}
org.opencontainers.image.created=${{ gitea.event.created_at }}
push: ${{ github.event_name != 'pull_request' }}
tags: registry.container-registry:5000/log101-blog:latest

View File

@ -1,10 +1,9 @@
FROM oven/bun AS build
FROM node:lts AS build
WORKDIR /app
COPY package*.json ./
RUN bun install
RUN npm install
COPY . .
ENV PUBLIC_BACKEND_HOST=https://api.acayip.dev
RUN bun run build
RUN npm run build
FROM nginx:alpine AS runtime
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf

50
Jenkinsfile vendored
View File

@ -1,50 +0,0 @@
pipeline {
agent {
docker {
image 'ubuntu-latest'
}
}
stages {
stage('Checkout') {
steps {
git(branch: 'main', url: 'https://git.acayip.dev/log101/log101-dot-dev.git')
}
}
stage('Build Docker Image') {
steps {
script {
docker.build("${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG}")
}
}
}
stage('Push to microk8s Registry') {
steps {
script {
docker.withRegistry("http://${REGISTRY}") {
docker.image("${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG}").push()
}
}
}
}
stage('Cleanup') {
steps {
script {
sh "docker rmi ${REGISTRY}/${DOCKER_IMAGE}:${DOCKER_TAG} || true"
}
}
}
}
environment {
DOCKER_IMAGE = 'log101-dot-dev'
DOCKER_TAG = 'latest'
REGISTRY = '192.168.88.252:5000'
}
}

View File

@ -1,6 +1,3 @@
> Geçmesi imkansız geçmiş, gelmesi imkansız gelecek...
log101.dev blog

View File

@ -5,7 +5,7 @@ import remarkToc from "remark-toc";
// https://astro.build/config
export default defineConfig({
site: "https://blog.acayip.dev",
site: "https://blog.log101.dev",
markdown: {
remarkPlugins: [[remarkToc, { heading: "İçindekiler" }]],
shikiConfig: {

BIN
bun.lockb

Binary file not shown.

View File

@ -1,23 +0,0 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

View File

@ -1,24 +0,0 @@
apiVersion: argoproj.io/v1alpha1
name: blog
description: blog.log101.dev helm chart
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.0.0"

View File

@ -1,22 +0,0 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "chart.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "chart.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}

View File

@ -1,62 +0,0 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "chart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "chart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "chart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "chart.labels" -}}
helm.sh/chart: {{ include "chart.chart" . }}
{{ include "chart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "chart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "chart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "chart.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@ -1,86 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "chart.fullname" . }}
labels:
{{- include "chart.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
revisionHistoryLimit: {{ .Values.revisionHistoryLimit }}
selector:
matchLabels:
{{- include "chart.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "chart.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "chart.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.containerPort | default 8080 }} # ← Now points to 8080
protocol: TCP
{{- if .Values.env }}
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
{{- with .Values.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.volumes }}
volumes:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@ -1,32 +0,0 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "chart.fullname" . }}
labels:
{{- include "chart.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "chart.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}

View File

@ -1,43 +0,0 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "chart.fullname" . }}
labels:
{{- include "chart.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.ingress.className }}
ingressClassName: {{ . }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- with .pathType }}
pathType: {{ . }}
{{- end }}
backend:
service:
name: {{ include "chart.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -1,13 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "chart.fullname" . }}
labels: {{- include "chart.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector: {{- include "chart.selectorLabels" . | nindent 4 }}

View File

@ -1,13 +0,0 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "chart.serviceAccountName" . }}
labels:
{{- include "chart.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
{{- end }}

View File

@ -1,15 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "chart.fullname" . }}-test-connection"
labels:
{{- include "chart.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "chart.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

View File

@ -1,136 +0,0 @@
# Default values for chart.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
replicaCount: 1
revisionHistoryLimit: 3
# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/
image:
repository: registry.acayip.dev/log101-dot-dev
# This sets the pull policy for images.
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
imagePullSecrets:
- name: acayip-registry-secret
# This is to override the chart name.
nameOverride: ""
fullnameOverride: ""
# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/
serviceAccount:
# Specifies whether a service account should be created
create: true
# Automatically mount a ServiceAccount's API credentials?
automount: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
# This is for setting Kubernetes Annotations to a Pod.
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
podAnnotations: {}
# This is for setting Kubernetes Labels to a Pod.
# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
podLabels: {}
podSecurityContext:
{}
# fsGroup: 2000
securityContext:
{}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/
service:
# This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
type: ClusterIP
# This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports
port: 8080
containerPort: 8080
# Environment variables to be passed to the container
env:
PUBLIC_BACKEND_HOST: "https://api.acayip.dev"
# This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/
ingress:
enabled: true
className: ""
annotations:
cert-manager.io/cluster-issuer: lets-encrypt
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: blog.acayip.dev
paths:
- path: /
pathType: Prefix
tls:
- secretName: blog-tls
hosts:
- blog.acayip.dev
resources:
{}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
# Additional volumes on the output Deployment definition.
volumes: []
# - name: foo
# secret:
# secretName: mysecret
# optional: false
# Additional volumeMounts on the output Deployment definition.
volumeMounts: []
# - name: foo
# mountPath: "/etc/foo"
# readOnly: true
nodeSelector: {}
tolerations: []
affinity: {}

View File

@ -1,20 +0,0 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: blog-deployment
labels:
app: blog
spec:
selector:
matchLabels:
app: blog
template:
metadata:
labels:
app: blog
spec:
containers:
- name: blog
image: localhost:32000/log101-dot-dev:v3
ports:
- containerPort: 8080

7
cypress.config.js Normal file
View File

@ -0,0 +1,7 @@
import { defineConfig } from "cypress";
export default defineConfig({
e2e: {
supportFile: false,
},
});

7
cypress/e2e/index.cy.js Normal file
View File

@ -0,0 +1,7 @@
describe("Home", () =>
it("titles are correct", () => {
const page = cy.visit("http://localhost:4321");
page.get("title").should("have.text", "log101");
page.get("h1").should("have.text", "Log101");
}));

View File

@ -8,7 +8,6 @@ http {
server {
listen 8080;
server_name _;
client_max_body_size 50M;
root /usr/share/nginx/html;
index index.html index.htm;

6535
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -7,19 +7,20 @@
"start": "astro dev",
"build": "astro check && astro build",
"preview": "astro preview",
"astro": "astro"
"astro": "astro",
"test": "cypress run --browser chrome && cypress run --browser firefox"
},
"dependencies": {
"@astrojs/check": "0.9.4",
"@astrojs/tailwind": "^6.0.2",
"astro": "^5.13.7",
"dewp": "^0.0.6",
"@astrojs/tailwind": "6.0.0",
"astro": "5.3.0",
"htmx.org": "^1.9.12",
"remark-toc": "^9.0.0",
"tailwindcss": "^3.4.3",
"typescript": "^5.4.5"
},
"devDependencies": {
"cypress": "^13.11.0",
"prettier": "^3.2.5",
"prettier-plugin-astro": "^0.14.0"
},

View File

@ -1,25 +0,0 @@
backend:
name: gitea
repo: log101/log101-dot-dev # Path to your Gitea repository
app_id: 2cb1c31c-4c74-4272-ac74-5d60a4b5c9ab # The Client ID provided by Gitea
api_root: https://git.acayip.dev/api/v1 # API URL of your Gitea instance
base_url: https://git.acayip.dev # Root URL of your Gitea instance
auth_endpoint: https://git.acayip.dev/login/oauth/authorize
branch: draft
collections:
- name: "blog" # Used in routes, e.g., /admin/collections/blog
label: "Blog" # Used in the UI
folder: "src/content/blog" # The path to the folder where the documents are stored
create: true # Allow users to create new documents in this collection
slug: "{{year}}-{{month}}-{{day}}-{{slug}}" # Filename template, e.g., YYYY-MM-DD-title.md
format: frontmatter
fields: # The fields for each document, usually in front matter
- { label: "Taslak", name: "draft", widget: "boolean", default: true }
- { label: "Başlık", name: "title", widget: "string" }
- { label: "Tarih", name: "date", widget: "datetime" }
- { label: "Özet", name: "summary", widget: "string" }
- { label: "Kategori", name: "category", widget: "select", options: ["fikir", "teknik", "edebiyat", "ansiklopedi"] }
- { label: "Alt Kategori", name: "subcategory", widget: "string" }
- { label: "Body", name: "body", widget: "markdown" }
media_folder: "public/images"
public_folder: "/images"

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

View File

@ -1,19 +1,13 @@
---
import { render, getCollection, type CollectionEntry } from "astro:content";
import type { CollectionEntry } from "astro:content";
interface Props {
post: CollectionEntry<"posts">;
post: CollectionEntry<"blog">;
componentType: "short" | "long" | "full";
}
const { post, componentType } = Astro.props;
const categoryTitles = await Promise.all(
post.data.categories.map(async (c) => await getEntry("categories", c.id))
);
const parentCategory = categoryTitles.find((c) => !Boolean(c?.data.parent?.id));
// default options for the post component
const deafultOptions = {
showTags: false,
@ -53,15 +47,16 @@ const postDateFormatted = post.data.date.toLocaleDateString("tr-TR", {
});
// Create post link
const postLink = `/${parentCategory?.data.slug}/${post.data.slug}`;
const postLink = `/${post.data.category}/${post.slug}`;
// Create post content as an astro component
const { Content } = await render(post);
const { Content } = await post.render();
const copyPost = post;
import { Image } from "astro:assets";
import questionMark from "@/images/questionMark.svg";
import calendar from "@/images/calendar.svg";
import { getEntry } from "astro:content";
---
<style>
@ -75,13 +70,26 @@ import { getEntry } from "astro:content";
}
</style>
<div class="flex flex-col gap-1">
<div class="flex flex-col gap-3">
<div class="flex flex-col gap-2">
<p class="tracking-wide text-slate-700">{categoryTitles[0]?.data.name}</p>
<p class="tracking-wide text-slate-700">{post.data.subcategory}</p>
<a class="no-underline text-inherit" href={postLink}>
<h4 class="text-2xl font-normal">{post.data.title.rendered}</h4>
<h4 class="text-3xl font-normal">{post.data.title}</h4>
</a>
<div class="flex flex-row gap-2">
{
options.showTags && post.data.tags?.length && (
<div class="flex items-center gap-1">
<Image alt="question mark" src={questionMark} />
<ul class="list-none flex pl-0 meta-list">
{post.data.tags.map((tag) => (
<li class="text-sm text-gray-500">{tag}</li>
))}
</ul>
</div>
)
}
<div class="flex items-center gap-1">
<Image alt="calendar" src={calendar} />
<ul class="list-none flex pl-0 meta-list">
@ -92,7 +100,7 @@ import { getEntry } from "astro:content";
</div>
{
(options.shortSummary || options.longSummary) && (
<p class="post-summary" set:html={post.data.excerpt.rendered} />
<p class="post-summary">{post.data.summary}</p>
)
}

View File

@ -135,7 +135,7 @@ Peki tüm bu saydığım servisler ne kadar kaynak tüketiyor? Özellikle RAM ka
### Gelecek
Sistemimde çalışan servisleri kısaca tanıttım. Bunlar şimdilik işimi görüyor fakat yakın gelecekte daha fazlasına ihtiyaç duyacağımı tahmin ediyorum. Özellikle güvenlik açısından sunucumun çok eksiği var. DDoS saldırılarına açık ve bildiğim bilmediğim birçok zafiyete sahip. Yine de kendi CI/CD sistemimi kullanmak ve kodum ile alakalı bütün süreçleri yönetmek projelerime esneklik katıyor.
Sistemimde çalışan servisleri kısaca tanıtmış oldum. Bunlar şimdilik işimi görüyor fakat yakın gelecekte daha fazlasına ihtiyaç duyacağımı tahmin ediyorum. Özellikle güvenlik açısından sunucumun çok eksiği var. DDoS saldırılarına açık ve bildiğim bilmediğim birçok zafiyete sahip. Yine de kendi CI/CD sistemimi kullanmak ve kodum ile alakalı bütün süreçleri yönetmek projelerime esneklik katıyor.
Kendi sunucunuzu kurmanın, sizin için de keyifli ve kıymetli bir tecrübe olacağına inanıyorum.

View File

@ -1,5 +1,4 @@
import { z, defineCollection } from "astro:content";
import { wpCollections } from "dewp/loaders";
export const CATEGORIES = ["fikir", "teknik", "edebiyat", "ansiklopedi"];
@ -36,5 +35,4 @@ const bookReviewCollection = defineCollection({
export const collections = {
blog: blogCollection,
bookReview: bookReviewCollection,
...wpCollections({ endpoint: "https://wp.log101.dev/wp-json/" }),
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -1,6 +1,7 @@
---
import type { Page } from "astro";
import { getCollection } from "astro:content";
import { CATEGORIES } from "@/content/config";
import Header from "@/components/Header.astro";
import Footer from "@/components/Footer.astro";
@ -8,16 +9,19 @@ import Layout from "@/layouts/Layout.astro";
import Post from "@/components/Post.astro";
export async function getStaticPaths({ paginate }: { paginate: any }) {
const posts = await getCollection("posts");
const categories = await getCollection("categories");
const blogEntries = await getCollection("blog");
const allReviews = await getCollection("bookReview");
return categories.flatMap((category) => {
const filteredPosts = posts.filter((post) =>
post.data.categories.find((c) => c.id === category.id)
const allPosts = [...allReviews, ...blogEntries].filter(
(post) => !post.data.draft
);
return CATEGORIES.flatMap((category) => {
const filteredPosts = allPosts.filter(
(post) => post.data.category == category
);
return paginate(filteredPosts, {
params: { category: category.data.slug },
params: { category },
pageSize: 3,
});
});

View File

@ -1,5 +1,5 @@
---
import { getCollection, getEntry } from "astro:content";
import { getCollection } from "astro:content";
import Footer from "@/components/Footer.astro";
import Header from "@/components/Header.astro";
@ -8,6 +8,7 @@ import Post from "@/components/Post.astro";
import EmojiReactionForm from "@/components/EmojiReactionForm.astro";
import CommentForm from "@/components/CommentForm.astro";
import HorizontalLine from "@/components/HorizontalLine.astro";
import BookReview from "@/components/BookReview.astro";
const { entry } = Astro.props;
@ -16,37 +17,33 @@ const URL = Astro.url;
const backendHost = import.meta.env.PUBLIC_BACKEND_HOST;
export async function getStaticPaths() {
const posts = await getCollection("posts");
const blogEntries = await getCollection("blog");
const allReviews = await getCollection("bookReview");
return await Promise.all(
posts.map(async (entry) => {
const categoryTitles = await Promise.all(
entry.data.categories.map(
async (c) => await getEntry("categories", c.id)
)
);
const parentCategory = categoryTitles.find(
(c) => !Boolean(c?.data.parent?.id)
);
return {
params: { category: parentCategory?.data.slug, slug: entry.data.slug },
props: { entry },
};
})
const allPosts = [...allReviews, ...blogEntries].filter(
(post) => !post.data.draft
);
return allPosts.map((entry) => ({
params: { category: entry.data.category, slug: entry.slug },
props: { entry },
}));
}
---
<Layout
title="log101"
ogTitle={entry.data.title.rendered}
ogDescription={entry.data.excerpt.rendered}
ogTitle={entry.data.title}
ogDescription={entry.data.summary}
ogURL={URL.toString()}>
<Header />
<Post post={entry} componentType="full" />
{
entry.collection === "blog" ? (
<Post post={entry} componentType="full" />
) : (
<BookReview post={entry} componentType="full" />
)
}
<EmojiReactionForm entryId={entry.id} />
<section class="comments">

View File

@ -5,17 +5,30 @@ import Layout from "@/layouts/Layout.astro";
import { getCollection } from "astro:content";
import Post from "@/components/Post.astro";
import BookReview from "@/components/BookReview.astro";
const posts = await getCollection("posts");
const allTeknikPosts = await getCollection("blog");
const allReviews = await getCollection("bookReview");
const allPosts = [...allReviews, ...allTeknikPosts].filter(
(post) => !post.data.draft
);
---
<Layout title="log101">
<Header />
<div class="posts">
{
posts
allPosts
.sort((p1, p2) => p2.data.date.getTime() - p1.data.date.getTime())
.map((p) => <Post post={p} componentType="short" />)
.map((p) => {
if (p.collection == "blog") {
return <Post post={p} componentType="short" />;
} else {
p.collection == "bookReview";
return <BookReview post={p} componentType="short" />;
}
})
}
</div>
<a class="text-inherit" href="/posts/1">Tüm Yayınlar</a>

View File

@ -8,10 +8,15 @@ import Layout from "@/layouts/Layout.astro";
import Post from "@/components/Post.astro";
export async function getStaticPaths({ paginate }: { paginate: any }) {
const posts = await getCollection("posts");
const blogEntries = await getCollection("blog");
const allReviews = await getCollection("bookReview");
return paginate(posts, {
pageSize: 10,
const allPosts = [...allReviews, ...blogEntries].filter(
(post) => !post.data.draft
);
return paginate(allPosts, {
pageSize: 3,
});
}

View File

@ -43,51 +43,3 @@ video {
font-family: "Source Code Pro", monospace;
}
}
.shiki {
font-size: 16px;
line-height: 1rem;
padding: 18px;
border-radius: 8px;
margin-bottom: 16px;
}
h3,
hr {
margin: 0.7em 0 0.5em 0;
}
#full-text p {
margin: 0.5em 0 1.2em 0;
}
figcaption {
color: gray;
text-align: center;
font-size: 0.9em;
}
#toc > ul {
line-height: 2em;
}
li a {
color: black;
}
table {
border: 1px solid slategrey;
padding: 4px;
background-color: #f8f9fa;
margin: 0.5em 0 1.2em 0;
}
th {
text-align: left;
white-space: nowrap;
}
td {
text-align: left;
white-space: nowrap;
}

View File

@ -1,5 +1,9 @@
{
"extends": "astro/tsconfigs/strict",
"exclude": ["./src/components/*.astro"],
"compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] } }
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}