4141 <!-- Subdomain section -->
4242 <div class =" card flex flex-col gap-4" >
4343 <label for =" username-field" class =" flex flex-col gap-2" >
44- <span class =" text-lg font-bold text-contrast" >Custom URL </span >
44+ <span class =" text-lg font-bold text-contrast" >Custom Subdomain </span >
4545 <span > Your friends can connect to your server using this URL. </span >
4646 </label >
4747 <div class =" flex w-full items-center gap-2 md:w-[60%]" >
5959 </span >
6060 </div >
6161
62+ <div class =" card flex flex-col gap-4" >
63+ <div class =" flex w-full flex-row items-center justify-between" >
64+ <label for =" username-field" class =" flex flex-col gap-2" >
65+ <span class =" text-lg font-bold text-contrast" >DNS records</span >
66+ <span > Use your personal domain to connect to your server. </span >
67+ </label >
68+
69+ <Button @click =" exportDnsRecords" > Export DNS records </Button >
70+ </div >
71+
72+ <input
73+ v-model =" userDomain"
74+ class =" w-full md:w-[50%]"
75+ maxlength =" 64"
76+ minlength =" 1"
77+ type =" text"
78+ placeholder =" domain.com"
79+ />
80+
81+ <div class =" rounded-xl bg-table-alternateRow p-4" >
82+ <table
83+ class =" min-w-full border-collapse overflow-hidden rounded-lg border-2 border-gray-300"
84+ >
85+ <tbody >
86+ <tr v-for =" record in dnsRecords" :key =" record.content" >
87+ <td class =" py-3" >
88+ <div class =" ml-2 flex flex-col gap-1" @click =" copyText(record.type)" >
89+ <span
90+ class =" text-md font-bold tracking-wide text-contrast hover:cursor-pointer"
91+ >
92+ {{ record.type }}
93+ </span >
94+ <span class =" text-xs uppercase text-secondary" >type</span >
95+ </div >
96+ </td >
97+ <td class =" py-3" >
98+ <div class =" flex flex-col gap-1" @click =" copyText(record.name)" >
99+ <span
100+ class =" text-md font-bold tracking-wide text-contrast hover:cursor-pointer"
101+ >
102+ {{ record.name }}
103+ </span >
104+ <span class =" text-xs uppercase text-secondary" >name</span >
105+ </div >
106+ </td >
107+ <td class =" px-4" >
108+ <div class =" flex flex-col gap-1" @click =" copyText(record.content)" >
109+ <span
110+ class =" text-md w-fit font-bold tracking-wide text-contrast hover:cursor-pointer"
111+ >
112+ {{ record.content }}
113+ </span >
114+ <span class =" text-xs uppercase text-secondary" >content</span >
115+ </div >
116+ </td >
117+ </tr >
118+ </tbody >
119+ </table >
120+ </div >
121+ <div class =" flex items-center gap-2" >
122+ <InfoIcon />
123+ <span class =" text-sm text-secondary" >
124+ You must own your own domain to use this feature.
125+ </span >
126+ </div >
127+ </div >
128+
62129 <!-- Allocations section -->
63130 <div class =" card flex flex-col gap-4" >
64131 <div class =" flex w-full flex-row items-center justify-between" >
143210</template >
144211
145212<script setup lang="ts">
146- import { PlusIcon , TrashIcon , EditIcon , VersionIcon , SaveIcon } from " @modrinth/assets" ;
213+ import { PlusIcon , TrashIcon , EditIcon , VersionIcon , SaveIcon , InfoIcon } from " @modrinth/assets" ;
147214import { ButtonStyled , Modal , Button } from " @modrinth/ui" ;
148215import type { Server } from " ~/composables/pyroServers" ;
149216
@@ -157,6 +224,7 @@ const data = computed(() => props.server.general);
157224const serverIP = ref (data ?.value ?.net ?.ip ?? " " );
158225const serverSubdomain = ref (data ?.value ?.net ?.domain ?? " " );
159226const serverPrimaryPort = ref (data ?.value ?.net ?.port ?? 0 );
227+ const userDomain = ref (" play.yourdomain.com" );
160228
161229const network = computed (() => props .server .network );
162230const allocations = computed (() => network .value ?.allocations );
@@ -279,4 +347,55 @@ const saveNetwork = async () => {
279347const resetNetwork = () => {
280348 serverSubdomain .value = data ?.value ?.net ?.domain ?? " " ;
281349};
350+
351+ const dnsRecords = computed (() => {
352+ return [
353+ {
354+ type: " A" ,
355+ name: ` ${userDomain .value } ` ,
356+ content: data .value ?.net ?.ip ?? " " ,
357+ },
358+ {
359+ type: " SRV" ,
360+ name: ` _minecraft._tcp.${userDomain .value } ` ,
361+ content: ` 0 0 ${data .value ?.net ?.port } ${userDomain .value } ` ,
362+ },
363+ ];
364+ });
365+
366+ const exportDnsRecords = () => {
367+ const records = dnsRecords .value .reduce (
368+ (acc , record ) => {
369+ const type = record .type ;
370+ if (! acc [type ]) {
371+ acc [type ] = [];
372+ }
373+ acc [type ].push (record );
374+ return acc ;
375+ },
376+ {} as Record <string , any []>,
377+ );
378+
379+ const text = Object .entries (records )
380+ .map (([type , records ]) => {
381+ return ` ; ${type } Record\n ${records .map ((record ) => ` ${record .name }. 1 IN ${record .type } ${record .content } ` ).join (" \n " )}\n ` ;
382+ })
383+ .join (" \n " );
384+ const blob = new Blob ([text ], { type: " text/plain" });
385+ const a = document .createElement (" a" );
386+ a .href = window .URL .createObjectURL (blob );
387+ a .download = ` ${userDomain .value }.txt ` ;
388+ a .click ();
389+ a .remove ();
390+ };
391+
392+ const copyText = (text : string ) => {
393+ navigator .clipboard .writeText (text );
394+ addNotification ({
395+ group: " serverOptions" ,
396+ type: " success" ,
397+ title: " Text copied" ,
398+ text: ` ${text } has been copied to your clipboard ` ,
399+ });
400+ };
282401 </script >
0 commit comments